blob: 18676f305ed7ab07467c7e56d942d6fbe8f04df4 [file] [log] [blame]
Rohit PAId87bf7f2025-06-11 08:52:29 +05301#include "Inventory.hpp"
2
3#include "Utils.hpp"
4
Rohit PAI15e5d9f2025-06-12 17:11:46 +05305#include <boost/asio/io_context.hpp>
Rohit PAId87bf7f2025-06-11 08:52:29 +05306#include <phosphor-logging/lg2.hpp>
7
Rohit PAI15e5d9f2025-06-12 17:11:46 +05308#include <optional>
9#include <string_view>
10#include <utility>
11
12constexpr int maxRetryAttempts = 3;
Rohit PAId87bf7f2025-06-11 08:52:29 +053013static constexpr const char* inventoryPrefix =
14 "/xyz/openbmc_project/inventory/";
15static constexpr const char* acceleratorIfaceName =
16 "xyz.openbmc_project.Inventory.Item.Accelerator";
17static constexpr const char* assetIfaceName =
18 "xyz.openbmc_project.Inventory.Decorator.Asset";
19
20Inventory::Inventory(
21 const std::shared_ptr<sdbusplus::asio::connection>& /*conn*/,
22 sdbusplus::asio::object_server& objectServer,
23 const std::string& inventoryName, mctp::MctpRequester& mctpRequester,
Rohit PAI15e5d9f2025-06-12 17:11:46 +053024 DeviceType deviceType, uint8_t eid, boost::asio::io_context& io) :
Rohit PAId87bf7f2025-06-11 08:52:29 +053025 name(escapeName(inventoryName)), mctpRequester(mctpRequester),
Rohit PAI15e5d9f2025-06-12 17:11:46 +053026 deviceType(deviceType), eid(eid), retryTimer(io)
Rohit PAId87bf7f2025-06-11 08:52:29 +053027{
Rohit PAI15e5d9f2025-06-12 17:11:46 +053028 requestBuffer = std::make_shared<InventoryRequestBuffer>();
29 responseBuffer = std::make_shared<InventoryResponseBuffer>();
30
31 std::string path = std::string(inventoryPrefix) + name;
32 acceleratorInterface =
33 objectServer.add_interface(path, acceleratorIfaceName);
34 assetIface = objectServer.add_interface(path, assetIfaceName);
35
36 // Static properties
Rohit PAId87bf7f2025-06-11 08:52:29 +053037 if (deviceType == DeviceType::GPU)
38 {
Rohit PAI15e5d9f2025-06-12 17:11:46 +053039 acceleratorInterface->register_property("Type", std::string("GPU"));
40 }
41 assetIface->register_property("Manufacturer", std::string("NVIDIA"));
42
43 // Register properties which need to be fetched from the device
44 registerProperty(gpu::InventoryPropertyId::SERIAL_NUMBER, assetIfaceName,
45 "SerialNumber");
46 registerProperty(gpu::InventoryPropertyId::BOARD_PART_NUMBER,
47 assetIfaceName, "PartNumber");
48
49 acceleratorInterface->initialize();
50 assetIface->initialize();
51 processNextProperty();
52}
53
54void Inventory::registerProperty(gpu::InventoryPropertyId propertyId,
55 const std::string& interfaceName,
56 const std::string& propertyName)
57{
58 std::shared_ptr<sdbusplus::asio::dbus_interface> interface;
59 if (interfaceName == assetIfaceName)
60 {
61 interface = assetIface;
62 }
63 else if (interfaceName == acceleratorIfaceName)
64 {
65 interface = acceleratorInterface;
66 }
67
68 if (interface)
69 {
70 interface->register_property(propertyName, std::string{});
71 properties[propertyId] = {interface, propertyName, 0, true};
72 }
73}
74
75void Inventory::fetchBoardPartNumber()
76{
77 fetchInventoryProperty(gpu::InventoryPropertyId::BOARD_PART_NUMBER);
78}
79
80void Inventory::fetchSerialNumber()
81{
82 fetchInventoryProperty(gpu::InventoryPropertyId::SERIAL_NUMBER);
83}
84
85void Inventory::fetchInventoryProperty(gpu::InventoryPropertyId propertyId)
86{
87 auto it = properties.find(propertyId);
88 if (it != properties.end())
89 {
90 markPropertyPending(propertyId);
91 std::optional<gpu::InventoryPropertyId> nextProperty =
92 getNextPendingProperty();
93 if (nextProperty && *nextProperty == propertyId)
Rohit PAId87bf7f2025-06-11 08:52:29 +053094 {
Rohit PAI15e5d9f2025-06-12 17:11:46 +053095 processNextProperty();
Rohit PAId87bf7f2025-06-11 08:52:29 +053096 }
Rohit PAI15e5d9f2025-06-12 17:11:46 +053097 }
98}
99
100void Inventory::markPropertyPending(gpu::InventoryPropertyId propertyId)
101{
102 auto it = properties.find(propertyId);
103 if (it != properties.end())
104 {
105 it->second.isPending = true;
106 it->second.retryCount = 0;
107 }
108}
109
110void Inventory::markPropertyProcessed(gpu::InventoryPropertyId propertyId)
111{
112 auto it = properties.find(propertyId);
113 if (it != properties.end())
114 {
115 it->second.isPending = false;
116 }
117}
118
119std::optional<gpu::InventoryPropertyId> Inventory::getNextPendingProperty()
120 const
121{
122 for (const auto& [propertyId, info] : properties)
123 {
124 if (info.isPending)
Rohit PAId87bf7f2025-06-11 08:52:29 +0530125 {
Rohit PAI15e5d9f2025-06-12 17:11:46 +0530126 return propertyId;
Rohit PAId87bf7f2025-06-11 08:52:29 +0530127 }
128 }
Rohit PAI15e5d9f2025-06-12 17:11:46 +0530129 return std::nullopt;
130}
131
132void Inventory::requestInventoryProperty(gpu::InventoryPropertyId propertyId)
133{
134 int rc = gpu::encodeGetInventoryInformationRequest(
135 0, static_cast<uint8_t>(propertyId), *requestBuffer);
136 if (rc != 0)
137 {
138 lg2::error("Failed to encode property ID {PROP_ID} request: rc={RC}",
139 "PROP_ID", static_cast<uint8_t>(propertyId), "RC", rc);
140 return;
141 }
142
143 lg2::info(
144 "Sending inventory request for property ID {PROP_ID} to EID {EID}",
145 "PROP_ID", static_cast<uint8_t>(propertyId), "EID", eid);
146
147 mctpRequester.sendRecvMsg(eid, *requestBuffer, *responseBuffer,
148 [this, propertyId](int sendRecvMsgResult) {
149 this->handleInventoryPropertyResponse(
150 propertyId, sendRecvMsgResult);
151 });
152}
153
154void Inventory::handleInventoryPropertyResponse(
155 gpu::InventoryPropertyId propertyId, int sendRecvMsgResult)
156{
157 bool success = false;
158 if (sendRecvMsgResult == 0)
159 {
160 ocp::accelerator_management::CompletionCode cc{};
161 uint16_t reasonCode = 0;
162 gpu::InventoryInfo info;
163 int rc = gpu::decodeGetInventoryInformationResponse(
164 *responseBuffer, cc, reasonCode, propertyId, info);
165
166 lg2::info(
167 "Response for property ID {PROP_ID}, sendRecvMsgResult: {RESULT}, decode_rc: {RC}, completion_code: {CC}, reason_code: {REASON}",
168 "PROP_ID", static_cast<uint8_t>(propertyId), "RESULT",
169 sendRecvMsgResult, "RC", rc, "CC", static_cast<uint8_t>(cc),
170 "REASON", reasonCode);
171
172 if (rc == 0 &&
173 cc == ocp::accelerator_management::CompletionCode::SUCCESS &&
174 std::holds_alternative<std::string>(info))
175 {
176 std::string value = std::get<std::string>(info);
177 auto it = properties.find(propertyId);
178 if (it != properties.end())
179 {
180 it->second.interface->set_property(it->second.propertyName,
181 value);
182 lg2::info(
183 "Successfully received property ID {PROP_ID} with value: {VALUE}",
184 "PROP_ID", static_cast<uint8_t>(propertyId), "VALUE",
185 value);
186 success = true;
187 }
188 }
189 }
190
191 if (!success)
192 {
193 auto it = properties.find(propertyId);
194 if (it != properties.end())
195 {
196 it->second.retryCount++;
197 if (it->second.retryCount >= maxRetryAttempts)
198 {
199 lg2::error(
200 "Property ID {PROP_ID} failed after {ATTEMPTS} attempts",
201 "PROP_ID", static_cast<uint8_t>(propertyId), "ATTEMPTS",
202 maxRetryAttempts);
203 markPropertyProcessed(propertyId);
204 }
205 else
206 {
207 retryTimer.expires_after(retryDelay);
208 retryTimer.async_wait(
209 [this](const boost::system::error_code& ec) {
210 if (ec)
211 {
212 lg2::error("Retry timer error: {ERROR}", "ERROR",
213 ec.message());
214 return;
215 }
216 this->processNextProperty();
217 });
218 return;
219 }
220 }
221 }
222 else
223 {
224 markPropertyProcessed(propertyId);
225 }
226
227 processNextProperty();
228}
229
230void Inventory::processNextProperty()
231{
232 std::optional<gpu::InventoryPropertyId> nextProperty =
233 getNextPendingProperty();
234 if (nextProperty)
235 {
236 requestInventoryProperty(*nextProperty);
237 }
238 else
239 {
240 lg2::info("No pending properties found to process");
241 }
242}
243
244void Inventory::update()
245{
246 fetchBoardPartNumber();
247 fetchSerialNumber();
248}
249
250std::optional<std::string_view> Inventory::dbusPropertyNameForId(
251 gpu::InventoryPropertyId propertyId)
252{
253 switch (propertyId)
254 {
255 case gpu::InventoryPropertyId::BOARD_PART_NUMBER:
256 return "PartNumber";
257 case gpu::InventoryPropertyId::SERIAL_NUMBER:
258 return "SerialNumber";
259 case gpu::InventoryPropertyId::MARKETING_NAME:
260 return "MarketingName";
261 case gpu::InventoryPropertyId::DEVICE_PART_NUMBER:
262 return "PartNumber";
263 // Add more as needed
264 default:
265 return std::nullopt;
266 }
Rohit PAId87bf7f2025-06-11 08:52:29 +0530267}