blob: c7aa15388e28d634efce9e578ffa8333b1d5aeae [file] [log] [blame]
Rohit PAI0a888262025-06-11 08:52:29 +05301#include "Inventory.hpp"
2
3#include "Utils.hpp"
4
Rohit PAIada6baa2025-07-01 18:26:19 +05305#include <MctpRequester.hpp>
Rohit PAI0a888262025-06-11 08:52:29 +05306#include <NvidiaGpuMctpVdm.hpp>
Rohit PAIada6baa2025-07-01 18:26:19 +05307#include <OcpMctpVdm.hpp>
8#include <boost/asio/io_context.hpp>
Rohit PAI0a888262025-06-11 08:52:29 +05309#include <phosphor-logging/lg2.hpp>
10#include <sdbusplus/asio/connection.hpp>
11#include <sdbusplus/asio/object_server.hpp>
12
Rohit PAIada6baa2025-07-01 18:26:19 +053013#include <cstdint>
Rohit PAI0a888262025-06-11 08:52:29 +053014#include <memory>
Rohit PAIada6baa2025-07-01 18:26:19 +053015#include <optional>
Rohit PAI0a888262025-06-11 08:52:29 +053016#include <string>
Rohit PAIada6baa2025-07-01 18:26:19 +053017#include <unordered_map>
18#include <variant>
Rohit PAI0a888262025-06-11 08:52:29 +053019
20constexpr const char* inventoryPrefix = "/xyz/openbmc_project/inventory/";
21constexpr const char* acceleratorIfaceName =
22 "xyz.openbmc_project.Inventory.Item.Accelerator";
Rohit PAIada6baa2025-07-01 18:26:19 +053023static constexpr const char* assetIfaceName =
24 "xyz.openbmc_project.Inventory.Decorator.Asset";
Rohit PAI0a888262025-06-11 08:52:29 +053025
26Inventory::Inventory(
27 const std::shared_ptr<sdbusplus::asio::connection>& /*conn*/,
28 sdbusplus::asio::object_server& objectServer,
Rohit PAIada6baa2025-07-01 18:26:19 +053029 const std::string& inventoryName, mctp::MctpRequester& mctpRequester,
30 const gpu::DeviceIdentification deviceTypeIn, const uint8_t eid,
31 boost::asio::io_context& io) :
32 name(escapeName(inventoryName)), mctpRequester(mctpRequester),
33 deviceType(deviceTypeIn), eid(eid), retryTimer(io)
Rohit PAI0a888262025-06-11 08:52:29 +053034{
Rohit PAIada6baa2025-07-01 18:26:19 +053035 requestBuffer = std::make_shared<InventoryRequestBuffer>();
36 responseBuffer = std::make_shared<InventoryResponseBuffer>();
37
38 std::string path = inventoryPrefix + name;
39 assetIface = objectServer.add_interface(path, assetIfaceName);
40 assetIface->register_property("Manufacturer", std::string("NVIDIA"));
41 // Register properties which need to be fetched from the device
42 registerProperty(gpu::InventoryPropertyId::SERIAL_NUMBER, assetIface,
43 "SerialNumber");
44 registerProperty(gpu::InventoryPropertyId::BOARD_PART_NUMBER, assetIface,
45 "PartNumber");
46 assetIface->initialize();
47
48 // Static properties
Rohit PAI0a888262025-06-11 08:52:29 +053049 if (deviceType == gpu::DeviceIdentification::DEVICE_GPU)
50 {
Rohit PAIada6baa2025-07-01 18:26:19 +053051 acceleratorInterface =
52 objectServer.add_interface(path, acceleratorIfaceName);
53 acceleratorInterface->register_property("Type", std::string("GPU"));
54 acceleratorInterface->initialize();
55 }
56
57 processNextProperty();
58}
59
60void Inventory::registerProperty(
61 gpu::InventoryPropertyId propertyId,
62 const std::shared_ptr<sdbusplus::asio::dbus_interface>& interface,
63 const std::string& propertyName)
64{
65 if (interface)
66 {
67 interface->register_property(propertyName, std::string{});
68 properties[propertyId] = {interface, propertyName, 0, true};
69 }
70}
71
72void Inventory::processInventoryProperty(gpu::InventoryPropertyId propertyId)
73{
74 auto it = properties.find(propertyId);
75 if (it != properties.end())
76 {
77 markPropertyPending(it);
78 std::optional<gpu::InventoryPropertyId> nextProperty =
79 getNextPendingProperty();
80 if (nextProperty && *nextProperty == propertyId)
Rohit PAI0a888262025-06-11 08:52:29 +053081 {
Rohit PAIada6baa2025-07-01 18:26:19 +053082 processNextProperty();
Rohit PAI0a888262025-06-11 08:52:29 +053083 }
Rohit PAIada6baa2025-07-01 18:26:19 +053084 }
85}
86
87void Inventory::markPropertyPending(
88 std::unordered_map<gpu::InventoryPropertyId, PropertyInfo>::iterator it)
89{
90 it->second.isPending = true;
91 it->second.retryCount = 0;
92}
93
94void Inventory::markPropertyProcessed(
95 std::unordered_map<gpu::InventoryPropertyId, PropertyInfo>::iterator it)
96{
97 it->second.isPending = false;
98}
99
100std::optional<gpu::InventoryPropertyId> Inventory::getNextPendingProperty()
101 const
102{
103 for (const auto& [propertyId, info] : properties)
104 {
105 if (info.isPending)
106 {
107 return propertyId;
108 }
109 }
110 return std::nullopt;
111}
112
113void Inventory::sendInventoryPropertyRequest(
114 gpu::InventoryPropertyId propertyId)
115{
116 int rc = gpu::encodeGetInventoryInformationRequest(
117 0, static_cast<uint8_t>(propertyId), *requestBuffer);
118 if (rc != 0)
119 {
120 lg2::error(
121 "Failed to encode property ID {PROP_ID} request for {NAME}: rc={RC}",
122 "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name, "RC",
123 rc);
124 return;
125 }
126
127 lg2::info(
128 "Sending inventory request for property ID {PROP_ID} to EID {EID} for {NAME}",
129 "PROP_ID", static_cast<uint8_t>(propertyId), "EID", eid, "NAME", name);
130
131 mctpRequester.sendRecvMsg(eid, *requestBuffer, *responseBuffer,
132 [this, propertyId](int sendRecvMsgResult) {
133 this->handleInventoryPropertyResponse(
134 propertyId, sendRecvMsgResult);
135 });
136}
137
138void Inventory::handleInventoryPropertyResponse(
139 gpu::InventoryPropertyId propertyId, int sendRecvMsgResult)
140{
141 auto it = properties.find(propertyId);
142 if (it == properties.end())
143 {
144 lg2::error("Property ID {PROP_ID} for {NAME} not found", "PROP_ID",
145 static_cast<uint8_t>(propertyId), "NAME", name);
146 processNextProperty();
147 return;
148 }
149
150 bool success = false;
151 if (sendRecvMsgResult == 0)
152 {
153 ocp::accelerator_management::CompletionCode cc{};
154 uint16_t reasonCode = 0;
155 gpu::InventoryValue info;
156 int rc = gpu::decodeGetInventoryInformationResponse(
157 *responseBuffer, cc, reasonCode, propertyId, info);
158
159 lg2::info(
160 "Response for property ID {PROP_ID} from {NAME}, sendRecvMsgResult: {RESULT}, decode_rc: {RC}, completion_code: {CC}, reason_code: {REASON}",
161 "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name, "RESULT",
162 sendRecvMsgResult, "RC", rc, "CC", static_cast<uint8_t>(cc),
163 "REASON", reasonCode);
164
165 if (rc == 0 &&
166 cc == ocp::accelerator_management::CompletionCode::SUCCESS &&
167 std::holds_alternative<std::string>(info))
168 {
169 std::string value = std::get<std::string>(info);
170 it->second.interface->set_property(it->second.propertyName, value);
171 lg2::info(
172 "Successfully received property ID {PROP_ID} for {NAME} with value: {VALUE}",
173 "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name,
174 "VALUE", value);
175 success = true;
176 }
177 }
178
179 if (!success)
180 {
181 it->second.retryCount++;
182 if (it->second.retryCount >= maxRetryAttempts)
Rohit PAI0a888262025-06-11 08:52:29 +0530183 {
184 lg2::error(
Rohit PAIada6baa2025-07-01 18:26:19 +0530185 "Property ID {PROP_ID} for {NAME} failed after {ATTEMPTS} attempts",
186 "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name,
187 "ATTEMPTS", maxRetryAttempts);
188 markPropertyProcessed(it);
Rohit PAI0a888262025-06-11 08:52:29 +0530189 }
Rohit PAIada6baa2025-07-01 18:26:19 +0530190 else
191 {
192 retryTimer.expires_after(retryDelay);
193 retryTimer.async_wait([this](const boost::system::error_code& ec) {
194 if (ec)
195 {
196 lg2::error("Retry timer error for {NAME}: {ERROR}", "NAME",
197 name, "ERROR", ec.message());
198 return;
199 }
200 this->processNextProperty();
201 });
202 return;
203 }
204 }
205 else
206 {
207 markPropertyProcessed(it);
208 }
209
210 processNextProperty();
211}
212
213void Inventory::processNextProperty()
214{
215 std::optional<gpu::InventoryPropertyId> nextProperty =
216 getNextPendingProperty();
217 if (nextProperty)
218 {
219 sendInventoryPropertyRequest(*nextProperty);
220 }
221 else
222 {
223 lg2::info("No pending properties found to process for {NAME}", "NAME",
224 name);
Rohit PAI0a888262025-06-11 08:52:29 +0530225 }
226}