blob: 18b9dc2e0dc0ca5b27f73783a8ef2829648141fb [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 PAIfb64f062025-06-13 18:20:02 +05309#include <boost/uuid/uuid.hpp>
10#include <boost/uuid/uuid_io.hpp>
Rohit PAI0a888262025-06-11 08:52:29 +053011#include <phosphor-logging/lg2.hpp>
12#include <sdbusplus/asio/connection.hpp>
13#include <sdbusplus/asio/object_server.hpp>
14
Rohit PAIfb64f062025-06-13 18:20:02 +053015#include <algorithm>
Rohit PAIada6baa2025-07-01 18:26:19 +053016#include <cstdint>
Rohit PAI0a888262025-06-11 08:52:29 +053017#include <memory>
Rohit PAIada6baa2025-07-01 18:26:19 +053018#include <optional>
Rohit PAI0a888262025-06-11 08:52:29 +053019#include <string>
Rohit PAIada6baa2025-07-01 18:26:19 +053020#include <unordered_map>
21#include <variant>
Rohit PAIfb64f062025-06-13 18:20:02 +053022#include <vector>
Rohit PAI0a888262025-06-11 08:52:29 +053023
24constexpr const char* inventoryPrefix = "/xyz/openbmc_project/inventory/";
25constexpr const char* acceleratorIfaceName =
26 "xyz.openbmc_project.Inventory.Item.Accelerator";
Rohit PAIada6baa2025-07-01 18:26:19 +053027static constexpr const char* assetIfaceName =
28 "xyz.openbmc_project.Inventory.Decorator.Asset";
Rohit PAIfb64f062025-06-13 18:20:02 +053029static constexpr const char* uuidIfaceName = "xyz.openbmc_project.Common.UUID";
Rohit PAI0a888262025-06-11 08:52:29 +053030
31Inventory::Inventory(
32 const std::shared_ptr<sdbusplus::asio::connection>& /*conn*/,
33 sdbusplus::asio::object_server& objectServer,
Rohit PAIada6baa2025-07-01 18:26:19 +053034 const std::string& inventoryName, mctp::MctpRequester& mctpRequester,
35 const gpu::DeviceIdentification deviceTypeIn, const uint8_t eid,
36 boost::asio::io_context& io) :
37 name(escapeName(inventoryName)), mctpRequester(mctpRequester),
38 deviceType(deviceTypeIn), eid(eid), retryTimer(io)
Rohit PAI0a888262025-06-11 08:52:29 +053039{
Rohit PAIada6baa2025-07-01 18:26:19 +053040 requestBuffer = std::make_shared<InventoryRequestBuffer>();
41 responseBuffer = std::make_shared<InventoryResponseBuffer>();
42
43 std::string path = inventoryPrefix + name;
Rohit PAIfb64f062025-06-13 18:20:02 +053044
Rohit PAIada6baa2025-07-01 18:26:19 +053045 assetIface = objectServer.add_interface(path, assetIfaceName);
46 assetIface->register_property("Manufacturer", std::string("NVIDIA"));
47 // Register properties which need to be fetched from the device
48 registerProperty(gpu::InventoryPropertyId::SERIAL_NUMBER, assetIface,
49 "SerialNumber");
50 registerProperty(gpu::InventoryPropertyId::BOARD_PART_NUMBER, assetIface,
51 "PartNumber");
52 assetIface->initialize();
53
Rohit PAIfb64f062025-06-13 18:20:02 +053054 uuidInterface = objectServer.add_interface(path, uuidIfaceName);
55 registerProperty(gpu::InventoryPropertyId::DEVICE_GUID, uuidInterface,
56 "UUID");
57 uuidInterface->initialize();
58
Rohit PAIada6baa2025-07-01 18:26:19 +053059 // Static properties
Rohit PAI0a888262025-06-11 08:52:29 +053060 if (deviceType == gpu::DeviceIdentification::DEVICE_GPU)
61 {
Rohit PAIada6baa2025-07-01 18:26:19 +053062 acceleratorInterface =
63 objectServer.add_interface(path, acceleratorIfaceName);
64 acceleratorInterface->register_property("Type", std::string("GPU"));
65 acceleratorInterface->initialize();
66 }
67
68 processNextProperty();
69}
70
71void Inventory::registerProperty(
72 gpu::InventoryPropertyId propertyId,
73 const std::shared_ptr<sdbusplus::asio::dbus_interface>& interface,
74 const std::string& propertyName)
75{
76 if (interface)
77 {
78 interface->register_property(propertyName, std::string{});
79 properties[propertyId] = {interface, propertyName, 0, true};
80 }
81}
82
83void Inventory::processInventoryProperty(gpu::InventoryPropertyId propertyId)
84{
85 auto it = properties.find(propertyId);
86 if (it != properties.end())
87 {
88 markPropertyPending(it);
89 std::optional<gpu::InventoryPropertyId> nextProperty =
90 getNextPendingProperty();
91 if (nextProperty && *nextProperty == propertyId)
Rohit PAI0a888262025-06-11 08:52:29 +053092 {
Rohit PAIada6baa2025-07-01 18:26:19 +053093 processNextProperty();
Rohit PAI0a888262025-06-11 08:52:29 +053094 }
Rohit PAIada6baa2025-07-01 18:26:19 +053095 }
96}
97
98void Inventory::markPropertyPending(
99 std::unordered_map<gpu::InventoryPropertyId, PropertyInfo>::iterator it)
100{
101 it->second.isPending = true;
102 it->second.retryCount = 0;
103}
104
105void Inventory::markPropertyProcessed(
106 std::unordered_map<gpu::InventoryPropertyId, PropertyInfo>::iterator it)
107{
108 it->second.isPending = false;
109}
110
111std::optional<gpu::InventoryPropertyId> Inventory::getNextPendingProperty()
112 const
113{
114 for (const auto& [propertyId, info] : properties)
115 {
116 if (info.isPending)
117 {
118 return propertyId;
119 }
120 }
121 return std::nullopt;
122}
123
124void Inventory::sendInventoryPropertyRequest(
125 gpu::InventoryPropertyId propertyId)
126{
127 int rc = gpu::encodeGetInventoryInformationRequest(
128 0, static_cast<uint8_t>(propertyId), *requestBuffer);
129 if (rc != 0)
130 {
131 lg2::error(
132 "Failed to encode property ID {PROP_ID} request for {NAME}: rc={RC}",
133 "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name, "RC",
134 rc);
135 return;
136 }
137
138 lg2::info(
139 "Sending inventory request for property ID {PROP_ID} to EID {EID} for {NAME}",
140 "PROP_ID", static_cast<uint8_t>(propertyId), "EID", eid, "NAME", name);
141
142 mctpRequester.sendRecvMsg(eid, *requestBuffer, *responseBuffer,
143 [this, propertyId](int sendRecvMsgResult) {
144 this->handleInventoryPropertyResponse(
145 propertyId, sendRecvMsgResult);
146 });
147}
148
149void Inventory::handleInventoryPropertyResponse(
150 gpu::InventoryPropertyId propertyId, int sendRecvMsgResult)
151{
152 auto it = properties.find(propertyId);
153 if (it == properties.end())
154 {
155 lg2::error("Property ID {PROP_ID} for {NAME} not found", "PROP_ID",
156 static_cast<uint8_t>(propertyId), "NAME", name);
157 processNextProperty();
158 return;
159 }
160
161 bool success = false;
162 if (sendRecvMsgResult == 0)
163 {
164 ocp::accelerator_management::CompletionCode cc{};
165 uint16_t reasonCode = 0;
166 gpu::InventoryValue info;
167 int rc = gpu::decodeGetInventoryInformationResponse(
168 *responseBuffer, cc, reasonCode, propertyId, info);
169
170 lg2::info(
171 "Response for property ID {PROP_ID} from {NAME}, sendRecvMsgResult: {RESULT}, decode_rc: {RC}, completion_code: {CC}, reason_code: {REASON}",
172 "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name, "RESULT",
173 sendRecvMsgResult, "RC", rc, "CC", static_cast<uint8_t>(cc),
174 "REASON", reasonCode);
175
176 if (rc == 0 &&
Rohit PAIfb64f062025-06-13 18:20:02 +0530177 cc == ocp::accelerator_management::CompletionCode::SUCCESS)
Rohit PAIada6baa2025-07-01 18:26:19 +0530178 {
Rohit PAIfb64f062025-06-13 18:20:02 +0530179 std::string value;
180
181 // Handle different property types based on property ID
182 switch (propertyId)
183 {
184 case gpu::InventoryPropertyId::BOARD_PART_NUMBER:
185 case gpu::InventoryPropertyId::SERIAL_NUMBER:
186 case gpu::InventoryPropertyId::MARKETING_NAME:
187 case gpu::InventoryPropertyId::DEVICE_PART_NUMBER:
188 if (std::holds_alternative<std::string>(info))
189 {
190 value = std::get<std::string>(info);
191 }
192 else
193 {
194 lg2::error(
195 "Property ID {PROP_ID} for {NAME} expected string but got different type",
196 "PROP_ID", static_cast<uint8_t>(propertyId), "NAME",
197 name);
198 break;
199 }
200 break;
201
202 case gpu::InventoryPropertyId::DEVICE_GUID:
203 if (std::holds_alternative<std::vector<uint8_t>>(info))
204 {
205 const auto& guidBytes =
206 std::get<std::vector<uint8_t>>(info);
207 if (guidBytes.size() >= 16)
208 {
209 boost::uuids::uuid uuid;
210 std::copy(guidBytes.begin(), guidBytes.begin() + 16,
211 uuid.begin());
212 value = boost::uuids::to_string(uuid);
213 }
214 else
215 {
216 lg2::error(
217 "Property ID {PROP_ID} for {NAME} GUID size {SIZE} is less than 16 bytes",
218 "PROP_ID", static_cast<uint8_t>(propertyId),
219 "NAME", name, "SIZE", guidBytes.size());
220 break;
221 }
222 }
223 else
224 {
225 lg2::error(
226 "Property ID {PROP_ID} for {NAME} expected vector<uint8_t> but got different type",
227 "PROP_ID", static_cast<uint8_t>(propertyId), "NAME",
228 name);
229 break;
230 }
231 break;
232
233 default:
234 lg2::error("Unsupported property ID {PROP_ID} for {NAME}",
235 "PROP_ID", static_cast<uint8_t>(propertyId),
236 "NAME", name);
237 break;
238 }
239
240 if (!value.empty())
241 {
242 it->second.interface->set_property(it->second.propertyName,
243 value);
244 lg2::info(
245 "Successfully received property ID {PROP_ID} for {NAME} with value: {VALUE}",
246 "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name,
247 "VALUE", value);
248 success = true;
249 }
Rohit PAIada6baa2025-07-01 18:26:19 +0530250 }
251 }
252
253 if (!success)
254 {
255 it->second.retryCount++;
256 if (it->second.retryCount >= maxRetryAttempts)
Rohit PAI0a888262025-06-11 08:52:29 +0530257 {
258 lg2::error(
Rohit PAIada6baa2025-07-01 18:26:19 +0530259 "Property ID {PROP_ID} for {NAME} failed after {ATTEMPTS} attempts",
260 "PROP_ID", static_cast<uint8_t>(propertyId), "NAME", name,
261 "ATTEMPTS", maxRetryAttempts);
262 markPropertyProcessed(it);
Rohit PAI0a888262025-06-11 08:52:29 +0530263 }
Rohit PAIada6baa2025-07-01 18:26:19 +0530264 else
265 {
266 retryTimer.expires_after(retryDelay);
267 retryTimer.async_wait([this](const boost::system::error_code& ec) {
268 if (ec)
269 {
270 lg2::error("Retry timer error for {NAME}: {ERROR}", "NAME",
271 name, "ERROR", ec.message());
272 return;
273 }
274 this->processNextProperty();
275 });
276 return;
277 }
278 }
279 else
280 {
281 markPropertyProcessed(it);
282 }
283
284 processNextProperty();
285}
286
287void Inventory::processNextProperty()
288{
289 std::optional<gpu::InventoryPropertyId> nextProperty =
290 getNextPendingProperty();
291 if (nextProperty)
292 {
293 sendInventoryPropertyRequest(*nextProperty);
294 }
295 else
296 {
297 lg2::info("No pending properties found to process for {NAME}", "NAME",
298 name);
Rohit PAI0a888262025-06-11 08:52:29 +0530299 }
300}