1*275f7c39SAndrew Jeffery #pragma once 2*275f7c39SAndrew Jeffery 3*275f7c39SAndrew Jeffery #include "Utils.hpp" 4*275f7c39SAndrew Jeffery 5*275f7c39SAndrew Jeffery #include <boost/asio/steady_timer.hpp> 6*275f7c39SAndrew Jeffery #include <sdbusplus/asio/connection.hpp> 7*275f7c39SAndrew Jeffery #include <sdbusplus/bus/match.hpp> 8*275f7c39SAndrew Jeffery #include <sdbusplus/message.hpp> 9*275f7c39SAndrew Jeffery #include <sdbusplus/message/native_types.hpp> 10*275f7c39SAndrew Jeffery 11*275f7c39SAndrew Jeffery #include <cstdint> 12*275f7c39SAndrew Jeffery #include <iostream> 13*275f7c39SAndrew Jeffery 14*275f7c39SAndrew Jeffery /** 15*275f7c39SAndrew Jeffery * @file 16*275f7c39SAndrew Jeffery * @brief Abstract and concrete classes representing MCTP concepts and 17*275f7c39SAndrew Jeffery * behaviours. 18*275f7c39SAndrew Jeffery */ 19*275f7c39SAndrew Jeffery 20*275f7c39SAndrew Jeffery /** 21*275f7c39SAndrew Jeffery * @brief An exception type that may be thrown by implementations of the MCTP 22*275f7c39SAndrew Jeffery * abstract classes. 23*275f7c39SAndrew Jeffery * 24*275f7c39SAndrew Jeffery * This exception should be the basis for all exceptions thrown out of the MCTP 25*275f7c39SAndrew Jeffery * APIs, and should capture any other exceptions that occur. 26*275f7c39SAndrew Jeffery */ 27*275f7c39SAndrew Jeffery class MCTPException : public std::exception 28*275f7c39SAndrew Jeffery { 29*275f7c39SAndrew Jeffery public: 30*275f7c39SAndrew Jeffery MCTPException() = delete; MCTPException(const char * desc)31*275f7c39SAndrew Jeffery explicit MCTPException(const char* desc) : desc(desc) {} what() const32*275f7c39SAndrew Jeffery const char* what() const noexcept override 33*275f7c39SAndrew Jeffery { 34*275f7c39SAndrew Jeffery return desc; 35*275f7c39SAndrew Jeffery } 36*275f7c39SAndrew Jeffery 37*275f7c39SAndrew Jeffery private: 38*275f7c39SAndrew Jeffery const char* desc; 39*275f7c39SAndrew Jeffery }; 40*275f7c39SAndrew Jeffery 41*275f7c39SAndrew Jeffery /** 42*275f7c39SAndrew Jeffery * @brief An enum of the MCTP transports described in DSP0239 v1.10.0 Section 7. 43*275f7c39SAndrew Jeffery * 44*275f7c39SAndrew Jeffery * https://www.dmtf.org/sites/default/files/standards/documents/DSP0239_1.10.0.pdf 45*275f7c39SAndrew Jeffery */ 46*275f7c39SAndrew Jeffery enum class MCTPTransport 47*275f7c39SAndrew Jeffery { 48*275f7c39SAndrew Jeffery Reserved = 0x00, 49*275f7c39SAndrew Jeffery SMBus = 0x01, 50*275f7c39SAndrew Jeffery }; 51*275f7c39SAndrew Jeffery 52*275f7c39SAndrew Jeffery /** 53*275f7c39SAndrew Jeffery * @brief Captures properties of MCTP interfaces. 54*275f7c39SAndrew Jeffery * 55*275f7c39SAndrew Jeffery * https://github.com/CodeConstruct/mctp/blob/v1.1/src/mctp.c#L672-L703 56*275f7c39SAndrew Jeffery */ 57*275f7c39SAndrew Jeffery struct MCTPInterface 58*275f7c39SAndrew Jeffery { 59*275f7c39SAndrew Jeffery std::string name; 60*275f7c39SAndrew Jeffery MCTPTransport transport; 61*275f7c39SAndrew Jeffery 62*275f7c39SAndrew Jeffery auto operator<=>(const MCTPInterface& r) const = default; 63*275f7c39SAndrew Jeffery }; 64*275f7c39SAndrew Jeffery 65*275f7c39SAndrew Jeffery class MCTPDevice; 66*275f7c39SAndrew Jeffery 67*275f7c39SAndrew Jeffery /** 68*275f7c39SAndrew Jeffery * @brief Captures the behaviour of an endpoint at the MCTP layer 69*275f7c39SAndrew Jeffery * 70*275f7c39SAndrew Jeffery * The lifetime of an instance of MctpEndpoint is proportional to the lifetime 71*275f7c39SAndrew Jeffery * of the endpoint configuration. If an endpoint is deconfigured such that its 72*275f7c39SAndrew Jeffery * device has no assigned EID, then any related MctpEndpoint instance must be 73*275f7c39SAndrew Jeffery * destructed as a consequence. 74*275f7c39SAndrew Jeffery */ 75*275f7c39SAndrew Jeffery class MCTPEndpoint 76*275f7c39SAndrew Jeffery { 77*275f7c39SAndrew Jeffery public: 78*275f7c39SAndrew Jeffery using Event = std::function<void(const std::shared_ptr<MCTPEndpoint>& ep)>; 79*275f7c39SAndrew Jeffery using Result = std::function<void(const std::error_code& ec)>; 80*275f7c39SAndrew Jeffery 81*275f7c39SAndrew Jeffery virtual ~MCTPEndpoint() = default; 82*275f7c39SAndrew Jeffery 83*275f7c39SAndrew Jeffery /** 84*275f7c39SAndrew Jeffery * @return The Linux network ID of the network in which the endpoint 85*275f7c39SAndrew Jeffery participates 86*275f7c39SAndrew Jeffery */ 87*275f7c39SAndrew Jeffery virtual int network() const = 0; 88*275f7c39SAndrew Jeffery 89*275f7c39SAndrew Jeffery /** 90*275f7c39SAndrew Jeffery * @return The MCTP endpoint ID of the endpoint in its network 91*275f7c39SAndrew Jeffery */ 92*275f7c39SAndrew Jeffery virtual uint8_t eid() const = 0; 93*275f7c39SAndrew Jeffery 94*275f7c39SAndrew Jeffery /** 95*275f7c39SAndrew Jeffery * @brief Subscribe to events produced by an endpoint object across its 96*275f7c39SAndrew Jeffery * lifecycle 97*275f7c39SAndrew Jeffery * 98*275f7c39SAndrew Jeffery * @param degraded The callback to execute when the MCTP layer indicates the 99*275f7c39SAndrew Jeffery * endpoint is unresponsive 100*275f7c39SAndrew Jeffery * 101*275f7c39SAndrew Jeffery * @param available The callback to execute when the MCTP layer indicates 102*275f7c39SAndrew Jeffery * that communication with the degraded endpoint has been 103*275f7c39SAndrew Jeffery * recovered 104*275f7c39SAndrew Jeffery * 105*275f7c39SAndrew Jeffery * @param removed The callback to execute when the MCTP layer indicates the 106*275f7c39SAndrew Jeffery * endpoint has been removed. 107*275f7c39SAndrew Jeffery */ 108*275f7c39SAndrew Jeffery virtual void subscribe(Event&& degraded, Event&& available, 109*275f7c39SAndrew Jeffery Event&& removed) = 0; 110*275f7c39SAndrew Jeffery 111*275f7c39SAndrew Jeffery /** 112*275f7c39SAndrew Jeffery * @brief Remove the endpoint from its associated network 113*275f7c39SAndrew Jeffery */ 114*275f7c39SAndrew Jeffery virtual void remove() = 0; 115*275f7c39SAndrew Jeffery 116*275f7c39SAndrew Jeffery /** 117*275f7c39SAndrew Jeffery * @return A formatted string representing the endpoint in terms of its 118*275f7c39SAndrew Jeffery * address properties 119*275f7c39SAndrew Jeffery */ 120*275f7c39SAndrew Jeffery virtual std::string describe() const = 0; 121*275f7c39SAndrew Jeffery 122*275f7c39SAndrew Jeffery /** 123*275f7c39SAndrew Jeffery * @return A shared pointer to the device instance associated with the 124*275f7c39SAndrew Jeffery * endpoint. 125*275f7c39SAndrew Jeffery */ 126*275f7c39SAndrew Jeffery virtual std::shared_ptr<MCTPDevice> device() const = 0; 127*275f7c39SAndrew Jeffery }; 128*275f7c39SAndrew Jeffery 129*275f7c39SAndrew Jeffery /** 130*275f7c39SAndrew Jeffery * @brief Represents an MCTP-capable device on a bus. 131*275f7c39SAndrew Jeffery * 132*275f7c39SAndrew Jeffery * It is often known that an MCTP-capable device exists on a bus prior to the 133*275f7c39SAndrew Jeffery * MCTP stack configuring the device for communication. MctpDevice exposes the 134*275f7c39SAndrew Jeffery * ability to set-up the endpoint device for communication. 135*275f7c39SAndrew Jeffery * 136*275f7c39SAndrew Jeffery * The lifetime of an MctpDevice instance is proportional to the existence of an 137*275f7c39SAndrew Jeffery * MCTP-capable device in the system. If a device represented by an MctpDevice 138*275f7c39SAndrew Jeffery * instance is removed from the system then any related MctpDevice instance must 139*275f7c39SAndrew Jeffery * be destructed a consequence. 140*275f7c39SAndrew Jeffery * 141*275f7c39SAndrew Jeffery * Successful set-up of the device as an endpoint yields an MctpEndpoint 142*275f7c39SAndrew Jeffery * instance. The lifetime of the MctpEndpoint instance produced must not exceed 143*275f7c39SAndrew Jeffery * the lifetime of its parent MctpDevice. 144*275f7c39SAndrew Jeffery */ 145*275f7c39SAndrew Jeffery class MCTPDevice 146*275f7c39SAndrew Jeffery { 147*275f7c39SAndrew Jeffery public: 148*275f7c39SAndrew Jeffery virtual ~MCTPDevice() = default; 149*275f7c39SAndrew Jeffery 150*275f7c39SAndrew Jeffery /** 151*275f7c39SAndrew Jeffery * @brief Configure the device for MCTP communication 152*275f7c39SAndrew Jeffery * 153*275f7c39SAndrew Jeffery * @param added The callback to invoke once the setup process has 154*275f7c39SAndrew Jeffery * completed. The provided error code @p ec must be 155*275f7c39SAndrew Jeffery * checked as the request may not have succeeded. If 156*275f7c39SAndrew Jeffery * the request was successful then @p ep contains a 157*275f7c39SAndrew Jeffery * valid MctpEndpoint instance. 158*275f7c39SAndrew Jeffery */ 159*275f7c39SAndrew Jeffery virtual void 160*275f7c39SAndrew Jeffery setup(std::function<void(const std::error_code& ec, 161*275f7c39SAndrew Jeffery const std::shared_ptr<MCTPEndpoint>& ep)>&& 162*275f7c39SAndrew Jeffery added) = 0; 163*275f7c39SAndrew Jeffery 164*275f7c39SAndrew Jeffery /** 165*275f7c39SAndrew Jeffery * @brief Remove the device and any associated endpoint from the MCTP stack. 166*275f7c39SAndrew Jeffery */ 167*275f7c39SAndrew Jeffery virtual void remove() = 0; 168*275f7c39SAndrew Jeffery 169*275f7c39SAndrew Jeffery /** 170*275f7c39SAndrew Jeffery * @return A formatted string representing the device in terms of its 171*275f7c39SAndrew Jeffery * address properties. 172*275f7c39SAndrew Jeffery */ 173*275f7c39SAndrew Jeffery virtual std::string describe() const = 0; 174*275f7c39SAndrew Jeffery }; 175*275f7c39SAndrew Jeffery 176*275f7c39SAndrew Jeffery class MCTPDDevice; 177*275f7c39SAndrew Jeffery 178*275f7c39SAndrew Jeffery /** 179*275f7c39SAndrew Jeffery * @brief An implementation of MctpEndpoint in terms of the D-Bus interfaces 180*275f7c39SAndrew Jeffery * exposed by @c mctpd. 181*275f7c39SAndrew Jeffery * 182*275f7c39SAndrew Jeffery * The lifetime of an MctpdEndpoint is proportional to the lifetime of the 183*275f7c39SAndrew Jeffery * endpoint object exposed by @c mctpd. The lifecycle of @c mctpd endpoint 184*275f7c39SAndrew Jeffery * objects is discussed here: 185*275f7c39SAndrew Jeffery * 186*275f7c39SAndrew Jeffery * https://github.com/CodeConstruct/mctp/pull/23/files#diff-00234f5f2543b8b9b8a419597e55121fe1cc57cf1c7e4ff9472bed83096bd28e 187*275f7c39SAndrew Jeffery */ 188*275f7c39SAndrew Jeffery class MCTPDEndpoint : 189*275f7c39SAndrew Jeffery public MCTPEndpoint, 190*275f7c39SAndrew Jeffery public std::enable_shared_from_this<MCTPDEndpoint> 191*275f7c39SAndrew Jeffery { 192*275f7c39SAndrew Jeffery public: 193*275f7c39SAndrew Jeffery static std::string path(const std::shared_ptr<MCTPEndpoint>& ep); 194*275f7c39SAndrew Jeffery 195*275f7c39SAndrew 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)196*275f7c39SAndrew Jeffery MCTPDEndpoint( 197*275f7c39SAndrew Jeffery const std::shared_ptr<MCTPDDevice>& dev, 198*275f7c39SAndrew Jeffery const std::shared_ptr<sdbusplus::asio::connection>& connection, 199*275f7c39SAndrew Jeffery sdbusplus::message::object_path objpath, int network, uint8_t eid) : 200*275f7c39SAndrew Jeffery dev(dev), connection(connection), objpath(std::move(objpath)), 201*275f7c39SAndrew Jeffery mctp{network, eid} 202*275f7c39SAndrew Jeffery {} 203*275f7c39SAndrew Jeffery MCTPDEndpoint& McptdEndpoint(const MCTPDEndpoint& other) = delete; 204*275f7c39SAndrew Jeffery MCTPDEndpoint(MCTPDEndpoint&& other) noexcept = default; 205*275f7c39SAndrew Jeffery ~MCTPDEndpoint() override = default; 206*275f7c39SAndrew Jeffery 207*275f7c39SAndrew Jeffery int network() const override; 208*275f7c39SAndrew Jeffery uint8_t eid() const override; 209*275f7c39SAndrew Jeffery void subscribe(Event&& degraded, Event&& available, 210*275f7c39SAndrew Jeffery Event&& removed) override; 211*275f7c39SAndrew Jeffery void remove() override; 212*275f7c39SAndrew Jeffery 213*275f7c39SAndrew Jeffery std::string describe() const override; 214*275f7c39SAndrew Jeffery 215*275f7c39SAndrew Jeffery std::shared_ptr<MCTPDevice> device() const override; 216*275f7c39SAndrew Jeffery 217*275f7c39SAndrew Jeffery /** 218*275f7c39SAndrew Jeffery * @brief Indicate the endpoint has been removed 219*275f7c39SAndrew Jeffery * 220*275f7c39SAndrew Jeffery * Called from the implementation of MctpdDevice for resource cleanup 221*275f7c39SAndrew Jeffery * prior to destruction. Resource cleanup is delegated by invoking the 222*275f7c39SAndrew Jeffery * notifyRemoved() callback. As the actions may be abitrary we avoid 223*275f7c39SAndrew Jeffery * invoking notifyRemoved() in the destructor. 224*275f7c39SAndrew Jeffery */ 225*275f7c39SAndrew Jeffery void removed(); 226*275f7c39SAndrew Jeffery 227*275f7c39SAndrew Jeffery private: 228*275f7c39SAndrew Jeffery std::shared_ptr<MCTPDDevice> dev; 229*275f7c39SAndrew Jeffery std::shared_ptr<sdbusplus::asio::connection> connection; 230*275f7c39SAndrew Jeffery sdbusplus::message::object_path objpath; 231*275f7c39SAndrew Jeffery struct 232*275f7c39SAndrew Jeffery { 233*275f7c39SAndrew Jeffery int network; 234*275f7c39SAndrew Jeffery uint8_t eid; 235*275f7c39SAndrew Jeffery } mctp; 236*275f7c39SAndrew Jeffery MCTPEndpoint::Event notifyAvailable; 237*275f7c39SAndrew Jeffery MCTPEndpoint::Event notifyDegraded; 238*275f7c39SAndrew Jeffery MCTPEndpoint::Event notifyRemoved; 239*275f7c39SAndrew Jeffery std::optional<sdbusplus::bus::match_t> connectivityMatch; 240*275f7c39SAndrew Jeffery 241*275f7c39SAndrew Jeffery void onMctpEndpointChange(sdbusplus::message_t& msg); 242*275f7c39SAndrew Jeffery void updateEndpointConnectivity(const std::string& connectivity); 243*275f7c39SAndrew Jeffery }; 244*275f7c39SAndrew Jeffery 245*275f7c39SAndrew Jeffery /** 246*275f7c39SAndrew Jeffery * @brief An implementation of MctpDevice in terms of D-Bus interfaces exposed 247*275f7c39SAndrew Jeffery * by @c mctpd. 248*275f7c39SAndrew Jeffery * 249*275f7c39SAndrew Jeffery * The construction or destruction of an MctpdDevice is not required to be 250*275f7c39SAndrew Jeffery * correlated with signals from @c mctpd. For instance, EntityManager may expose 251*275f7c39SAndrew Jeffery * the existance of an MCTP-capable device through its usual configuration 252*275f7c39SAndrew Jeffery * mechanisms. 253*275f7c39SAndrew Jeffery */ 254*275f7c39SAndrew Jeffery class MCTPDDevice : 255*275f7c39SAndrew Jeffery public MCTPDevice, 256*275f7c39SAndrew Jeffery public std::enable_shared_from_this<MCTPDDevice> 257*275f7c39SAndrew Jeffery { 258*275f7c39SAndrew Jeffery public: 259*275f7c39SAndrew Jeffery MCTPDDevice() = delete; 260*275f7c39SAndrew Jeffery MCTPDDevice(const std::shared_ptr<sdbusplus::asio::connection>& connection, 261*275f7c39SAndrew Jeffery const std::string& interface, 262*275f7c39SAndrew Jeffery const std::vector<uint8_t>& physaddr); 263*275f7c39SAndrew Jeffery MCTPDDevice(const MCTPDDevice& other) = delete; 264*275f7c39SAndrew Jeffery MCTPDDevice(MCTPDDevice&& other) = delete; 265*275f7c39SAndrew Jeffery ~MCTPDDevice() override = default; 266*275f7c39SAndrew Jeffery 267*275f7c39SAndrew Jeffery void setup(std::function<void(const std::error_code& ec, 268*275f7c39SAndrew Jeffery const std::shared_ptr<MCTPEndpoint>& ep)>&& 269*275f7c39SAndrew Jeffery added) override; 270*275f7c39SAndrew Jeffery void remove() override; 271*275f7c39SAndrew Jeffery std::string describe() const override; 272*275f7c39SAndrew Jeffery 273*275f7c39SAndrew Jeffery private: 274*275f7c39SAndrew Jeffery static void onEndpointInterfacesRemoved( 275*275f7c39SAndrew Jeffery const std::weak_ptr<MCTPDDevice>& weak, const std::string& objpath, 276*275f7c39SAndrew Jeffery sdbusplus::message_t& msg); 277*275f7c39SAndrew Jeffery 278*275f7c39SAndrew Jeffery std::shared_ptr<sdbusplus::asio::connection> connection; 279*275f7c39SAndrew Jeffery const std::string interface; 280*275f7c39SAndrew Jeffery const std::vector<uint8_t> physaddr; 281*275f7c39SAndrew Jeffery std::shared_ptr<MCTPDEndpoint> endpoint; 282*275f7c39SAndrew Jeffery std::unique_ptr<sdbusplus::bus::match_t> removeMatch; 283*275f7c39SAndrew Jeffery 284*275f7c39SAndrew Jeffery /** 285*275f7c39SAndrew Jeffery * @brief Actions to perform once endpoint setup has succeeded 286*275f7c39SAndrew Jeffery * 287*275f7c39SAndrew Jeffery * Now that the endpoint exists two tasks remain: 288*275f7c39SAndrew Jeffery * 289*275f7c39SAndrew Jeffery * 1. Setup the match capturing removal of the endpoint object by mctpd 290*275f7c39SAndrew Jeffery * 2. Invoke the callback to notify the requester that setup has completed, 291*275f7c39SAndrew Jeffery * providing the MctpEndpoint instance associated with the MctpDevice. 292*275f7c39SAndrew Jeffery */ 293*275f7c39SAndrew Jeffery void finaliseEndpoint( 294*275f7c39SAndrew Jeffery const std::string& objpath, uint8_t eid, int network, 295*275f7c39SAndrew Jeffery std::function<void(const std::error_code& ec, 296*275f7c39SAndrew Jeffery const std::shared_ptr<MCTPEndpoint>& ep)>& added); 297*275f7c39SAndrew Jeffery void endpointRemoved(); 298*275f7c39SAndrew Jeffery }; 299*275f7c39SAndrew Jeffery 300*275f7c39SAndrew Jeffery class I2CMCTPDDevice : public MCTPDDevice 301*275f7c39SAndrew Jeffery { 302*275f7c39SAndrew Jeffery public: 303*275f7c39SAndrew Jeffery static std::optional<SensorBaseConfigMap> match(const SensorData& config); 304*275f7c39SAndrew Jeffery static bool match(const std::set<std::string>& interfaces); 305*275f7c39SAndrew Jeffery static std::shared_ptr<I2CMCTPDDevice> 306*275f7c39SAndrew Jeffery from(const std::shared_ptr<sdbusplus::asio::connection>& connection, 307*275f7c39SAndrew Jeffery const SensorBaseConfigMap& iface); 308*275f7c39SAndrew Jeffery 309*275f7c39SAndrew Jeffery I2CMCTPDDevice() = delete; I2CMCTPDDevice(const std::shared_ptr<sdbusplus::asio::connection> & connection,int bus,uint8_t physaddr)310*275f7c39SAndrew Jeffery I2CMCTPDDevice( 311*275f7c39SAndrew Jeffery const std::shared_ptr<sdbusplus::asio::connection>& connection, int bus, 312*275f7c39SAndrew Jeffery uint8_t physaddr) : 313*275f7c39SAndrew Jeffery MCTPDDevice(connection, interfaceFromBus(bus), {physaddr}) 314*275f7c39SAndrew Jeffery {} 315*275f7c39SAndrew Jeffery ~I2CMCTPDDevice() override = default; 316*275f7c39SAndrew Jeffery 317*275f7c39SAndrew Jeffery private: 318*275f7c39SAndrew Jeffery static constexpr const char* configType = "MCTPI2CTarget"; 319*275f7c39SAndrew Jeffery 320*275f7c39SAndrew Jeffery static std::string interfaceFromBus(int bus); 321*275f7c39SAndrew Jeffery }; 322