1 /*
2 * SPDX-FileCopyrightText: Copyright OpenBMC Authors
3 * 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 <cstddef>
14 #include <cstdint>
15 #include <cstring>
16 #include <span>
17 #include <string>
18 #include <vector>
19
20 namespace gpu
21 {
22 // These functions encode/decode data communicated over the network
23 // The use of reinterpret_cast enables direct memory access to raw byte buffers
24 // without doing unnecessary data copying
25 // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
packHeader(const ocp::accelerator_management::BindingPciVidInfo & hdr,ocp::accelerator_management::BindingPciVid & msg)26 int packHeader(const ocp::accelerator_management::BindingPciVidInfo& hdr,
27 ocp::accelerator_management::BindingPciVid& msg)
28 {
29 return ocp::accelerator_management::packHeader(nvidiaPciVendorId, hdr, msg);
30 }
31
encodeQueryDeviceIdentificationRequest(uint8_t instanceId,const std::span<uint8_t> buf)32 int encodeQueryDeviceIdentificationRequest(uint8_t instanceId,
33 const std::span<uint8_t> buf)
34 {
35 if (buf.size() < sizeof(QueryDeviceIdentificationRequest))
36 {
37 return EINVAL;
38 }
39
40 auto* msg = reinterpret_cast<QueryDeviceIdentificationRequest*>(buf.data());
41
42 ocp::accelerator_management::BindingPciVidInfo header{};
43
44 header.ocp_accelerator_management_msg_type =
45 static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
46 header.instance_id = instanceId &
47 ocp::accelerator_management::instanceIdBitMask;
48 header.msg_type =
49 static_cast<uint8_t>(MessageType::DEVICE_CAPABILITY_DISCOVERY);
50
51 auto rc = packHeader(header, msg->hdr.msgHdr.hdr);
52
53 if (rc != 0)
54 {
55 return rc;
56 }
57
58 msg->hdr.command = static_cast<uint8_t>(
59 DeviceCapabilityDiscoveryCommands::QUERY_DEVICE_IDENTIFICATION);
60 msg->hdr.data_size = 0;
61
62 return 0;
63 }
64
decodeQueryDeviceIdentificationResponse(const std::span<const uint8_t> buf,ocp::accelerator_management::CompletionCode & cc,uint16_t & reasonCode,uint8_t & deviceIdentification,uint8_t & deviceInstance)65 int decodeQueryDeviceIdentificationResponse(
66 const std::span<const uint8_t> buf,
67 ocp::accelerator_management::CompletionCode& cc, uint16_t& reasonCode,
68 uint8_t& deviceIdentification, uint8_t& deviceInstance)
69 {
70 auto rc =
71 ocp::accelerator_management::decodeReasonCodeAndCC(buf, cc, reasonCode);
72
73 if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
74 {
75 return rc;
76 }
77
78 if (buf.size() < sizeof(QueryDeviceIdentificationResponse))
79 {
80 return EINVAL;
81 }
82
83 const auto* response =
84 reinterpret_cast<const QueryDeviceIdentificationResponse*>(buf.data());
85
86 deviceIdentification = response->device_identification;
87 deviceInstance = response->instance_id;
88
89 return 0;
90 }
91
encodeGetTemperatureReadingRequest(uint8_t instanceId,uint8_t sensorId,std::span<uint8_t> buf)92 int encodeGetTemperatureReadingRequest(uint8_t instanceId, uint8_t sensorId,
93 std::span<uint8_t> buf)
94 {
95 if (buf.size() < sizeof(GetTemperatureReadingRequest))
96 {
97 return EINVAL;
98 }
99
100 auto* msg = reinterpret_cast<GetTemperatureReadingRequest*>(buf.data());
101
102 ocp::accelerator_management::BindingPciVidInfo header{};
103 header.ocp_accelerator_management_msg_type =
104 static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
105 header.instance_id = instanceId &
106 ocp::accelerator_management::instanceIdBitMask;
107 header.msg_type = static_cast<uint8_t>(MessageType::PLATFORM_ENVIRONMENTAL);
108
109 auto rc = packHeader(header, msg->hdr.msgHdr.hdr);
110
111 if (rc != 0)
112 {
113 return rc;
114 }
115
116 msg->hdr.command = static_cast<uint8_t>(
117 PlatformEnvironmentalCommands::GET_TEMPERATURE_READING);
118 msg->hdr.data_size = sizeof(sensorId);
119 msg->sensor_id = sensorId;
120
121 return 0;
122 }
123
decodeGetTemperatureReadingResponse(const std::span<const uint8_t> buf,ocp::accelerator_management::CompletionCode & cc,uint16_t & reasonCode,double & temperatureReading)124 int decodeGetTemperatureReadingResponse(
125 const std::span<const uint8_t> buf,
126 ocp::accelerator_management::CompletionCode& cc, uint16_t& reasonCode,
127 double& temperatureReading)
128 {
129 auto rc =
130 ocp::accelerator_management::decodeReasonCodeAndCC(buf, cc, reasonCode);
131
132 if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
133 {
134 return rc;
135 }
136
137 if (buf.size() < sizeof(GetTemperatureReadingResponse))
138 {
139 return EINVAL;
140 }
141
142 const auto* response =
143 reinterpret_cast<const GetTemperatureReadingResponse*>(buf.data());
144
145 uint16_t dataSize = le16toh(response->hdr.data_size);
146
147 if (dataSize != sizeof(int32_t))
148 {
149 return EINVAL;
150 }
151
152 int32_t reading = le32toh(response->reading);
153 temperatureReading = reading / static_cast<double>(1 << 8);
154
155 return 0;
156 }
157
encodeReadThermalParametersRequest(uint8_t instanceId,uint8_t sensorId,std::span<uint8_t> buf)158 int encodeReadThermalParametersRequest(uint8_t instanceId, uint8_t sensorId,
159 std::span<uint8_t> buf)
160 {
161 if (buf.size() < sizeof(ReadThermalParametersRequest))
162 {
163 return EINVAL;
164 }
165
166 auto* msg = reinterpret_cast<ReadThermalParametersRequest*>(buf.data());
167
168 ocp::accelerator_management::BindingPciVidInfo header{};
169 header.ocp_accelerator_management_msg_type =
170 static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
171 header.instance_id = instanceId &
172 ocp::accelerator_management::instanceIdBitMask;
173 header.msg_type = static_cast<uint8_t>(MessageType::PLATFORM_ENVIRONMENTAL);
174
175 auto rc = packHeader(header, msg->hdr.msgHdr.hdr);
176
177 if (rc != 0)
178 {
179 return rc;
180 }
181
182 msg->hdr.command = static_cast<uint8_t>(
183 PlatformEnvironmentalCommands::READ_THERMAL_PARAMETERS);
184 msg->hdr.data_size = sizeof(sensorId);
185 msg->sensor_id = sensorId;
186
187 return 0;
188 }
189
decodeReadThermalParametersResponse(std::span<const uint8_t> buf,ocp::accelerator_management::CompletionCode & cc,uint16_t & reasonCode,int32_t & threshold)190 int decodeReadThermalParametersResponse(
191 std::span<const uint8_t> buf,
192 ocp::accelerator_management::CompletionCode& cc, uint16_t& reasonCode,
193 int32_t& threshold)
194 {
195 auto rc =
196 ocp::accelerator_management::decodeReasonCodeAndCC(buf, cc, reasonCode);
197
198 if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
199 {
200 return rc;
201 }
202
203 if (buf.size() < sizeof(ReadThermalParametersResponse))
204 {
205 return EINVAL;
206 }
207
208 const auto* response =
209 reinterpret_cast<const ReadThermalParametersResponse*>(buf.data());
210
211 uint16_t dataSize = le16toh(response->hdr.data_size);
212
213 if (dataSize != sizeof(int32_t))
214 {
215 return EINVAL;
216 }
217
218 threshold = le32toh(response->threshold);
219
220 return 0;
221 }
222
encodeGetPowerDrawRequest(PlatformEnvironmentalCommands commandCode,uint8_t instanceId,uint8_t sensorId,uint8_t averagingInterval,std::span<uint8_t> buf)223 int encodeGetPowerDrawRequest(PlatformEnvironmentalCommands commandCode,
224 uint8_t instanceId, uint8_t sensorId,
225 uint8_t averagingInterval, std::span<uint8_t> buf)
226 {
227 if (buf.size() < sizeof(GetPowerDrawRequest))
228 {
229 return EINVAL;
230 }
231
232 auto* msg = reinterpret_cast<GetPowerDrawRequest*>(buf.data());
233
234 ocp::accelerator_management::BindingPciVidInfo header{};
235 header.ocp_accelerator_management_msg_type =
236 static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
237 header.instance_id = instanceId &
238 ocp::accelerator_management::instanceIdBitMask;
239 header.msg_type = static_cast<uint8_t>(MessageType::PLATFORM_ENVIRONMENTAL);
240
241 auto rc = packHeader(header, msg->hdr.msgHdr.hdr);
242
243 if (rc != 0)
244 {
245 return rc;
246 }
247
248 msg->hdr.command = static_cast<uint8_t>(commandCode);
249 msg->hdr.data_size = sizeof(sensorId) + sizeof(averagingInterval);
250 msg->sensorId = sensorId;
251 msg->averagingInterval = averagingInterval;
252
253 return 0;
254 }
255
decodeGetPowerDrawResponse(std::span<const uint8_t> buf,ocp::accelerator_management::CompletionCode & cc,uint16_t & reasonCode,uint32_t & power)256 int decodeGetPowerDrawResponse(std::span<const uint8_t> buf,
257 ocp::accelerator_management::CompletionCode& cc,
258 uint16_t& reasonCode, uint32_t& power)
259 {
260 auto rc =
261 ocp::accelerator_management::decodeReasonCodeAndCC(buf, cc, reasonCode);
262
263 if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
264 {
265 return rc;
266 }
267
268 if (buf.size() < sizeof(GetPowerDrawResponse))
269 {
270 return EINVAL;
271 }
272
273 const auto* response =
274 reinterpret_cast<const GetPowerDrawResponse*>(buf.data());
275
276 const uint16_t dataSize = le16toh(response->hdr.data_size);
277
278 if (dataSize != sizeof(uint32_t))
279 {
280 return EINVAL;
281 }
282
283 power = le32toh(response->power);
284
285 return 0;
286 }
287
encodeGetCurrentEnergyCounterRequest(uint8_t instanceId,uint8_t sensorId,std::span<uint8_t> buf)288 int encodeGetCurrentEnergyCounterRequest(uint8_t instanceId, uint8_t sensorId,
289 std::span<uint8_t> buf)
290 {
291 if (buf.size() < sizeof(GetTemperatureReadingRequest))
292 {
293 return EINVAL;
294 }
295
296 auto* msg = reinterpret_cast<GetCurrentEnergyCounterRequest*>(buf.data());
297
298 ocp::accelerator_management::BindingPciVidInfo header{};
299 header.ocp_accelerator_management_msg_type =
300 static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
301 header.instance_id = instanceId &
302 ocp::accelerator_management::instanceIdBitMask;
303 header.msg_type = static_cast<uint8_t>(MessageType::PLATFORM_ENVIRONMENTAL);
304
305 auto rc = packHeader(header, msg->hdr.msgHdr.hdr);
306
307 if (rc != 0)
308 {
309 return rc;
310 }
311
312 msg->hdr.command = static_cast<uint8_t>(
313 PlatformEnvironmentalCommands::GET_CURRENT_ENERGY_COUNTER);
314 msg->hdr.data_size = sizeof(sensorId);
315 msg->sensor_id = sensorId;
316
317 return 0;
318 }
319
decodeGetCurrentEnergyCounterResponse(std::span<const uint8_t> buf,ocp::accelerator_management::CompletionCode & cc,uint16_t & reasonCode,uint64_t & energy)320 int decodeGetCurrentEnergyCounterResponse(
321 std::span<const uint8_t> buf,
322 ocp::accelerator_management::CompletionCode& cc, uint16_t& reasonCode,
323 uint64_t& energy)
324 {
325 auto rc =
326 ocp::accelerator_management::decodeReasonCodeAndCC(buf, cc, reasonCode);
327
328 if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
329 {
330 return rc;
331 }
332
333 if (buf.size() < sizeof(GetPowerDrawResponse))
334 {
335 return EINVAL;
336 }
337
338 const auto* response =
339 reinterpret_cast<const GetCurrentEnergyCounterResponse*>(buf.data());
340
341 const uint16_t dataSize = le16toh(response->hdr.data_size);
342
343 if (dataSize != sizeof(uint64_t))
344 {
345 return EINVAL;
346 }
347
348 energy = le32toh(response->energy);
349
350 return 0;
351 }
352
encodeGetVoltageRequest(uint8_t instanceId,uint8_t sensorId,std::span<uint8_t> buf)353 int encodeGetVoltageRequest(uint8_t instanceId, uint8_t sensorId,
354 std::span<uint8_t> buf)
355 {
356 if (buf.size() < sizeof(GetVoltageRequest))
357 {
358 return EINVAL;
359 }
360
361 auto* msg = reinterpret_cast<GetVoltageRequest*>(buf.data());
362
363 ocp::accelerator_management::BindingPciVidInfo header{};
364 header.ocp_accelerator_management_msg_type =
365 static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
366 header.instance_id = instanceId &
367 ocp::accelerator_management::instanceIdBitMask;
368 header.msg_type = static_cast<uint8_t>(MessageType::PLATFORM_ENVIRONMENTAL);
369
370 auto rc = packHeader(header, msg->hdr.msgHdr.hdr);
371
372 if (rc != 0)
373 {
374 return rc;
375 }
376
377 msg->hdr.command =
378 static_cast<uint8_t>(PlatformEnvironmentalCommands::GET_VOLTAGE);
379 msg->hdr.data_size = sizeof(sensorId);
380 msg->sensor_id = sensorId;
381
382 return 0;
383 }
384
decodeGetVoltageResponse(std::span<const uint8_t> buf,ocp::accelerator_management::CompletionCode & cc,uint16_t & reasonCode,uint32_t & voltage)385 int decodeGetVoltageResponse(std::span<const uint8_t> buf,
386 ocp::accelerator_management::CompletionCode& cc,
387 uint16_t& reasonCode, uint32_t& voltage)
388 {
389 auto rc =
390 ocp::accelerator_management::decodeReasonCodeAndCC(buf, cc, reasonCode);
391
392 if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
393 {
394 return rc;
395 }
396
397 if (buf.size() < sizeof(GetVoltageResponse))
398 {
399 return EINVAL;
400 }
401
402 const auto* response =
403 reinterpret_cast<const GetVoltageResponse*>(buf.data());
404
405 const uint16_t dataSize = le16toh(response->hdr.data_size);
406
407 if (dataSize != sizeof(uint32_t))
408 {
409 return EINVAL;
410 }
411
412 voltage = le32toh(response->voltage);
413
414 return 0;
415 }
416
encodeGetDriverInformationRequest(uint8_t instanceId,std::span<uint8_t> buf)417 int encodeGetDriverInformationRequest(uint8_t instanceId,
418 std::span<uint8_t> buf)
419 {
420 if (buf.size() < sizeof(ocp::accelerator_management::CommonRequest))
421 {
422 return EINVAL;
423 }
424
425 auto* msg = reinterpret_cast<ocp::accelerator_management::CommonRequest*>(
426 buf.data());
427
428 ocp::accelerator_management::BindingPciVidInfo header{};
429 header.ocp_accelerator_management_msg_type =
430 static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
431 header.instance_id = instanceId &
432 ocp::accelerator_management::instanceIdBitMask;
433 header.msg_type = static_cast<uint8_t>(MessageType::PLATFORM_ENVIRONMENTAL);
434
435 auto rc = packHeader(header, msg->msgHdr.hdr);
436
437 if (rc != 0)
438 {
439 return rc;
440 }
441
442 msg->command = static_cast<uint8_t>(
443 PlatformEnvironmentalCommands::GET_DRIVER_INFORMATION);
444 msg->data_size = 0;
445
446 return 0;
447 }
448
decodeGetDriverInformationResponse(std::span<const uint8_t> buf,ocp::accelerator_management::CompletionCode & cc,uint16_t & reasonCode,DriverState & driverState,std::string & driverVersion)449 int decodeGetDriverInformationResponse(
450 std::span<const uint8_t> buf,
451 ocp::accelerator_management::CompletionCode& cc, uint16_t& reasonCode,
452 DriverState& driverState, std::string& driverVersion)
453 {
454 auto rc =
455 ocp::accelerator_management::decodeReasonCodeAndCC(buf, cc, reasonCode);
456
457 if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
458 {
459 return rc;
460 }
461
462 if (buf.size() < sizeof(GetDriverInformationResponse))
463 {
464 return EINVAL;
465 }
466
467 const auto* response =
468 reinterpret_cast<const GetDriverInformationResponse*>(buf.data());
469
470 const uint16_t dataSize = le16toh(response->hdr.data_size);
471
472 if (dataSize < sizeof(DriverState) + sizeof(char))
473 {
474 return EINVAL;
475 }
476
477 driverState = response->driverState;
478 const size_t versionSize =
479 buf.size() - sizeof(GetDriverInformationResponse);
480 driverVersion = std::string(&response->driverVersion, versionSize);
481
482 return 0;
483 }
484
encodeGetInventoryInformationRequest(uint8_t instanceId,uint8_t propertyId,std::span<uint8_t> buf)485 int encodeGetInventoryInformationRequest(uint8_t instanceId, uint8_t propertyId,
486 std::span<uint8_t> buf)
487 {
488 if (buf.size() < sizeof(GetInventoryInformationRequest))
489 {
490 return EINVAL;
491 }
492
493 auto* msg = reinterpret_cast<GetInventoryInformationRequest*>(buf.data());
494
495 ocp::accelerator_management::BindingPciVidInfo header{};
496 header.ocp_accelerator_management_msg_type =
497 static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
498 header.instance_id = instanceId &
499 ocp::accelerator_management::instanceIdBitMask;
500 header.msg_type = static_cast<uint8_t>(MessageType::PLATFORM_ENVIRONMENTAL);
501
502 auto rc = packHeader(header, msg->hdr.msgHdr.hdr);
503
504 if (rc != 0)
505 {
506 return rc;
507 }
508
509 msg->hdr.command = static_cast<uint8_t>(
510 PlatformEnvironmentalCommands::GET_INVENTORY_INFORMATION);
511 msg->hdr.data_size = sizeof(propertyId);
512 msg->property_id = propertyId;
513
514 return 0;
515 }
516
decodeGetInventoryInformationResponse(std::span<const uint8_t> buf,ocp::accelerator_management::CompletionCode & cc,uint16_t & reasonCode,InventoryPropertyId propertyId,InventoryValue & value)517 int decodeGetInventoryInformationResponse(
518 std::span<const uint8_t> buf,
519 ocp::accelerator_management::CompletionCode& cc, uint16_t& reasonCode,
520 InventoryPropertyId propertyId, InventoryValue& value)
521 {
522 auto rc =
523 ocp::accelerator_management::decodeReasonCodeAndCC(buf, cc, reasonCode);
524 if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
525 {
526 return rc;
527 }
528 // Expect at least one byte of inventory response data after common response
529 if (buf.size() < (sizeof(ocp::accelerator_management::CommonResponse) + 1))
530 {
531 return EINVAL;
532 }
533
534 const auto* response =
535 reinterpret_cast<const GetInventoryInformationResponse*>(buf.data());
536 uint16_t dataSize = le16toh(response->hdr.data_size);
537
538 if (dataSize == 0 || dataSize > maxInventoryDataSize)
539 {
540 return EINVAL;
541 }
542
543 const uint8_t* dataPtr = response->data.data();
544
545 switch (propertyId)
546 {
547 case InventoryPropertyId::BOARD_PART_NUMBER:
548 case InventoryPropertyId::SERIAL_NUMBER:
549 case InventoryPropertyId::MARKETING_NAME:
550 case InventoryPropertyId::DEVICE_PART_NUMBER:
551 value =
552 std::string(reinterpret_cast<const char*>(dataPtr), dataSize);
553 break;
554 case InventoryPropertyId::DEVICE_GUID:
555 value = std::vector<uint8_t>(dataPtr, dataPtr + dataSize);
556 break;
557 default:
558 return EINVAL;
559 }
560 return 0;
561 }
562
encodeQueryScalarGroupTelemetryV2Request(uint8_t instanceId,PciePortType portType,uint8_t upstreamPortNumber,uint8_t portNumber,uint8_t groupId,std::span<uint8_t> buf)563 int encodeQueryScalarGroupTelemetryV2Request(
564 uint8_t instanceId, PciePortType portType, uint8_t upstreamPortNumber,
565 uint8_t portNumber, uint8_t groupId, std::span<uint8_t> buf)
566 {
567 if (buf.size() < sizeof(QueryScalarGroupTelemetryV2Request))
568 {
569 return EINVAL;
570 }
571
572 auto* msg =
573 reinterpret_cast<QueryScalarGroupTelemetryV2Request*>(buf.data());
574
575 ocp::accelerator_management::BindingPciVidInfo header{};
576 header.ocp_accelerator_management_msg_type =
577 static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
578 header.instance_id = instanceId &
579 ocp::accelerator_management::instanceIdBitMask;
580 header.msg_type = static_cast<uint8_t>(MessageType::PCIE_LINK);
581
582 auto rc = packHeader(header, msg->hdr.msgHdr.hdr);
583
584 if (rc != 0)
585 {
586 return rc;
587 }
588
589 msg->hdr.command =
590 static_cast<uint8_t>(PcieLinkCommands::QueryScalarGroupTelemetryV2);
591 msg->hdr.data_size = 3;
592 msg->upstreamPortNumber =
593 (static_cast<uint8_t>(portType) << 7) | (upstreamPortNumber & 0x7F);
594 msg->portNumber = portNumber;
595 msg->groupId = groupId;
596
597 return 0;
598 }
599
decodeQueryScalarGroupTelemetryV2Response(std::span<const uint8_t> buf,ocp::accelerator_management::CompletionCode & cc,uint16_t & reasonCode,size_t & numTelemetryValues,std::vector<uint32_t> & telemetryValues)600 int decodeQueryScalarGroupTelemetryV2Response(
601 std::span<const uint8_t> buf,
602 ocp::accelerator_management::CompletionCode& cc, uint16_t& reasonCode,
603 size_t& numTelemetryValues, std::vector<uint32_t>& telemetryValues)
604 {
605 auto rc =
606 ocp::accelerator_management::decodeReasonCodeAndCC(buf, cc, reasonCode);
607
608 if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
609 {
610 return rc;
611 }
612
613 if (buf.size() < sizeof(ocp::accelerator_management::CommonResponse))
614 {
615 return EINVAL;
616 }
617
618 const auto* response =
619 reinterpret_cast<const ocp::accelerator_management::CommonResponse*>(
620 buf.data());
621
622 const uint16_t dataSize = le16toh(response->data_size);
623
624 if (buf.size() <
625 dataSize + sizeof(ocp::accelerator_management::CommonResponse))
626 {
627 return EINVAL;
628 }
629
630 numTelemetryValues = dataSize / sizeof(uint32_t);
631
632 if (telemetryValues.size() < numTelemetryValues)
633 {
634 telemetryValues.resize(numTelemetryValues);
635 }
636
637 const auto* telemetryDataPtr =
638 buf.data() + sizeof(ocp::accelerator_management::CommonResponse);
639
640 for (size_t i = 0; i < numTelemetryValues; i++)
641 {
642 std::memcpy(&telemetryValues[i],
643 telemetryDataPtr + i * sizeof(uint32_t), sizeof(uint32_t));
644
645 telemetryValues[i] = le32toh(telemetryValues[i]);
646 }
647
648 return 0;
649 }
650
encodeListPciePortsRequest(uint8_t instanceId,std::span<uint8_t> buf)651 int encodeListPciePortsRequest(uint8_t instanceId, std::span<uint8_t> buf)
652 {
653 if (buf.size() < sizeof(ocp::accelerator_management::CommonRequest))
654 {
655 return EINVAL;
656 }
657
658 auto* msg = reinterpret_cast<ocp::accelerator_management::CommonRequest*>(
659 buf.data());
660
661 ocp::accelerator_management::BindingPciVidInfo header{};
662 header.ocp_accelerator_management_msg_type =
663 static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
664 header.instance_id = instanceId &
665 ocp::accelerator_management::instanceIdBitMask;
666 header.msg_type = static_cast<uint8_t>(MessageType::PCIE_LINK);
667
668 auto rc = packHeader(header, msg->msgHdr.hdr);
669
670 if (rc != 0)
671 {
672 return rc;
673 }
674
675 msg->command = static_cast<uint8_t>(PcieLinkCommands::ListPCIePorts);
676 msg->data_size = 0;
677
678 return 0;
679 }
680
decodeListPciePortsResponse(std::span<const uint8_t> buf,ocp::accelerator_management::CompletionCode & cc,uint16_t & reasonCode,uint16_t & numUpstreamPorts,std::vector<uint8_t> & numDownstreamPorts)681 int decodeListPciePortsResponse(
682 std::span<const uint8_t> buf,
683 ocp::accelerator_management::CompletionCode& cc, uint16_t& reasonCode,
684 uint16_t& numUpstreamPorts, std::vector<uint8_t>& numDownstreamPorts)
685 {
686 auto rc =
687 ocp::accelerator_management::decodeReasonCodeAndCC(buf, cc, reasonCode);
688
689 if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
690 {
691 return rc;
692 }
693
694 if (buf.size() < sizeof(ListPCIePortsResponse))
695 {
696 return EINVAL;
697 }
698
699 const auto* response =
700 reinterpret_cast<const ListPCIePortsResponse*>(buf.data());
701
702 const uint16_t dataSize = le16toh(response->hdr.data_size);
703
704 if (dataSize < sizeof(uint16_t))
705 {
706 return EINVAL;
707 }
708
709 uint16_t upstreamPorts = le16toh(response->numUpstreamPorts);
710
711 numUpstreamPorts = 0;
712 numDownstreamPorts.clear();
713 numDownstreamPorts.reserve(upstreamPorts);
714
715 size_t offset = sizeof(ListPCIePortsResponse);
716
717 for (size_t i = 0; i < upstreamPorts; i++)
718 {
719 if (offset + sizeof(ListPCIePortsDownstreamPortsData) > buf.size())
720 {
721 return EINVAL;
722 }
723
724 const auto* downstreamPortData =
725 reinterpret_cast<const ListPCIePortsDownstreamPortsData*>(
726 buf.data() + offset);
727
728 // Count only external upstream ports
729 if (downstreamPortData->isInternal == 0)
730 {
731 ++numUpstreamPorts;
732 numDownstreamPorts.push_back(downstreamPortData->count);
733 }
734
735 offset += sizeof(ListPCIePortsDownstreamPortsData);
736 }
737
738 return 0;
739 }
740 // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
741 } // namespace gpu
742