1275f7c39SAndrew Jeffery #pragma once 2275f7c39SAndrew Jeffery 3275f7c39SAndrew Jeffery #include "Utils.hpp" 4275f7c39SAndrew Jeffery 5275f7c39SAndrew Jeffery #include <sdbusplus/asio/connection.hpp> 6275f7c39SAndrew Jeffery #include <sdbusplus/bus/match.hpp> 7275f7c39SAndrew Jeffery #include <sdbusplus/message.hpp> 8275f7c39SAndrew Jeffery #include <sdbusplus/message/native_types.hpp> 9275f7c39SAndrew Jeffery 10275f7c39SAndrew Jeffery #include <cstdint> 1118b6186eSEd Tanous #include <exception> 1218b6186eSEd Tanous #include <functional> 1318b6186eSEd Tanous #include <memory> 1418b6186eSEd Tanous #include <optional> 1518b6186eSEd Tanous #include <set> 1618b6186eSEd Tanous #include <string> 1718b6186eSEd Tanous #include <system_error> 1818b6186eSEd Tanous #include <utility> 1918b6186eSEd Tanous #include <vector> 20275f7c39SAndrew Jeffery 21275f7c39SAndrew Jeffery /** 22275f7c39SAndrew Jeffery * @file 23275f7c39SAndrew Jeffery * @brief Abstract and concrete classes representing MCTP concepts and 24275f7c39SAndrew Jeffery * behaviours. 25275f7c39SAndrew Jeffery */ 26275f7c39SAndrew Jeffery 27275f7c39SAndrew Jeffery /** 28275f7c39SAndrew Jeffery * @brief An exception type that may be thrown by implementations of the MCTP 29275f7c39SAndrew Jeffery * abstract classes. 30275f7c39SAndrew Jeffery * 31275f7c39SAndrew Jeffery * This exception should be the basis for all exceptions thrown out of the MCTP 32275f7c39SAndrew Jeffery * APIs, and should capture any other exceptions that occur. 33275f7c39SAndrew Jeffery */ 34275f7c39SAndrew Jeffery class MCTPException : public std::exception 35275f7c39SAndrew Jeffery { 36275f7c39SAndrew Jeffery public: 37275f7c39SAndrew Jeffery MCTPException() = delete; MCTPException(const char * desc)38275f7c39SAndrew Jeffery explicit MCTPException(const char* desc) : desc(desc) {} what() const39275f7c39SAndrew Jeffery const char* what() const noexcept override 40275f7c39SAndrew Jeffery { 41275f7c39SAndrew Jeffery return desc; 42275f7c39SAndrew Jeffery } 43275f7c39SAndrew Jeffery 44275f7c39SAndrew Jeffery private: 45275f7c39SAndrew Jeffery const char* desc; 46275f7c39SAndrew Jeffery }; 47275f7c39SAndrew Jeffery 48275f7c39SAndrew Jeffery /** 49275f7c39SAndrew Jeffery * @brief An enum of the MCTP transports described in DSP0239 v1.10.0 Section 7. 50275f7c39SAndrew Jeffery * 51275f7c39SAndrew Jeffery * https://www.dmtf.org/sites/default/files/standards/documents/DSP0239_1.10.0.pdf 52275f7c39SAndrew Jeffery */ 53275f7c39SAndrew Jeffery enum class MCTPTransport 54275f7c39SAndrew Jeffery { 55275f7c39SAndrew Jeffery Reserved = 0x00, 56275f7c39SAndrew Jeffery SMBus = 0x01, 57275f7c39SAndrew Jeffery }; 58275f7c39SAndrew Jeffery 59275f7c39SAndrew Jeffery /** 60275f7c39SAndrew Jeffery * @brief Captures properties of MCTP interfaces. 61275f7c39SAndrew Jeffery * 6219d1fda6SThu Nguyen * https://github.com/CodeConstruct/mctp/blob/v2.0/src/mctp.c#L668-L699 63275f7c39SAndrew Jeffery */ 64275f7c39SAndrew Jeffery struct MCTPInterface 65275f7c39SAndrew Jeffery { 66275f7c39SAndrew Jeffery std::string name; 67275f7c39SAndrew Jeffery MCTPTransport transport; 68275f7c39SAndrew Jeffery 69275f7c39SAndrew Jeffery auto operator<=>(const MCTPInterface& r) const = default; 70275f7c39SAndrew Jeffery }; 71275f7c39SAndrew Jeffery 72275f7c39SAndrew Jeffery class MCTPDevice; 73275f7c39SAndrew Jeffery 74275f7c39SAndrew Jeffery /** 75275f7c39SAndrew Jeffery * @brief Captures the behaviour of an endpoint at the MCTP layer 76275f7c39SAndrew Jeffery * 77275f7c39SAndrew Jeffery * The lifetime of an instance of MctpEndpoint is proportional to the lifetime 78275f7c39SAndrew Jeffery * of the endpoint configuration. If an endpoint is deconfigured such that its 79275f7c39SAndrew Jeffery * device has no assigned EID, then any related MctpEndpoint instance must be 80275f7c39SAndrew Jeffery * destructed as a consequence. 81275f7c39SAndrew Jeffery */ 82275f7c39SAndrew Jeffery class MCTPEndpoint 83275f7c39SAndrew Jeffery { 84275f7c39SAndrew Jeffery public: 85275f7c39SAndrew Jeffery using Event = std::function<void(const std::shared_ptr<MCTPEndpoint>& ep)>; 86275f7c39SAndrew Jeffery using Result = std::function<void(const std::error_code& ec)>; 87275f7c39SAndrew Jeffery 88275f7c39SAndrew Jeffery virtual ~MCTPEndpoint() = default; 89275f7c39SAndrew Jeffery 90275f7c39SAndrew Jeffery /** 91275f7c39SAndrew Jeffery * @return The Linux network ID of the network in which the endpoint 92275f7c39SAndrew Jeffery participates 93275f7c39SAndrew Jeffery */ 94275f7c39SAndrew Jeffery virtual int network() const = 0; 95275f7c39SAndrew Jeffery 96275f7c39SAndrew Jeffery /** 97275f7c39SAndrew Jeffery * @return The MCTP endpoint ID of the endpoint in its network 98275f7c39SAndrew Jeffery */ 99275f7c39SAndrew Jeffery virtual uint8_t eid() const = 0; 100275f7c39SAndrew Jeffery 101275f7c39SAndrew Jeffery /** 102275f7c39SAndrew Jeffery * @brief Subscribe to events produced by an endpoint object across its 103275f7c39SAndrew Jeffery * lifecycle 104275f7c39SAndrew Jeffery * 105275f7c39SAndrew Jeffery * @param degraded The callback to execute when the MCTP layer indicates the 106275f7c39SAndrew Jeffery * endpoint is unresponsive 107275f7c39SAndrew Jeffery * 108275f7c39SAndrew Jeffery * @param available The callback to execute when the MCTP layer indicates 109275f7c39SAndrew Jeffery * that communication with the degraded endpoint has been 110275f7c39SAndrew Jeffery * recovered 111275f7c39SAndrew Jeffery * 112275f7c39SAndrew Jeffery * @param removed The callback to execute when the MCTP layer indicates the 113275f7c39SAndrew Jeffery * endpoint has been removed. 114275f7c39SAndrew Jeffery */ 115275f7c39SAndrew Jeffery virtual void subscribe(Event&& degraded, Event&& available, 116275f7c39SAndrew Jeffery Event&& removed) = 0; 117275f7c39SAndrew Jeffery 118275f7c39SAndrew Jeffery /** 119275f7c39SAndrew Jeffery * @brief Remove the endpoint from its associated network 120275f7c39SAndrew Jeffery */ 121275f7c39SAndrew Jeffery virtual void remove() = 0; 122275f7c39SAndrew Jeffery 123275f7c39SAndrew Jeffery /** 124275f7c39SAndrew Jeffery * @return A formatted string representing the endpoint in terms of its 125275f7c39SAndrew Jeffery * address properties 126275f7c39SAndrew Jeffery */ 127275f7c39SAndrew Jeffery virtual std::string describe() const = 0; 128275f7c39SAndrew Jeffery 129275f7c39SAndrew Jeffery /** 130275f7c39SAndrew Jeffery * @return A shared pointer to the device instance associated with the 131275f7c39SAndrew Jeffery * endpoint. 132275f7c39SAndrew Jeffery */ 133275f7c39SAndrew Jeffery virtual std::shared_ptr<MCTPDevice> device() const = 0; 134275f7c39SAndrew Jeffery }; 135275f7c39SAndrew Jeffery 136275f7c39SAndrew Jeffery /** 137275f7c39SAndrew Jeffery * @brief Represents an MCTP-capable device on a bus. 138275f7c39SAndrew Jeffery * 139275f7c39SAndrew Jeffery * It is often known that an MCTP-capable device exists on a bus prior to the 140275f7c39SAndrew Jeffery * MCTP stack configuring the device for communication. MctpDevice exposes the 141275f7c39SAndrew Jeffery * ability to set-up the endpoint device for communication. 142275f7c39SAndrew Jeffery * 143275f7c39SAndrew Jeffery * The lifetime of an MctpDevice instance is proportional to the existence of an 144275f7c39SAndrew Jeffery * MCTP-capable device in the system. If a device represented by an MctpDevice 145275f7c39SAndrew Jeffery * instance is removed from the system then any related MctpDevice instance must 146275f7c39SAndrew Jeffery * be destructed a consequence. 147275f7c39SAndrew Jeffery * 148275f7c39SAndrew Jeffery * Successful set-up of the device as an endpoint yields an MctpEndpoint 149275f7c39SAndrew Jeffery * instance. The lifetime of the MctpEndpoint instance produced must not exceed 150275f7c39SAndrew Jeffery * the lifetime of its parent MctpDevice. 151275f7c39SAndrew Jeffery */ 152275f7c39SAndrew Jeffery class MCTPDevice 153275f7c39SAndrew Jeffery { 154275f7c39SAndrew Jeffery public: 155275f7c39SAndrew Jeffery virtual ~MCTPDevice() = default; 156275f7c39SAndrew Jeffery 157275f7c39SAndrew Jeffery /** 158275f7c39SAndrew Jeffery * @brief Configure the device for MCTP communication 159275f7c39SAndrew Jeffery * 160275f7c39SAndrew Jeffery * @param added The callback to invoke once the setup process has 161275f7c39SAndrew Jeffery * completed. The provided error code @p ec must be 162275f7c39SAndrew Jeffery * checked as the request may not have succeeded. If 163275f7c39SAndrew Jeffery * the request was successful then @p ep contains a 164275f7c39SAndrew Jeffery * valid MctpEndpoint instance. 165275f7c39SAndrew Jeffery */ 166*556e04b8SPatrick Williams virtual void setup( 167*556e04b8SPatrick Williams std::function<void(const std::error_code& ec, 168275f7c39SAndrew Jeffery const std::shared_ptr<MCTPEndpoint>& ep)>&& 169275f7c39SAndrew Jeffery added) = 0; 170275f7c39SAndrew Jeffery 171275f7c39SAndrew Jeffery /** 172275f7c39SAndrew Jeffery * @brief Remove the device and any associated endpoint from the MCTP stack. 173275f7c39SAndrew Jeffery */ 174275f7c39SAndrew Jeffery virtual void remove() = 0; 175275f7c39SAndrew Jeffery 176275f7c39SAndrew Jeffery /** 177275f7c39SAndrew Jeffery * @return A formatted string representing the device in terms of its 178275f7c39SAndrew Jeffery * address properties. 179275f7c39SAndrew Jeffery */ 180275f7c39SAndrew Jeffery virtual std::string describe() const = 0; 181275f7c39SAndrew Jeffery }; 182275f7c39SAndrew Jeffery 183275f7c39SAndrew Jeffery class MCTPDDevice; 184275f7c39SAndrew Jeffery 185275f7c39SAndrew Jeffery /** 186275f7c39SAndrew Jeffery * @brief An implementation of MctpEndpoint in terms of the D-Bus interfaces 187275f7c39SAndrew Jeffery * exposed by @c mctpd. 188275f7c39SAndrew Jeffery * 189275f7c39SAndrew Jeffery * The lifetime of an MctpdEndpoint is proportional to the lifetime of the 190275f7c39SAndrew Jeffery * endpoint object exposed by @c mctpd. The lifecycle of @c mctpd endpoint 191275f7c39SAndrew Jeffery * objects is discussed here: 192275f7c39SAndrew Jeffery * 193275f7c39SAndrew Jeffery * https://github.com/CodeConstruct/mctp/pull/23/files#diff-00234f5f2543b8b9b8a419597e55121fe1cc57cf1c7e4ff9472bed83096bd28e 194275f7c39SAndrew Jeffery */ 195275f7c39SAndrew Jeffery class MCTPDEndpoint : 196275f7c39SAndrew Jeffery public MCTPEndpoint, 197275f7c39SAndrew Jeffery public std::enable_shared_from_this<MCTPDEndpoint> 198275f7c39SAndrew Jeffery { 199275f7c39SAndrew Jeffery public: 200275f7c39SAndrew Jeffery static std::string path(const std::shared_ptr<MCTPEndpoint>& ep); 201275f7c39SAndrew Jeffery 202275f7c39SAndrew Jeffery MCTPDEndpoint() = delete; MCTPDEndpoint(const std::shared_ptr<MCTPDDevice> & dev,const std::shared_ptr<sdbusplus::asio::connection> & connection,sdbusplus::message::object_path objpath,int network,uint8_t eid)203275f7c39SAndrew Jeffery MCTPDEndpoint( 204275f7c39SAndrew Jeffery const std::shared_ptr<MCTPDDevice>& dev, 205275f7c39SAndrew Jeffery const std::shared_ptr<sdbusplus::asio::connection>& connection, 206275f7c39SAndrew Jeffery sdbusplus::message::object_path objpath, int network, uint8_t eid) : 207275f7c39SAndrew Jeffery dev(dev), connection(connection), objpath(std::move(objpath)), 208275f7c39SAndrew Jeffery mctp{network, eid} 209275f7c39SAndrew Jeffery {} 210275f7c39SAndrew Jeffery MCTPDEndpoint& McptdEndpoint(const MCTPDEndpoint& other) = delete; 211275f7c39SAndrew Jeffery MCTPDEndpoint(MCTPDEndpoint&& other) noexcept = default; 212275f7c39SAndrew Jeffery ~MCTPDEndpoint() override = default; 213275f7c39SAndrew Jeffery 214275f7c39SAndrew Jeffery int network() const override; 215275f7c39SAndrew Jeffery uint8_t eid() const override; 216275f7c39SAndrew Jeffery void subscribe(Event&& degraded, Event&& available, 217275f7c39SAndrew Jeffery Event&& removed) override; 218275f7c39SAndrew Jeffery void remove() override; 219275f7c39SAndrew Jeffery 220275f7c39SAndrew Jeffery std::string describe() const override; 221275f7c39SAndrew Jeffery 222275f7c39SAndrew Jeffery std::shared_ptr<MCTPDevice> device() const override; 223275f7c39SAndrew Jeffery 224275f7c39SAndrew Jeffery /** 225275f7c39SAndrew Jeffery * @brief Indicate the endpoint has been removed 226275f7c39SAndrew Jeffery * 227275f7c39SAndrew Jeffery * Called from the implementation of MctpdDevice for resource cleanup 228275f7c39SAndrew Jeffery * prior to destruction. Resource cleanup is delegated by invoking the 229275f7c39SAndrew Jeffery * notifyRemoved() callback. As the actions may be abitrary we avoid 230275f7c39SAndrew Jeffery * invoking notifyRemoved() in the destructor. 231275f7c39SAndrew Jeffery */ 232275f7c39SAndrew Jeffery void removed(); 233275f7c39SAndrew Jeffery 234275f7c39SAndrew Jeffery private: 235275f7c39SAndrew Jeffery std::shared_ptr<MCTPDDevice> dev; 236275f7c39SAndrew Jeffery std::shared_ptr<sdbusplus::asio::connection> connection; 237275f7c39SAndrew Jeffery sdbusplus::message::object_path objpath; 238275f7c39SAndrew Jeffery struct 239275f7c39SAndrew Jeffery { 240275f7c39SAndrew Jeffery int network; 241275f7c39SAndrew Jeffery uint8_t eid; 242275f7c39SAndrew Jeffery } mctp; 243275f7c39SAndrew Jeffery MCTPEndpoint::Event notifyAvailable; 244275f7c39SAndrew Jeffery MCTPEndpoint::Event notifyDegraded; 245275f7c39SAndrew Jeffery MCTPEndpoint::Event notifyRemoved; 246275f7c39SAndrew Jeffery std::optional<sdbusplus::bus::match_t> connectivityMatch; 247275f7c39SAndrew Jeffery 248275f7c39SAndrew Jeffery void onMctpEndpointChange(sdbusplus::message_t& msg); 249275f7c39SAndrew Jeffery void updateEndpointConnectivity(const std::string& connectivity); 250275f7c39SAndrew Jeffery }; 251275f7c39SAndrew Jeffery 252275f7c39SAndrew Jeffery /** 253275f7c39SAndrew Jeffery * @brief An implementation of MctpDevice in terms of D-Bus interfaces exposed 254275f7c39SAndrew Jeffery * by @c mctpd. 255275f7c39SAndrew Jeffery * 256275f7c39SAndrew Jeffery * The construction or destruction of an MctpdDevice is not required to be 257275f7c39SAndrew Jeffery * correlated with signals from @c mctpd. For instance, EntityManager may expose 258275f7c39SAndrew Jeffery * the existance of an MCTP-capable device through its usual configuration 259275f7c39SAndrew Jeffery * mechanisms. 260275f7c39SAndrew Jeffery */ 261275f7c39SAndrew Jeffery class MCTPDDevice : 262275f7c39SAndrew Jeffery public MCTPDevice, 263275f7c39SAndrew Jeffery public std::enable_shared_from_this<MCTPDDevice> 264275f7c39SAndrew Jeffery { 265275f7c39SAndrew Jeffery public: 266275f7c39SAndrew Jeffery MCTPDDevice() = delete; 267275f7c39SAndrew Jeffery MCTPDDevice(const std::shared_ptr<sdbusplus::asio::connection>& connection, 268275f7c39SAndrew Jeffery const std::string& interface, 269275f7c39SAndrew Jeffery const std::vector<uint8_t>& physaddr); 270275f7c39SAndrew Jeffery MCTPDDevice(const MCTPDDevice& other) = delete; 271275f7c39SAndrew Jeffery MCTPDDevice(MCTPDDevice&& other) = delete; 272275f7c39SAndrew Jeffery ~MCTPDDevice() override = default; 273275f7c39SAndrew Jeffery 274275f7c39SAndrew Jeffery void setup(std::function<void(const std::error_code& ec, 275275f7c39SAndrew Jeffery const std::shared_ptr<MCTPEndpoint>& ep)>&& 276275f7c39SAndrew Jeffery added) override; 277275f7c39SAndrew Jeffery void remove() override; 278275f7c39SAndrew Jeffery std::string describe() const override; 279275f7c39SAndrew Jeffery 280275f7c39SAndrew Jeffery private: 281275f7c39SAndrew Jeffery static void onEndpointInterfacesRemoved( 282275f7c39SAndrew Jeffery const std::weak_ptr<MCTPDDevice>& weak, const std::string& objpath, 283275f7c39SAndrew Jeffery sdbusplus::message_t& msg); 284275f7c39SAndrew Jeffery 285275f7c39SAndrew Jeffery std::shared_ptr<sdbusplus::asio::connection> connection; 286275f7c39SAndrew Jeffery const std::string interface; 287275f7c39SAndrew Jeffery const std::vector<uint8_t> physaddr; 288275f7c39SAndrew Jeffery std::shared_ptr<MCTPDEndpoint> endpoint; 289275f7c39SAndrew Jeffery std::unique_ptr<sdbusplus::bus::match_t> removeMatch; 290275f7c39SAndrew Jeffery 291275f7c39SAndrew Jeffery /** 292275f7c39SAndrew Jeffery * @brief Actions to perform once endpoint setup has succeeded 293275f7c39SAndrew Jeffery * 294275f7c39SAndrew Jeffery * Now that the endpoint exists two tasks remain: 295275f7c39SAndrew Jeffery * 296275f7c39SAndrew Jeffery * 1. Setup the match capturing removal of the endpoint object by mctpd 297275f7c39SAndrew Jeffery * 2. Invoke the callback to notify the requester that setup has completed, 298275f7c39SAndrew Jeffery * providing the MctpEndpoint instance associated with the MctpDevice. 299275f7c39SAndrew Jeffery */ 300275f7c39SAndrew Jeffery void finaliseEndpoint( 301275f7c39SAndrew Jeffery const std::string& objpath, uint8_t eid, int network, 302275f7c39SAndrew Jeffery std::function<void(const std::error_code& ec, 303275f7c39SAndrew Jeffery const std::shared_ptr<MCTPEndpoint>& ep)>& added); 304275f7c39SAndrew Jeffery void endpointRemoved(); 305275f7c39SAndrew Jeffery }; 306275f7c39SAndrew Jeffery 307275f7c39SAndrew Jeffery class I2CMCTPDDevice : public MCTPDDevice 308275f7c39SAndrew Jeffery { 309275f7c39SAndrew Jeffery public: 310275f7c39SAndrew Jeffery static std::optional<SensorBaseConfigMap> match(const SensorData& config); 311275f7c39SAndrew Jeffery static bool match(const std::set<std::string>& interfaces); 312*556e04b8SPatrick Williams static std::shared_ptr<I2CMCTPDDevice> from( 313*556e04b8SPatrick Williams const std::shared_ptr<sdbusplus::asio::connection>& connection, 314275f7c39SAndrew Jeffery const SensorBaseConfigMap& iface); 315275f7c39SAndrew Jeffery 316275f7c39SAndrew Jeffery I2CMCTPDDevice() = delete; I2CMCTPDDevice(const std::shared_ptr<sdbusplus::asio::connection> & connection,int bus,uint8_t physaddr)317275f7c39SAndrew Jeffery I2CMCTPDDevice( 318275f7c39SAndrew Jeffery const std::shared_ptr<sdbusplus::asio::connection>& connection, int bus, 319275f7c39SAndrew Jeffery uint8_t physaddr) : 320275f7c39SAndrew Jeffery MCTPDDevice(connection, interfaceFromBus(bus), {physaddr}) 321275f7c39SAndrew Jeffery {} 322275f7c39SAndrew Jeffery ~I2CMCTPDDevice() override = default; 323275f7c39SAndrew Jeffery 324275f7c39SAndrew Jeffery private: 325275f7c39SAndrew Jeffery static constexpr const char* configType = "MCTPI2CTarget"; 326275f7c39SAndrew Jeffery 327275f7c39SAndrew Jeffery static std::string interfaceFromBus(int bus); 328275f7c39SAndrew Jeffery }; 329