blob: 4af306ee9466be58186b93db5b8b3be7f55a9174 [file] [log] [blame]
Harshit Aghera560e6af2025-04-21 20:04:56 +05301/*
Ed Tanousb5e823f2025-10-09 20:28:42 -04002 * SPDX-FileCopyrightText: Copyright OpenBMC Authors
Harshit Aghera560e6af2025-04-21 20:04:56 +05303 * SPDX-License-Identifier: Apache-2.0
4 */
5
6#include "NvidiaGpuMctpVdm.hpp"
7
8#include "OcpMctpVdm.hpp"
9
10#include <endian.h>
11
12#include <cerrno>
13#include <cstdint>
Harshit Aghera560e6af2025-04-21 20:04:56 +053014#include <span>
Rohit PAI86786b62025-06-10 09:46:33 +053015#include <vector>
Harshit Aghera560e6af2025-04-21 20:04:56 +053016
17namespace gpu
18{
19// These functions encode/decode data communicated over the network
20// The use of reinterpret_cast enables direct memory access to raw byte buffers
21// without doing unnecessary data copying
22// NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
23int packHeader(const ocp::accelerator_management::BindingPciVidInfo& hdr,
24 ocp::accelerator_management::BindingPciVid& msg)
25{
26 return ocp::accelerator_management::packHeader(nvidiaPciVendorId, hdr, msg);
27}
28
29int encodeQueryDeviceIdentificationRequest(uint8_t instanceId,
30 const std::span<uint8_t> buf)
31{
32 if (buf.size() < sizeof(QueryDeviceIdentificationRequest))
33 {
34 return EINVAL;
35 }
36
37 auto* msg = reinterpret_cast<QueryDeviceIdentificationRequest*>(buf.data());
38
39 ocp::accelerator_management::BindingPciVidInfo header{};
40
41 header.ocp_accelerator_management_msg_type =
42 static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
43 header.instance_id = instanceId &
44 ocp::accelerator_management::instanceIdBitMask;
45 header.msg_type =
46 static_cast<uint8_t>(MessageType::DEVICE_CAPABILITY_DISCOVERY);
47
48 auto rc = packHeader(header, msg->hdr.msgHdr.hdr);
49
50 if (rc != 0)
51 {
52 return rc;
53 }
54
55 msg->hdr.command = static_cast<uint8_t>(
56 DeviceCapabilityDiscoveryCommands::QUERY_DEVICE_IDENTIFICATION);
57 msg->hdr.data_size = 0;
58
59 return 0;
60}
61
62int decodeQueryDeviceIdentificationResponse(
63 const std::span<const uint8_t> buf,
64 ocp::accelerator_management::CompletionCode& cc, uint16_t& reasonCode,
65 uint8_t& deviceIdentification, uint8_t& deviceInstance)
66{
67 auto rc =
68 ocp::accelerator_management::decodeReasonCodeAndCC(buf, cc, reasonCode);
69
70 if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
71 {
72 return rc;
73 }
74
75 if (buf.size() < sizeof(QueryDeviceIdentificationResponse))
76 {
77 return EINVAL;
78 }
79
80 const auto* response =
81 reinterpret_cast<const QueryDeviceIdentificationResponse*>(buf.data());
82
83 deviceIdentification = response->device_identification;
84 deviceInstance = response->instance_id;
85
86 return 0;
87}
88
89int encodeGetTemperatureReadingRequest(uint8_t instanceId, uint8_t sensorId,
90 std::span<uint8_t> buf)
91{
92 if (buf.size() < sizeof(GetTemperatureReadingRequest))
93 {
94 return EINVAL;
95 }
96
97 auto* msg = reinterpret_cast<GetTemperatureReadingRequest*>(buf.data());
98
99 ocp::accelerator_management::BindingPciVidInfo header{};
100 header.ocp_accelerator_management_msg_type =
101 static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
102 header.instance_id = instanceId &
103 ocp::accelerator_management::instanceIdBitMask;
104 header.msg_type = static_cast<uint8_t>(MessageType::PLATFORM_ENVIRONMENTAL);
105
106 auto rc = packHeader(header, msg->hdr.msgHdr.hdr);
107
108 if (rc != 0)
109 {
110 return rc;
111 }
112
113 msg->hdr.command = static_cast<uint8_t>(
114 PlatformEnvironmentalCommands::GET_TEMPERATURE_READING);
115 msg->hdr.data_size = sizeof(sensorId);
116 msg->sensor_id = sensorId;
117
118 return 0;
119}
120
121int decodeGetTemperatureReadingResponse(
122 const std::span<const uint8_t> buf,
123 ocp::accelerator_management::CompletionCode& cc, uint16_t& reasonCode,
124 double& temperatureReading)
125{
126 auto rc =
127 ocp::accelerator_management::decodeReasonCodeAndCC(buf, cc, reasonCode);
128
129 if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
130 {
131 return rc;
132 }
133
134 if (buf.size() < sizeof(GetTemperatureReadingResponse))
135 {
136 return EINVAL;
137 }
138
139 const auto* response =
140 reinterpret_cast<const GetTemperatureReadingResponse*>(buf.data());
141
142 uint16_t dataSize = le16toh(response->hdr.data_size);
143
144 if (dataSize != sizeof(int32_t))
145 {
146 return EINVAL;
147 }
148
149 int32_t reading = le32toh(response->reading);
150 temperatureReading = reading / static_cast<double>(1 << 8);
151
152 return 0;
153}
Harshit Aghera5e7decc2025-05-07 16:20:16 +0530154
155int encodeReadThermalParametersRequest(uint8_t instanceId, uint8_t sensorId,
156 std::span<uint8_t> buf)
157{
158 if (buf.size() < sizeof(ReadThermalParametersRequest))
159 {
160 return EINVAL;
161 }
162
163 auto* msg = reinterpret_cast<ReadThermalParametersRequest*>(buf.data());
164
165 ocp::accelerator_management::BindingPciVidInfo header{};
166 header.ocp_accelerator_management_msg_type =
167 static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
168 header.instance_id = instanceId &
169 ocp::accelerator_management::instanceIdBitMask;
170 header.msg_type = static_cast<uint8_t>(MessageType::PLATFORM_ENVIRONMENTAL);
171
172 auto rc = packHeader(header, msg->hdr.msgHdr.hdr);
173
174 if (rc != 0)
175 {
176 return rc;
177 }
178
179 msg->hdr.command = static_cast<uint8_t>(
180 PlatformEnvironmentalCommands::READ_THERMAL_PARAMETERS);
181 msg->hdr.data_size = sizeof(sensorId);
182 msg->sensor_id = sensorId;
183
184 return 0;
185}
186
187int decodeReadThermalParametersResponse(
188 std::span<const uint8_t> buf,
189 ocp::accelerator_management::CompletionCode& cc, uint16_t& reasonCode,
190 int32_t& threshold)
191{
192 auto rc =
193 ocp::accelerator_management::decodeReasonCodeAndCC(buf, cc, reasonCode);
194
195 if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
196 {
197 return rc;
198 }
199
200 if (buf.size() < sizeof(ReadThermalParametersResponse))
201 {
202 return EINVAL;
203 }
204
205 const auto* response =
206 reinterpret_cast<const ReadThermalParametersResponse*>(buf.data());
207
208 uint16_t dataSize = le16toh(response->hdr.data_size);
209
210 if (dataSize != sizeof(int32_t))
211 {
212 return EINVAL;
213 }
214
215 threshold = le32toh(response->threshold);
216
217 return 0;
218}
Harshit Aghera902c6492025-05-08 15:57:42 +0530219
Harshit Aghera6b712322025-07-31 19:25:12 +0530220int encodeGetPowerDrawRequest(PlatformEnvironmentalCommands commandCode,
221 uint8_t instanceId, uint8_t sensorId,
222 uint8_t averagingInterval, std::span<uint8_t> buf)
Harshit Aghera902c6492025-05-08 15:57:42 +0530223{
Harshit Aghera6b712322025-07-31 19:25:12 +0530224 if (buf.size() < sizeof(GetPowerDrawRequest))
Harshit Aghera902c6492025-05-08 15:57:42 +0530225 {
226 return EINVAL;
227 }
228
Harshit Aghera6b712322025-07-31 19:25:12 +0530229 auto* msg = reinterpret_cast<GetPowerDrawRequest*>(buf.data());
Harshit Aghera902c6492025-05-08 15:57:42 +0530230
231 ocp::accelerator_management::BindingPciVidInfo header{};
232 header.ocp_accelerator_management_msg_type =
233 static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
234 header.instance_id = instanceId &
235 ocp::accelerator_management::instanceIdBitMask;
236 header.msg_type = static_cast<uint8_t>(MessageType::PLATFORM_ENVIRONMENTAL);
237
238 auto rc = packHeader(header, msg->hdr.msgHdr.hdr);
239
240 if (rc != 0)
241 {
242 return rc;
243 }
244
Harshit Aghera6b712322025-07-31 19:25:12 +0530245 msg->hdr.command = static_cast<uint8_t>(commandCode);
Harshit Aghera902c6492025-05-08 15:57:42 +0530246 msg->hdr.data_size = sizeof(sensorId) + sizeof(averagingInterval);
247 msg->sensorId = sensorId;
248 msg->averagingInterval = averagingInterval;
249
250 return 0;
251}
252
Harshit Aghera6b712322025-07-31 19:25:12 +0530253int decodeGetPowerDrawResponse(std::span<const uint8_t> buf,
254 ocp::accelerator_management::CompletionCode& cc,
255 uint16_t& reasonCode, uint32_t& power)
Harshit Aghera902c6492025-05-08 15:57:42 +0530256{
257 auto rc =
258 ocp::accelerator_management::decodeReasonCodeAndCC(buf, cc, reasonCode);
259
260 if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
261 {
262 return rc;
263 }
264
Harshit Aghera6b712322025-07-31 19:25:12 +0530265 if (buf.size() < sizeof(GetPowerDrawResponse))
Harshit Aghera902c6492025-05-08 15:57:42 +0530266 {
267 return EINVAL;
268 }
269
270 const auto* response =
Harshit Aghera6b712322025-07-31 19:25:12 +0530271 reinterpret_cast<const GetPowerDrawResponse*>(buf.data());
Harshit Aghera902c6492025-05-08 15:57:42 +0530272
273 const uint16_t dataSize = le16toh(response->hdr.data_size);
274
275 if (dataSize != sizeof(uint32_t))
276 {
277 return EINVAL;
278 }
279
280 power = le32toh(response->power);
281
282 return 0;
283}
Harshit Aghera775199d2025-05-27 14:20:24 +0530284
285int encodeGetCurrentEnergyCounterRequest(uint8_t instanceId, uint8_t sensorId,
286 std::span<uint8_t> buf)
287{
288 if (buf.size() < sizeof(GetTemperatureReadingRequest))
289 {
290 return EINVAL;
291 }
292
293 auto* msg = reinterpret_cast<GetCurrentEnergyCounterRequest*>(buf.data());
294
295 ocp::accelerator_management::BindingPciVidInfo header{};
296 header.ocp_accelerator_management_msg_type =
297 static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
298 header.instance_id = instanceId &
299 ocp::accelerator_management::instanceIdBitMask;
300 header.msg_type = static_cast<uint8_t>(MessageType::PLATFORM_ENVIRONMENTAL);
301
302 auto rc = packHeader(header, msg->hdr.msgHdr.hdr);
303
304 if (rc != 0)
305 {
306 return rc;
307 }
308
309 msg->hdr.command = static_cast<uint8_t>(
310 PlatformEnvironmentalCommands::GET_CURRENT_ENERGY_COUNTER);
311 msg->hdr.data_size = sizeof(sensorId);
312 msg->sensor_id = sensorId;
313
314 return 0;
315}
316
317int decodeGetCurrentEnergyCounterResponse(
318 std::span<const uint8_t> buf,
319 ocp::accelerator_management::CompletionCode& cc, uint16_t& reasonCode,
320 uint64_t& energy)
321{
322 auto rc =
323 ocp::accelerator_management::decodeReasonCodeAndCC(buf, cc, reasonCode);
324
325 if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
326 {
327 return rc;
328 }
329
Harshit Aghera6b712322025-07-31 19:25:12 +0530330 if (buf.size() < sizeof(GetPowerDrawResponse))
Harshit Aghera775199d2025-05-27 14:20:24 +0530331 {
332 return EINVAL;
333 }
334
335 const auto* response =
336 reinterpret_cast<const GetCurrentEnergyCounterResponse*>(buf.data());
337
338 const uint16_t dataSize = le16toh(response->hdr.data_size);
339
340 if (dataSize != sizeof(uint64_t))
341 {
342 return EINVAL;
343 }
344
345 energy = le32toh(response->energy);
346
347 return 0;
348}
Harshit Agherabef4d412025-05-27 14:53:56 +0530349
350int encodeGetVoltageRequest(uint8_t instanceId, uint8_t sensorId,
351 std::span<uint8_t> buf)
352{
353 if (buf.size() < sizeof(GetVoltageRequest))
354 {
355 return EINVAL;
356 }
357
358 auto* msg = reinterpret_cast<GetVoltageRequest*>(buf.data());
359
360 ocp::accelerator_management::BindingPciVidInfo header{};
361 header.ocp_accelerator_management_msg_type =
362 static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
363 header.instance_id = instanceId &
364 ocp::accelerator_management::instanceIdBitMask;
365 header.msg_type = static_cast<uint8_t>(MessageType::PLATFORM_ENVIRONMENTAL);
366
367 auto rc = packHeader(header, msg->hdr.msgHdr.hdr);
368
369 if (rc != 0)
370 {
371 return rc;
372 }
373
374 msg->hdr.command =
375 static_cast<uint8_t>(PlatformEnvironmentalCommands::GET_VOLTAGE);
376 msg->hdr.data_size = sizeof(sensorId);
377 msg->sensor_id = sensorId;
378
379 return 0;
380}
381
382int decodeGetVoltageResponse(std::span<const uint8_t> buf,
383 ocp::accelerator_management::CompletionCode& cc,
384 uint16_t& reasonCode, uint32_t& voltage)
385{
386 auto rc =
387 ocp::accelerator_management::decodeReasonCodeAndCC(buf, cc, reasonCode);
388
389 if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
390 {
391 return rc;
392 }
393
394 if (buf.size() < sizeof(GetVoltageResponse))
395 {
396 return EINVAL;
397 }
398
399 const auto* response =
400 reinterpret_cast<const GetVoltageResponse*>(buf.data());
401
402 const uint16_t dataSize = le16toh(response->hdr.data_size);
403
404 if (dataSize != sizeof(uint32_t))
405 {
406 return EINVAL;
407 }
408
409 voltage = le32toh(response->voltage);
410
411 return 0;
412}
Rohit PAI86786b62025-06-10 09:46:33 +0530413
414int encodeGetInventoryInformationRequest(uint8_t instanceId, uint8_t propertyId,
415 std::span<uint8_t> buf)
416{
417 if (buf.size() < sizeof(GetInventoryInformationRequest))
418 {
419 return EINVAL;
420 }
421
422 auto* msg = reinterpret_cast<GetInventoryInformationRequest*>(buf.data());
423
424 ocp::accelerator_management::BindingPciVidInfo header{};
425 header.ocp_accelerator_management_msg_type =
426 static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
427 header.instance_id = instanceId &
428 ocp::accelerator_management::instanceIdBitMask;
429 header.msg_type = static_cast<uint8_t>(MessageType::PLATFORM_ENVIRONMENTAL);
430
431 auto rc = packHeader(header, msg->hdr.msgHdr.hdr);
432
433 if (rc != 0)
434 {
435 return rc;
436 }
437
438 msg->hdr.command = static_cast<uint8_t>(
439 PlatformEnvironmentalCommands::GET_INVENTORY_INFORMATION);
440 msg->hdr.data_size = sizeof(propertyId);
441 msg->property_id = propertyId;
442
443 return 0;
444}
445
446int decodeGetInventoryInformationResponse(
447 std::span<const uint8_t> buf,
448 ocp::accelerator_management::CompletionCode& cc, uint16_t& reasonCode,
449 InventoryPropertyId propertyId, InventoryValue& value)
450{
451 auto rc =
452 ocp::accelerator_management::decodeReasonCodeAndCC(buf, cc, reasonCode);
453 if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
454 {
455 return rc;
456 }
457 // Expect at least one byte of inventory response data after common response
458 if (buf.size() < (sizeof(ocp::accelerator_management::CommonResponse) + 1))
459 {
460 return EINVAL;
461 }
462
463 const auto* response =
464 reinterpret_cast<const GetInventoryInformationResponse*>(buf.data());
465 uint16_t dataSize = le16toh(response->hdr.data_size);
466
467 if (dataSize == 0 || dataSize > maxInventoryDataSize)
468 {
469 return EINVAL;
470 }
471
472 const uint8_t* dataPtr = response->data.data();
473
474 switch (propertyId)
475 {
476 case InventoryPropertyId::BOARD_PART_NUMBER:
477 case InventoryPropertyId::SERIAL_NUMBER:
478 case InventoryPropertyId::MARKETING_NAME:
479 case InventoryPropertyId::DEVICE_PART_NUMBER:
480 value =
481 std::string(reinterpret_cast<const char*>(dataPtr), dataSize);
482 break;
483 case InventoryPropertyId::DEVICE_GUID:
484 value = std::vector<uint8_t>(dataPtr, dataPtr + dataSize);
485 break;
486 default:
487 return EINVAL;
488 }
489 return 0;
490}
491
Harshit Aghera560e6af2025-04-21 20:04:56 +0530492// NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
493} // namespace gpu