1 /*
2 * SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION &
3 * AFFILIATES. All rights reserved.
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "NvidiaGpuMctpVdm.hpp"
8 #include "OcpMctpVdm.hpp"
9
10 #include <endian.h>
11
12 #include <array>
13 #include <cerrno>
14 #include <cstdint>
15 #include <cstring>
16 #include <vector>
17
18 #include <gtest/gtest.h>
19
20 namespace ocp_mctp_tests
21 {
22
23 class OcpMctpVdmTests : public ::testing::Test
24 {
25 protected:
SetUp()26 void SetUp() override
27 {
28 // Initialize common test data here
29 }
30 };
31
32 // Tests for OcpMctpVdm::packHeader function
TEST_F(OcpMctpVdmTests,PackHeaderRequestSuccess)33 TEST_F(OcpMctpVdmTests, PackHeaderRequestSuccess)
34 {
35 const uint16_t pciVendorId = 0x1234;
36 ocp::accelerator_management::BindingPciVidInfo hdr{};
37 ocp::accelerator_management::BindingPciVid msg{};
38
39 hdr.ocp_accelerator_management_msg_type =
40 static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
41 hdr.instance_id = 5;
42 hdr.msg_type = 0x7E;
43
44 int result = ocp::accelerator_management::packHeader(pciVendorId, hdr, msg);
45
46 EXPECT_EQ(result, 0);
47 EXPECT_EQ(msg.pci_vendor_id, htobe16(pciVendorId));
48 EXPECT_EQ(msg.instance_id & ocp::accelerator_management::instanceIdBitMask,
49 5);
50 EXPECT_NE(msg.instance_id & ocp::accelerator_management::requestBitMask, 0);
51 EXPECT_EQ(msg.ocp_version & 0x0F, ocp::accelerator_management::ocpVersion);
52 EXPECT_EQ((msg.ocp_version & 0xF0) >>
53 ocp::accelerator_management::ocpTypeBitOffset,
54 ocp::accelerator_management::ocpType);
55 EXPECT_EQ(msg.ocp_accelerator_management_msg_type, 0x7E);
56 }
57
TEST_F(OcpMctpVdmTests,PackHeaderResponseSuccess)58 TEST_F(OcpMctpVdmTests, PackHeaderResponseSuccess)
59 {
60 const uint16_t pciVendorId = 0x1234;
61 ocp::accelerator_management::BindingPciVidInfo hdr{};
62 ocp::accelerator_management::BindingPciVid msg{};
63
64 hdr.ocp_accelerator_management_msg_type = static_cast<uint8_t>(
65 ocp::accelerator_management::MessageType::RESPONSE);
66 hdr.instance_id = 10;
67 hdr.msg_type = 0x7E;
68
69 int result = ocp::accelerator_management::packHeader(pciVendorId, hdr, msg);
70
71 EXPECT_EQ(result, 0);
72 EXPECT_EQ(msg.pci_vendor_id, htobe16(pciVendorId));
73 EXPECT_EQ(msg.instance_id & ocp::accelerator_management::instanceIdBitMask,
74 10);
75 EXPECT_EQ(msg.instance_id & ocp::accelerator_management::requestBitMask, 0);
76 EXPECT_EQ(msg.ocp_version & 0x0F, ocp::accelerator_management::ocpVersion);
77 EXPECT_EQ((msg.ocp_version & 0xF0) >>
78 ocp::accelerator_management::ocpTypeBitOffset,
79 ocp::accelerator_management::ocpType);
80 EXPECT_EQ(msg.ocp_accelerator_management_msg_type, 0x7E);
81 }
82
TEST_F(OcpMctpVdmTests,PackHeaderInvalidMessageType)83 TEST_F(OcpMctpVdmTests, PackHeaderInvalidMessageType)
84 {
85 const uint16_t pciVendorId = 0x1234;
86 ocp::accelerator_management::BindingPciVidInfo hdr{};
87 ocp::accelerator_management::BindingPciVid msg{};
88
89 hdr.ocp_accelerator_management_msg_type = 3; // Invalid message type
90 hdr.instance_id = 5;
91 hdr.msg_type = 0x7E;
92
93 int result = ocp::accelerator_management::packHeader(pciVendorId, hdr, msg);
94
95 EXPECT_EQ(result, EINVAL);
96 }
97
TEST_F(OcpMctpVdmTests,PackHeaderInvalidInstanceId)98 TEST_F(OcpMctpVdmTests, PackHeaderInvalidInstanceId)
99 {
100 const uint16_t pciVendorId = 0x1234;
101 ocp::accelerator_management::BindingPciVidInfo hdr{};
102 ocp::accelerator_management::BindingPciVid msg{};
103
104 hdr.ocp_accelerator_management_msg_type =
105 static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
106 hdr.instance_id = 32; // Out of range (0-31 valid)
107 hdr.msg_type = 0x7E;
108
109 int result = ocp::accelerator_management::packHeader(pciVendorId, hdr, msg);
110
111 EXPECT_EQ(result, EINVAL);
112 }
113
114 // Tests for OcpMctpVdm::decodeReasonCodeAndCC function
TEST_F(OcpMctpVdmTests,DecodeReasonCodeAndCCSuccessCase)115 TEST_F(OcpMctpVdmTests, DecodeReasonCodeAndCCSuccessCase)
116 {
117 ocp::accelerator_management::CommonNonSuccessResponse response{};
118 response.command = 0x42;
119 response.completion_code = static_cast<uint8_t>(
120 ocp::accelerator_management::CompletionCode::SUCCESS);
121 response.reason_code = htole16(0x1234);
122
123 ocp::accelerator_management::CompletionCode cc{};
124 uint16_t reasonCode{};
125
126 std::array<uint8_t, sizeof(response)> buf{};
127 std::memcpy(buf.data(), &response, sizeof(response));
128
129 int result =
130 ocp::accelerator_management::decodeReasonCodeAndCC(buf, cc, reasonCode);
131
132 EXPECT_EQ(result, 0);
133 EXPECT_EQ(cc, ocp::accelerator_management::CompletionCode::SUCCESS);
134 EXPECT_EQ(reasonCode, 0); // Should be 0 for SUCCESS
135 }
136
TEST_F(OcpMctpVdmTests,DecodeReasonCodeAndCCErrorCase)137 TEST_F(OcpMctpVdmTests, DecodeReasonCodeAndCCErrorCase)
138 {
139 ocp::accelerator_management::CommonNonSuccessResponse response{};
140 response.command = 0x42;
141 response.completion_code = static_cast<uint8_t>(
142 ocp::accelerator_management::CompletionCode::ERROR);
143 response.reason_code = htole16(0x5678);
144
145 ocp::accelerator_management::CompletionCode cc{};
146 uint16_t reasonCode{};
147
148 std::array<uint8_t, sizeof(response)> buf{};
149 std::memcpy(buf.data(), &response, sizeof(response));
150
151 int result =
152 ocp::accelerator_management::decodeReasonCodeAndCC(buf, cc, reasonCode);
153
154 EXPECT_EQ(result, 0);
155 EXPECT_EQ(cc, ocp::accelerator_management::CompletionCode::ERROR);
156 EXPECT_EQ(reasonCode, 0x5678);
157 }
158
159 } // namespace ocp_mctp_tests
160
161 namespace gpu_mctp_tests
162 {
163
164 class GpuMctpVdmTests : public ::testing::Test
165 {
166 protected:
SetUp()167 void SetUp() override
168 {
169 // Initialize common test data here
170 }
171 };
172
173 // Tests for GpuMctpVdm::packHeader function
TEST_F(GpuMctpVdmTests,PackHeaderSuccess)174 TEST_F(GpuMctpVdmTests, PackHeaderSuccess)
175 {
176 ocp::accelerator_management::BindingPciVidInfo hdr{};
177 ocp::accelerator_management::BindingPciVid msg{};
178
179 hdr.ocp_accelerator_management_msg_type =
180 static_cast<uint8_t>(ocp::accelerator_management::MessageType::REQUEST);
181 hdr.instance_id = 5;
182 hdr.msg_type = 0x7E;
183
184 int result = gpu::packHeader(hdr, msg);
185
186 EXPECT_EQ(result, 0);
187 EXPECT_EQ(msg.pci_vendor_id, htobe16(gpu::nvidiaPciVendorId));
188 EXPECT_EQ(msg.instance_id & ocp::accelerator_management::instanceIdBitMask,
189 5);
190 EXPECT_NE(msg.instance_id & ocp::accelerator_management::requestBitMask, 0);
191 EXPECT_EQ(msg.ocp_version & 0x0F, ocp::accelerator_management::ocpVersion);
192 EXPECT_EQ((msg.ocp_version & 0xF0) >>
193 ocp::accelerator_management::ocpTypeBitOffset,
194 ocp::accelerator_management::ocpType);
195 EXPECT_EQ(msg.ocp_accelerator_management_msg_type, 0x7E);
196 }
197
198 // Tests for GpuMctpVdm::encodeQueryDeviceIdentificationRequest function
TEST_F(GpuMctpVdmTests,EncodeQueryDeviceIdentificationRequestSuccess)199 TEST_F(GpuMctpVdmTests, EncodeQueryDeviceIdentificationRequestSuccess)
200 {
201 const uint8_t instanceId = 3;
202 std::vector<uint8_t> buf(256);
203
204 int result = gpu::encodeQueryDeviceIdentificationRequest(instanceId, buf);
205
206 EXPECT_EQ(result, 0);
207
208 gpu::QueryDeviceIdentificationRequest request{};
209 std::memcpy(&request, buf.data(), sizeof(request));
210
211 EXPECT_EQ(request.hdr.msgHdr.hdr.pci_vendor_id,
212 htobe16(gpu::nvidiaPciVendorId));
213 EXPECT_EQ(request.hdr.msgHdr.hdr.instance_id &
214 ocp::accelerator_management::instanceIdBitMask,
215 instanceId & ocp::accelerator_management::instanceIdBitMask);
216 EXPECT_NE(request.hdr.msgHdr.hdr.instance_id &
217 ocp::accelerator_management::requestBitMask,
218 0);
219
220 EXPECT_EQ(request.hdr.command,
221 static_cast<uint8_t>(gpu::DeviceCapabilityDiscoveryCommands::
222 QUERY_DEVICE_IDENTIFICATION));
223 EXPECT_EQ(request.hdr.data_size, 0);
224 }
225
226 // Tests for GpuMctpVdm::decodeQueryDeviceIdentificationResponse function
TEST_F(GpuMctpVdmTests,DecodeQueryDeviceIdentificationResponseSuccess)227 TEST_F(GpuMctpVdmTests, DecodeQueryDeviceIdentificationResponseSuccess)
228 {
229 // Create a mock successful response
230 std::vector<uint8_t> buf(sizeof(gpu::QueryDeviceIdentificationResponse));
231
232 gpu::QueryDeviceIdentificationResponse response{};
233 ocp::accelerator_management::BindingPciVidInfo headerInfo{};
234 headerInfo.ocp_accelerator_management_msg_type = static_cast<uint8_t>(
235 ocp::accelerator_management::MessageType::RESPONSE);
236 headerInfo.instance_id = 3;
237 headerInfo.msg_type =
238 static_cast<uint8_t>(gpu::MessageType::DEVICE_CAPABILITY_DISCOVERY);
239
240 gpu::packHeader(headerInfo, response.hdr.msgHdr.hdr);
241
242 // Populate response data
243 response.hdr.command = static_cast<uint8_t>(
244 gpu::DeviceCapabilityDiscoveryCommands::QUERY_DEVICE_IDENTIFICATION);
245 response.hdr.completion_code = static_cast<uint8_t>(
246 ocp::accelerator_management::CompletionCode::SUCCESS);
247 response.hdr.reserved = 0;
248 response.hdr.data_size =
249 htole16(2); // Size of device_identification + instance_id
250 response.device_identification =
251 static_cast<uint8_t>(gpu::DeviceIdentification::DEVICE_GPU);
252 response.instance_id = 7;
253
254 std::memcpy(buf.data(), &response, sizeof(response));
255
256 // Test decoding
257 ocp::accelerator_management::CompletionCode cc{};
258 uint16_t reasonCode{};
259 uint8_t deviceIdentification{};
260 uint8_t deviceInstance{};
261
262 int result = gpu::decodeQueryDeviceIdentificationResponse(
263 buf, cc, reasonCode, deviceIdentification, deviceInstance);
264
265 EXPECT_EQ(result, 0);
266 EXPECT_EQ(cc, ocp::accelerator_management::CompletionCode::SUCCESS);
267 EXPECT_EQ(reasonCode, 0);
268 EXPECT_EQ(deviceIdentification,
269 static_cast<uint8_t>(gpu::DeviceIdentification::DEVICE_GPU));
270 EXPECT_EQ(deviceInstance, 7);
271 }
272
TEST_F(GpuMctpVdmTests,DecodeQueryDeviceIdentificationResponseError)273 TEST_F(GpuMctpVdmTests, DecodeQueryDeviceIdentificationResponseError)
274 {
275 // Create a mock successful response
276 std::vector<uint8_t> buf(
277 sizeof(ocp::accelerator_management::CommonNonSuccessResponse));
278
279 ocp::accelerator_management::CommonNonSuccessResponse response{};
280 ocp::accelerator_management::BindingPciVidInfo headerInfo{};
281 headerInfo.ocp_accelerator_management_msg_type = static_cast<uint8_t>(
282 ocp::accelerator_management::MessageType::RESPONSE);
283 headerInfo.instance_id = 3;
284 headerInfo.msg_type =
285 static_cast<uint8_t>(gpu::MessageType::DEVICE_CAPABILITY_DISCOVERY);
286
287 gpu::packHeader(headerInfo, response.msgHdr.hdr);
288
289 // Populate response data
290 response.command = static_cast<uint8_t>(
291 gpu::DeviceCapabilityDiscoveryCommands::QUERY_DEVICE_IDENTIFICATION);
292 response.command = static_cast<uint8_t>(
293 gpu::DeviceCapabilityDiscoveryCommands::QUERY_DEVICE_IDENTIFICATION);
294 response.completion_code = static_cast<uint8_t>(
295 ocp::accelerator_management::CompletionCode::ERROR);
296 response.reason_code = htole16(0x1234);
297
298 std::memcpy(buf.data(), &response, sizeof(response));
299
300 // Test decoding
301 ocp::accelerator_management::CompletionCode cc{};
302 uint16_t reasonCode{};
303 uint8_t deviceIdentification{};
304 uint8_t deviceInstance{};
305
306 int result = gpu::decodeQueryDeviceIdentificationResponse(
307 buf, cc, reasonCode, deviceIdentification, deviceInstance);
308
309 EXPECT_EQ(result, 0);
310 EXPECT_EQ(cc, ocp::accelerator_management::CompletionCode::ERROR);
311 EXPECT_EQ(reasonCode, 0x1234);
312 }
313
TEST_F(GpuMctpVdmTests,DecodeQueryDeviceIdentificationResponseInvalidSize)314 TEST_F(GpuMctpVdmTests, DecodeQueryDeviceIdentificationResponseInvalidSize)
315 {
316 // Create a too-small buffer
317 std::vector<uint8_t> buf(
318 sizeof(ocp::accelerator_management::Message) + 2); // Too small
319
320 // Populate Message header only
321 ocp::accelerator_management::Message msg{};
322 ocp::accelerator_management::BindingPciVidInfo headerInfo{};
323 headerInfo.ocp_accelerator_management_msg_type = static_cast<uint8_t>(
324 ocp::accelerator_management::MessageType::RESPONSE);
325 headerInfo.instance_id = 3;
326 headerInfo.msg_type =
327 static_cast<uint8_t>(gpu::MessageType::DEVICE_CAPABILITY_DISCOVERY);
328
329 gpu::packHeader(headerInfo, msg.hdr);
330 std::memcpy(buf.data(), &msg, sizeof(msg));
331
332 // Test decoding with insufficient data
333 ocp::accelerator_management::CompletionCode cc{};
334 uint16_t reasonCode{};
335 uint8_t deviceIdentification{};
336 uint8_t deviceInstance{};
337
338 int result = gpu::decodeQueryDeviceIdentificationResponse(
339 buf, cc, reasonCode, deviceIdentification, deviceInstance);
340
341 EXPECT_EQ(result, EINVAL); // Should indicate error for invalid size
342 }
343
344 // Tests for GpuMctpVdm::encodeGetTemperatureReadingRequest function
TEST_F(GpuMctpVdmTests,EncodeGetTemperatureReadingRequestSuccess)345 TEST_F(GpuMctpVdmTests, EncodeGetTemperatureReadingRequestSuccess)
346 {
347 const uint8_t instanceId = 4;
348 const uint8_t sensorId = 0;
349 std::vector<uint8_t> buf(256);
350
351 int result =
352 gpu::encodeGetTemperatureReadingRequest(instanceId, sensorId, buf);
353
354 EXPECT_EQ(result, 0);
355
356 gpu::GetTemperatureReadingRequest request{};
357 std::memcpy(&request, buf.data(), sizeof(request));
358
359 EXPECT_EQ(request.hdr.msgHdr.hdr.pci_vendor_id,
360 htobe16(gpu::nvidiaPciVendorId));
361 EXPECT_EQ(request.hdr.msgHdr.hdr.instance_id &
362 ocp::accelerator_management::instanceIdBitMask,
363 instanceId & ocp::accelerator_management::instanceIdBitMask);
364 EXPECT_NE(request.hdr.msgHdr.hdr.instance_id &
365 ocp::accelerator_management::requestBitMask,
366 0);
367 EXPECT_EQ(request.hdr.msgHdr.hdr.ocp_accelerator_management_msg_type,
368 static_cast<uint8_t>(gpu::MessageType::PLATFORM_ENVIRONMENTAL));
369
370 // Verify request data
371 EXPECT_EQ(request.hdr.command,
372 static_cast<uint8_t>(
373 gpu::PlatformEnvironmentalCommands::GET_TEMPERATURE_READING));
374 EXPECT_EQ(request.hdr.data_size, sizeof(sensorId));
375 EXPECT_EQ(request.sensor_id, sensorId);
376 }
377
378 // Tests for GpuMctpVdm::decodeGetTemperatureReadingResponse function
TEST_F(GpuMctpVdmTests,DecodeGetTemperatureReadingResponseSuccess)379 TEST_F(GpuMctpVdmTests, DecodeGetTemperatureReadingResponseSuccess)
380 {
381 // Create a mock successful response
382 std::vector<uint8_t> buf(sizeof(gpu::GetTemperatureReadingResponse));
383
384 gpu::GetTemperatureReadingResponse response{};
385 ocp::accelerator_management::BindingPciVidInfo headerInfo{};
386 headerInfo.ocp_accelerator_management_msg_type = static_cast<uint8_t>(
387 ocp::accelerator_management::MessageType::RESPONSE);
388 headerInfo.instance_id = 4;
389 headerInfo.msg_type =
390 static_cast<uint8_t>(gpu::MessageType::PLATFORM_ENVIRONMENTAL);
391
392 gpu::packHeader(headerInfo, response.hdr.msgHdr.hdr);
393
394 // Populate response data
395 response.hdr.command = static_cast<uint8_t>(
396 gpu::PlatformEnvironmentalCommands::GET_TEMPERATURE_READING);
397 response.hdr.completion_code = static_cast<uint8_t>(
398 ocp::accelerator_management::CompletionCode::SUCCESS);
399 response.hdr.reserved = 0;
400 response.hdr.data_size = htole16(sizeof(int32_t));
401
402 // Set a temperature value of 75.5°C (75.5 * 256 = 19328)
403 response.reading = htole32(19328);
404
405 std::memcpy(buf.data(), &response, sizeof(response));
406
407 // Test decoding
408 ocp::accelerator_management::CompletionCode cc{};
409 uint16_t reasonCode{};
410 double temperatureReading{};
411
412 int result = gpu::decodeGetTemperatureReadingResponse(
413 buf, cc, reasonCode, temperatureReading);
414
415 EXPECT_EQ(result, 0);
416 EXPECT_EQ(cc, ocp::accelerator_management::CompletionCode::SUCCESS);
417 EXPECT_EQ(reasonCode, 0);
418 EXPECT_NEAR(temperatureReading, 75.5, 0.01);
419 }
420
TEST_F(GpuMctpVdmTests,DecodeGetTemperatureReadingResponseError)421 TEST_F(GpuMctpVdmTests, DecodeGetTemperatureReadingResponseError)
422 {
423 std::vector<uint8_t> buf(
424 sizeof(ocp::accelerator_management::CommonNonSuccessResponse));
425
426 // Populate error response data
427 ocp::accelerator_management::CommonNonSuccessResponse errorResponse{};
428 ocp::accelerator_management::BindingPciVidInfo headerInfo{};
429 headerInfo.ocp_accelerator_management_msg_type = static_cast<uint8_t>(
430 ocp::accelerator_management::MessageType::RESPONSE);
431 headerInfo.instance_id = 3;
432 headerInfo.msg_type =
433 static_cast<uint8_t>(gpu::MessageType::DEVICE_CAPABILITY_DISCOVERY);
434
435 gpu::packHeader(headerInfo, errorResponse.msgHdr.hdr);
436
437 errorResponse.command = static_cast<uint8_t>(
438 gpu::PlatformEnvironmentalCommands::GET_TEMPERATURE_READING);
439 errorResponse.completion_code = static_cast<uint8_t>(
440 ocp::accelerator_management::CompletionCode::ERR_NOT_READY);
441 errorResponse.reason_code = htole16(0x4321);
442
443 std::memcpy(buf.data(), &errorResponse, sizeof(errorResponse));
444
445 // Test decoding
446 ocp::accelerator_management::CompletionCode cc{};
447 uint16_t reasonCode{};
448 double temperatureReading{};
449
450 int result = gpu::decodeGetTemperatureReadingResponse(
451 buf, cc, reasonCode, temperatureReading);
452
453 EXPECT_EQ(result, 0);
454 EXPECT_EQ(cc, ocp::accelerator_management::CompletionCode::ERR_NOT_READY);
455 EXPECT_EQ(reasonCode, 0x4321);
456 }
457
TEST_F(GpuMctpVdmTests,DecodeGetTemperatureReadingResponseInvalidSize)458 TEST_F(GpuMctpVdmTests, DecodeGetTemperatureReadingResponseInvalidSize)
459 {
460 // Create a mock response with invalid data_size
461 std::vector<uint8_t> buf(sizeof(gpu::GetTemperatureReadingResponse));
462
463 gpu::GetTemperatureReadingResponse response{};
464 ocp::accelerator_management::BindingPciVidInfo headerInfo{};
465 headerInfo.ocp_accelerator_management_msg_type = static_cast<uint8_t>(
466 ocp::accelerator_management::MessageType::RESPONSE);
467 headerInfo.instance_id = 4;
468 headerInfo.msg_type =
469 static_cast<uint8_t>(gpu::MessageType::PLATFORM_ENVIRONMENTAL);
470
471 gpu::packHeader(headerInfo, response.hdr.msgHdr.hdr);
472
473 response.hdr.command = static_cast<uint8_t>(
474 gpu::PlatformEnvironmentalCommands::GET_TEMPERATURE_READING);
475 response.hdr.completion_code = static_cast<uint8_t>(
476 ocp::accelerator_management::CompletionCode::SUCCESS);
477 response.hdr.reserved = 0;
478 response.hdr.data_size = htole16(1); // Invalid - should be sizeof(int32_t)
479 response.reading = htole32(19328);
480
481 std::memcpy(buf.data(), &response, sizeof(response));
482
483 // Test decoding
484 ocp::accelerator_management::CompletionCode cc{};
485 uint16_t reasonCode{};
486 double temperatureReading{};
487
488 int result = gpu::decodeGetTemperatureReadingResponse(
489 buf, cc, reasonCode, temperatureReading);
490
491 EXPECT_EQ(result, EINVAL); // Should indicate error for invalid data size
492 }
493
494 } // namespace gpu_mctp_tests
495
main(int argc,char ** argv)496 int main(int argc, char** argv)
497 {
498 ::testing::InitGoogleTest(&argc, argv);
499 return RUN_ALL_TESTS();
500 }
501