xref: /openbmc/dbus-sensors/src/nvidia-gpu/MctpRequester.hpp (revision db74edb9ce0be3821d449b39de284a26ce8f07e8)
1 /*
2  * SPDX-FileCopyrightText: Copyright OpenBMC Authors
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #pragma once
7 
8 #include <MctpAsioEndpoint.hpp>
9 #include <OcpMctpVdm.hpp>
10 #include <boost/asio/generic/datagram_protocol.hpp>
11 #include <boost/asio/io_context.hpp>
12 #include <boost/asio/steady_timer.hpp>
13 #include <boost/circular_buffer.hpp>
14 #include <boost/container/devector.hpp>
15 #include <boost/container/flat_map.hpp>
16 #include <boost/container/small_vector.hpp>
17 
18 #include <cstddef>
19 #include <cstdint>
20 #include <expected>
21 #include <functional>
22 #include <iostream>
23 #include <memory>
24 #include <queue>
25 #include <span>
26 #include <system_error>
27 #include <unordered_map>
28 #include <utility>
29 
30 namespace mctp
31 {
32 class MctpRequester
33 {
34   public:
35     MctpRequester() = delete;
36 
37     MctpRequester(const MctpRequester&) = delete;
38 
39     MctpRequester(MctpRequester&&) = delete;
40 
41     MctpRequester& operator=(const MctpRequester&) = delete;
42 
43     MctpRequester& operator=(MctpRequester&&) = delete;
44 
45     explicit MctpRequester(boost::asio::io_context& ctx);
46 
47     void sendRecvMsg(uint8_t eid, std::span<const uint8_t> reqMsg,
48                      std::move_only_function<void(const std::error_code&,
49                                                   std::span<const uint8_t>)>
50                          callback);
51 
52   private:
53     using cb_t = std::move_only_function<void(const std::error_code&,
54                                               std::span<const uint8_t>)>;
55 
56     static constexpr uint8_t msgType = ocp::accelerator_management::messageType;
57 
58     struct RequestContext
59     {
60         std::vector<uint8_t> reqMsg;
61         cb_t callback;
62 
63         RequestContext(const RequestContext&) = delete;
64         RequestContext& operator=(const RequestContext&) = delete;
65 
66         RequestContext(RequestContext&&) = default;
67         RequestContext& operator=(RequestContext&&) = default;
68         ~RequestContext() = default;
69 
RequestContextmctp::MctpRequester::RequestContext70         explicit RequestContext(std::span<const uint8_t> req, cb_t&& cb) :
71             reqMsg(req.begin(), req.end()), callback(std::move(cb))
72         {}
73     };
74 
75     struct EidContext
76     {
77         boost::asio::steady_timer timer;
78         uint8_t iid{};
79         boost::container::devector<RequestContext> queue;
EidContextmctp::MctpRequester::EidContext80         EidContext(boost::asio::io_context& io) : timer{io}, iid{0xFF} {}
81         EidContext(EidContext&&) noexcept = default;
82         EidContext& operator=(EidContext&&) noexcept = default;
83         EidContext& operator=(const EidContext&) = delete;
84         EidContext(const EidContext&) = delete;
85         ~EidContext() = default;
86     };
87 
88     std::optional<uint8_t> getNextIid(uint8_t eid);
89     void startReceive();
90     void processRecvMsg(const boost::system::error_code& ec, size_t length);
91     void handleSendMsgCompletion(uint8_t eid,
92                                  const boost::system::error_code& ec,
93                                  size_t length);
94 
95     void handleResult(uint8_t eid, const std::error_code& ec,
96                       std::span<const uint8_t> buffer);
97     void processQueue(uint8_t eid);
98 
99     boost::asio::io_context& io;
100 
101     boost::asio::generic::datagram_protocol::socket mctpSocket;
102     static constexpr size_t maxMessageSize = 65536 + 256;
103     std::array<uint8_t, maxMessageSize> buffer{};
104     MctpAsioEndpoint recvEndPoint;
105     std::unordered_map<uint8_t, EidContext> requestContextQueues;
106 };
107 
108 } // namespace mctp
109