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