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