xref: /openbmc/dbus-sensors/src/mctp/MCTPEndpoint.hpp (revision 556e04b8f374a9eb8cf32bf0e36ac46c14873eba)
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