xref: /openbmc/dbus-sensors/src/nvidia-gpu/NvidiaGpuMctpVdm.cpp (revision 7427aeef4225bf23715539b195a23bce10865265)
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         default:
562             return EINVAL;
563     }
564     return 0;
565 }
566 
encodeQueryScalarGroupTelemetryV2Request(uint8_t instanceId,PciePortType portType,uint8_t upstreamPortNumber,uint8_t portNumber,uint8_t groupId,std::span<uint8_t> buf)567 int encodeQueryScalarGroupTelemetryV2Request(
568     uint8_t instanceId, PciePortType portType, uint8_t upstreamPortNumber,
569     uint8_t portNumber, uint8_t groupId, std::span<uint8_t> buf)
570 {
571     if (buf.size() < sizeof(QueryScalarGroupTelemetryV2Request))
572     {
573         return EINVAL;
574     }
575 
576     auto* msg =
577         reinterpret_cast<QueryScalarGroupTelemetryV2Request*>(buf.data());
578 
579     ocp::accelerator_management::BindingPciVidInfo header{};
580     header.ocp_accelerator_management_msg_type =
581         static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
582     header.instance_id = instanceId &
583                          ocp::accelerator_management::instanceIdBitMask;
584     header.msg_type = static_cast<uint8_t>(MessageType::PCIE_LINK);
585 
586     auto rc = packHeader(header, msg->hdr.msgHdr.hdr);
587 
588     if (rc != 0)
589     {
590         return rc;
591     }
592 
593     msg->hdr.command =
594         static_cast<uint8_t>(PcieLinkCommands::QueryScalarGroupTelemetryV2);
595     msg->hdr.data_size = 3;
596     msg->upstreamPortNumber =
597         (static_cast<uint8_t>(portType) << 7) | (upstreamPortNumber & 0x7F);
598     msg->portNumber = portNumber;
599     msg->groupId = groupId;
600 
601     return 0;
602 }
603 
decodeQueryScalarGroupTelemetryV2Response(std::span<const uint8_t> buf,ocp::accelerator_management::CompletionCode & cc,uint16_t & reasonCode,size_t & numTelemetryValues,std::vector<uint32_t> & telemetryValues)604 int decodeQueryScalarGroupTelemetryV2Response(
605     std::span<const uint8_t> buf,
606     ocp::accelerator_management::CompletionCode& cc, uint16_t& reasonCode,
607     size_t& numTelemetryValues, std::vector<uint32_t>& telemetryValues)
608 {
609     auto rc =
610         ocp::accelerator_management::decodeReasonCodeAndCC(buf, cc, reasonCode);
611 
612     if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
613     {
614         return rc;
615     }
616 
617     if (buf.size() < sizeof(ocp::accelerator_management::CommonResponse))
618     {
619         return EINVAL;
620     }
621 
622     const auto* response =
623         reinterpret_cast<const ocp::accelerator_management::CommonResponse*>(
624             buf.data());
625 
626     const uint16_t dataSize = le16toh(response->data_size);
627 
628     if (buf.size() <
629         dataSize + sizeof(ocp::accelerator_management::CommonResponse))
630     {
631         return EINVAL;
632     }
633 
634     numTelemetryValues = dataSize / sizeof(uint32_t);
635 
636     if (telemetryValues.size() < numTelemetryValues)
637     {
638         telemetryValues.resize(numTelemetryValues);
639     }
640 
641     const auto* telemetryDataPtr =
642         buf.data() + sizeof(ocp::accelerator_management::CommonResponse);
643 
644     for (size_t i = 0; i < numTelemetryValues; i++)
645     {
646         std::memcpy(&telemetryValues[i],
647                     telemetryDataPtr + i * sizeof(uint32_t), sizeof(uint32_t));
648 
649         telemetryValues[i] = le32toh(telemetryValues[i]);
650     }
651 
652     return 0;
653 }
654 
encodeListPciePortsRequest(uint8_t instanceId,std::span<uint8_t> buf)655 int encodeListPciePortsRequest(uint8_t instanceId, std::span<uint8_t> buf)
656 {
657     if (buf.size() < sizeof(ocp::accelerator_management::CommonRequest))
658     {
659         return EINVAL;
660     }
661 
662     auto* msg = reinterpret_cast<ocp::accelerator_management::CommonRequest*>(
663         buf.data());
664 
665     ocp::accelerator_management::BindingPciVidInfo header{};
666     header.ocp_accelerator_management_msg_type =
667         static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
668     header.instance_id = instanceId &
669                          ocp::accelerator_management::instanceIdBitMask;
670     header.msg_type = static_cast<uint8_t>(MessageType::PCIE_LINK);
671 
672     auto rc = packHeader(header, msg->msgHdr.hdr);
673 
674     if (rc != 0)
675     {
676         return rc;
677     }
678 
679     msg->command = static_cast<uint8_t>(PcieLinkCommands::ListPCIePorts);
680     msg->data_size = 0;
681 
682     return 0;
683 }
684 
decodeListPciePortsResponse(std::span<const uint8_t> buf,ocp::accelerator_management::CompletionCode & cc,uint16_t & reasonCode,uint16_t & numUpstreamPorts,std::vector<uint8_t> & numDownstreamPorts)685 int decodeListPciePortsResponse(
686     std::span<const uint8_t> buf,
687     ocp::accelerator_management::CompletionCode& cc, uint16_t& reasonCode,
688     uint16_t& numUpstreamPorts, std::vector<uint8_t>& numDownstreamPorts)
689 {
690     auto rc =
691         ocp::accelerator_management::decodeReasonCodeAndCC(buf, cc, reasonCode);
692 
693     if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
694     {
695         return rc;
696     }
697 
698     if (buf.size() < sizeof(ListPCIePortsResponse))
699     {
700         return EINVAL;
701     }
702 
703     const auto* response =
704         reinterpret_cast<const ListPCIePortsResponse*>(buf.data());
705 
706     const uint16_t dataSize = le16toh(response->hdr.data_size);
707 
708     if (dataSize < sizeof(uint16_t))
709     {
710         return EINVAL;
711     }
712 
713     uint16_t upstreamPorts = le16toh(response->numUpstreamPorts);
714 
715     numUpstreamPorts = 0;
716     numDownstreamPorts.clear();
717     numDownstreamPorts.reserve(upstreamPorts);
718 
719     size_t offset = sizeof(ListPCIePortsResponse);
720 
721     for (size_t i = 0; i < upstreamPorts; i++)
722     {
723         if (offset + sizeof(ListPCIePortsDownstreamPortsData) > buf.size())
724         {
725             return EINVAL;
726         }
727 
728         const auto* downstreamPortData =
729             reinterpret_cast<const ListPCIePortsDownstreamPortsData*>(
730                 buf.data() + offset);
731 
732         // Count only external upstream ports
733         if (downstreamPortData->isInternal == 0)
734         {
735             ++numUpstreamPorts;
736             numDownstreamPorts.push_back(downstreamPortData->count);
737         }
738 
739         offset += sizeof(ListPCIePortsDownstreamPortsData);
740     }
741 
742     return 0;
743 }
744 
encodeGetPortNetworkAddressesRequest(uint8_t instanceId,uint16_t portNumber,std::span<uint8_t> buf)745 int encodeGetPortNetworkAddressesRequest(
746     uint8_t instanceId, uint16_t portNumber, std::span<uint8_t> buf)
747 {
748     if (buf.size() < sizeof(GetPortNetworkAddressesRequest))
749     {
750         return EINVAL;
751     }
752 
753     auto* msg = std::bit_cast<GetPortNetworkAddressesRequest*>(buf.data());
754 
755     ocp::accelerator_management::BindingPciVidInfo header{};
756     header.ocp_accelerator_management_msg_type =
757         static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
758     header.instance_id = instanceId &
759                          ocp::accelerator_management::instanceIdBitMask;
760     header.msg_type = static_cast<uint8_t>(MessageType::NETWORK_PORT);
761 
762     auto rc = packHeader(header, msg->hdr.msgHdr.hdr);
763 
764     if (rc != 0)
765     {
766         return rc;
767     }
768 
769     msg->hdr.command =
770         static_cast<uint8_t>(NetworkPortCommands::GetPortNetworkAddresses);
771     msg->hdr.data_size = sizeof(portNumber);
772     msg->portNumber = le16toh(portNumber);
773 
774     return 0;
775 }
776 
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)777 int decodeGetPortNetworkAddressesResponse(
778     std::span<const uint8_t> buf,
779     ocp::accelerator_management::CompletionCode& cc, uint16_t& reasonCode,
780     NetworkPortLinkType& linkType,
781     std::vector<std::pair<uint8_t, uint64_t>>& addresses)
782 {
783     addresses.clear();
784     addresses.reserve(std::numeric_limits<uint8_t>::max());
785 
786     const int rc = ocp::accelerator_management::decodeAggregateResponse(
787         buf, cc, reasonCode,
788         [&linkType, &addresses](const uint8_t tag, const uint8_t length,
789                                 const uint8_t* value) -> int {
790             if (tag == 0 && length == 1)
791             {
792                 linkType = static_cast<NetworkPortLinkType>(*value);
793                 return 0;
794             }
795 
796             if (length == sizeof(uint64_t))
797             {
798                 uint64_t telemetryData = 0;
799                 std::memcpy(&telemetryData, value, sizeof(uint64_t));
800                 addresses.emplace_back(tag, le64toh(telemetryData));
801             }
802 
803             return 0;
804         });
805 
806     return rc;
807 }
808 
encodeGetEthernetPortTelemetryCountersRequest(uint8_t instanceId,uint16_t portNumber,std::span<uint8_t> buf)809 int encodeGetEthernetPortTelemetryCountersRequest(
810     uint8_t instanceId, uint16_t portNumber, std::span<uint8_t> buf)
811 {
812     if (buf.size() < sizeof(GetEthernetPortTelemetryCountersRequest))
813     {
814         return EINVAL;
815     }
816 
817     auto* msg =
818         std::bit_cast<GetEthernetPortTelemetryCountersRequest*>(buf.data());
819 
820     ocp::accelerator_management::BindingPciVidInfo header{};
821     header.ocp_accelerator_management_msg_type =
822         static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
823     header.instance_id = instanceId &
824                          ocp::accelerator_management::instanceIdBitMask;
825     header.msg_type = static_cast<uint8_t>(MessageType::NETWORK_PORT);
826 
827     auto rc = packHeader(header, msg->hdr.msgHdr.hdr);
828 
829     if (rc != 0)
830     {
831         return rc;
832     }
833 
834     msg->hdr.command = static_cast<uint8_t>(
835         NetworkPortCommands::GetEthernetPortTelemetryCounters);
836     msg->hdr.data_size = sizeof(portNumber);
837     msg->portNumber = le16toh(portNumber);
838 
839     return 0;
840 }
841 
decodeGetEthernetPortTelemetryCountersResponse(std::span<const uint8_t> buf,ocp::accelerator_management::CompletionCode & cc,uint16_t & reasonCode,std::vector<std::pair<uint8_t,uint64_t>> & telemetryValues)842 int decodeGetEthernetPortTelemetryCountersResponse(
843     std::span<const uint8_t> buf,
844     ocp::accelerator_management::CompletionCode& cc, uint16_t& reasonCode,
845     std::vector<std::pair<uint8_t, uint64_t>>& telemetryValues)
846 {
847     telemetryValues.clear();
848     telemetryValues.reserve(std::numeric_limits<uint8_t>::max());
849 
850     const int rc = ocp::accelerator_management::decodeAggregateResponse(
851         buf, cc, reasonCode,
852         [&telemetryValues](const uint8_t tag, const uint8_t length,
853                            const uint8_t* value) -> int {
854             uint64_t telemetryData = 0;
855 
856             if (length == sizeof(uint32_t))
857             {
858                 uint32_t telemetryValue = 0;
859                 std::memcpy(&telemetryValue, value, sizeof(uint32_t));
860 
861                 telemetryData = le32toh(telemetryValue);
862             }
863             else if (length == sizeof(uint64_t))
864             {
865                 uint64_t telemetryValue = 0;
866                 std::memcpy(&telemetryValue, value, sizeof(uint64_t));
867 
868                 telemetryData = le64toh(telemetryValue);
869             }
870             else
871             {
872                 return EINVAL;
873             }
874 
875             telemetryValues.emplace_back(tag, telemetryData);
876 
877             return 0;
878         });
879 
880     return rc;
881 }
882 // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
883 } // namespace gpu
884