blob: 71dff136907c67402394f86f44054af04015baf6 [file] [log] [blame]
Matt Spinler18c42b02020-06-02 15:59:50 -05001/**
2 * Copyright © 2020 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "extensions/openpower-pels/device_callouts.hpp"
18#include "extensions/openpower-pels/paths.hpp"
19
20#include <fstream>
21
22#include <gtest/gtest.h>
23
24using namespace openpower::pels;
25using namespace openpower::pels::device_callouts;
26namespace fs = std::filesystem;
27
28// The callout JSON looks like:
29// "I2C":
30// "<bus>":
31// "<address>":
32// "Callouts": ...
33//
34// "FSI":
35// "<fsi link>":
36// "Callouts": ...
37//
38// "FSI-I2C":
39// "<fsi link>":
40// "<bus>":
41// "<address>":
42// "Callouts": ...
43//
44// "FSI-SPI":
45// "<fsi link>":
46// "<bus>":
47// "Callouts": ...
48
49const auto calloutJSON = R"(
50{
51 "I2C":
52 {
53 "0":
54 {
55 "32":
56 {
57 "Callouts":[
58 {
59 "Name": "/chassis/motherboard/cpu0",
60 "LocationCode": "P1-C19",
61 "Priority": "H"
62 }
63 ],
64 "Dest": "proc-0 target"
65 },
66 "81":
67 {
68 "Callouts":[
69 {
70 "Name": "/chassis/motherboard/cpu0",
71 "LocationCode": "P1-C19",
72 "Priority": "H"
73 }
74 ],
75 "Dest": "proc-0 target"
Matt Spinler6bc74ae2020-06-03 15:13:59 -050076 },
77 "90":
78 {
79 "Callouts":[
80 {
81 "Name": "This is missing the location code",
82 "Priority": "H"
83 }
84 ],
85 "Dest": "proc-0 target"
Matt Spinler18c42b02020-06-02 15:59:50 -050086 }
87 },
88 "14":
89 {
90 "112":
91 {
92 "Callouts":[
93 {
94 "Name": "/chassis/motherboard/cpu0",
95 "LocationCode": "P1-C19",
96 "Priority": "H"
97 }
98 ],
99 "Dest": "proc-0 target"
100 },
101 "114":
102 {
103 "Callouts":[
104 {
105 "Name": "/chassis/motherboard/cpu0",
106 "LocationCode": "P1-C19",
Matt Spinler6bc74ae2020-06-03 15:13:59 -0500107 "Priority": "H",
108 "MRU": "core0"
Matt Spinler18c42b02020-06-02 15:59:50 -0500109 },
110 {
111 "Name": "/chassis/motherboard",
112 "LocationCode": "P1",
113 "Priority": "M"
114 }
115 ],
116 "Dest": "proc-0 target"
117 }
118 }
119 },
120 "FSI":
121 {
122 "0":
123 {
124 "Callouts":[
125 {
126 "Name": "/chassis/motherboard/cpu0",
127 "LocationCode": "P1-C19",
128 "Priority": "H"
129 }
130 ],
131 "Dest": "proc-0 target"
132 },
133 "0-1":
134 {
135 "Callouts":[
136 {
137 "Name": "/chassis/motherboard/cpu0",
138 "LocationCode": "P1-C19",
139 "Priority": "H",
140 "MRU": "core"
141 }
142 ],
143 "Dest": "proc-0 target"
144 }
145 },
146 "FSI-I2C":
147 {
148 "0-3":
149 {
150 "7":
151 {
152 "24":
153 {
154 "Callouts":[
155 {
156 "Name": "/chassis/motherboard/cpu0",
157 "LocationCode": "P1-C19",
158 "Priority": "H"
159 }
160 ],
161 "Dest": "proc-0 target"
162 },
163 "25":
164 {
165 "Callouts":[
166 {
167 "Name": "/chassis/motherboard/cpu5",
168 "LocationCode": "P1-C25",
169 "Priority": "H"
170 },
171 {
172 "Name": "/chassis/motherboard",
173 "LocationCode": "P1",
174 "Priority": "M"
175 },
176 {
177 "Name": "/chassis/motherboard/bmc",
178 "LocationCode": "P2",
179 "Priority": "L"
180 }
181 ],
182 "Dest": "proc-5 target"
183 }
184 }
185 }
186 },
187 "FSI-SPI":
188 {
189 "8":
190 {
191 "3":
192 {
193 "Callouts":[
194 {
195 "Name": "/chassis/motherboard/cpu0",
196 "LocationCode": "P1-C19",
197 "Priority": "H"
198 }
199 ],
200 "Dest": "proc-0 target"
201 },
202 "4":
203 {
204 "Callouts":[
205 {
Matt Spinler6bc74ae2020-06-03 15:13:59 -0500206 "Name": "/chassis/motherboard/cpu2",
207 "LocationCode": "P1-C12",
208 "Priority": "M"
Matt Spinler18c42b02020-06-02 15:59:50 -0500209 }
210 ],
211 "Dest": "proc-0 target"
212 }
213 }
214 }
215})"_json;
216
217class DeviceCalloutsTest : public ::testing::Test
218{
219 public:
220 static void SetUpTestCase()
221 {
222 dataPath = getPELReadOnlyDataPath();
223 std::ofstream file{dataPath / filename};
224 file << calloutJSON.dump();
225 }
226
227 static void TearDownTestCase()
228 {
229 fs::remove_all(dataPath);
230 }
231
232 static std::string filename;
233 static fs::path dataPath;
234};
235
236std::string DeviceCalloutsTest::filename = "systemA_dev_callouts.json";
237fs::path DeviceCalloutsTest::dataPath;
238
Matt Spinler6bc74ae2020-06-03 15:13:59 -0500239namespace openpower::pels::device_callouts
240{
241
242// Helpers to compair vectors of Callout objects
243bool operator!=(const Callout& left, const Callout& right)
244{
245 return (left.priority != right.priority) ||
246 (left.locationCode != right.locationCode) ||
247 (left.name != right.name) || (left.mru != right.mru) ||
248 (left.debug != right.debug);
249}
250
251bool operator==(const std::vector<Callout>& left,
252 const std::vector<Callout>& right)
253{
254 if (left.size() != right.size())
255 {
256 return false;
257 }
258
259 for (size_t i = 0; i < left.size(); i++)
260 {
261 if (left[i] != right[i])
262 {
263 return false;
264 }
265 }
266
267 return true;
268}
269
270} // namespace openpower::pels::device_callouts
271
Matt Spinler18c42b02020-06-02 15:59:50 -0500272// Test looking up the JSON file based on the system compatible names
273TEST_F(DeviceCalloutsTest, getJSONFilenameTest)
274{
275 {
276 std::vector<std::string> compatibles{"system1", "systemA", "system3"};
277 EXPECT_EQ(util::getJSONFilename(compatibles),
278 fs::path{dataPath / filename});
279 }
280
281 // Actual filename not in compatibles
282 {
283 std::vector<std::string> compatibles{"system5", "system6"};
284 EXPECT_THROW(util::getJSONFilename(compatibles), std::invalid_argument);
285 }
Matt Spinler0f8a7382020-07-22 12:58:45 -0500286
287 // Test using the fallback name
288 {
289 // If _dev_callouts.json is there, it will be used if no other
290 // match is found.
291 fs::path fallbackFile{dataPath / "_dev_callouts.json"};
292 std::ofstream file{fallbackFile};
293 file << calloutJSON.dump();
294 file.close();
295
296 // Fallback shouldn't be used because the actual systemA file is there
297 {
298 std::vector<std::string> compatibles{"system1", "systemA",
299 "system3"};
300 EXPECT_EQ(util::getJSONFilename(compatibles),
301 fs::path{dataPath / filename});
302 }
303
304 // Fallback should be used because no other match
305 {
306 std::vector<std::string> compatibles{"systemX", "systemY"};
307 EXPECT_EQ(util::getJSONFilename(compatibles), fallbackFile);
308 }
309 }
Matt Spinler18c42b02020-06-02 15:59:50 -0500310}
Matt Spinlera3070892020-06-03 10:52:32 -0500311
312// Test determining the callout type from the device path
313TEST_F(DeviceCalloutsTest, getCalloutTypeTest)
314{
315
316 // Invalid
317 {
318 EXPECT_EQ(util::getCalloutType("/some/bad/device/path"),
319 util::CalloutType::unknown);
320 }
321
322 // I2C
323 {
324 EXPECT_EQ(util::getCalloutType(
325 "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/"
Matt Spinler6bc74ae2020-06-03 15:13:59 -0500326 "1e78a340.i2c-bus/i2c-14/14-0072"),
Matt Spinlera3070892020-06-03 10:52:32 -0500327 util::CalloutType::i2c);
328 }
329
330 // FSI
331 {
332 EXPECT_EQ(util::getCalloutType(
333 "/sys/devices/platform/ahb/ahb:apb/1e79b000.fsi/"
334 "fsi-master/fsi0/slave@00:00/00:00:00:0a/fsi-master/fsi1/"
335 "slave@01:00/01:01:00:06/sbefifo2-dev0/occ-hwmon.2"),
336 util::CalloutType::fsi);
337 }
338
339 // FSI-I2C
340 {
341 EXPECT_EQ(util::getCalloutType(
342 "/sys/devices/platform/ahb/ahb:apb/1e79b000.fsi/"
343 "fsi-master/fsi0/slave@00:00/00:00:00:0a/fsi-master/fsi1/"
344 "slave@01:00/01:01:00:03/i2c-211/211-0055"),
345 util::CalloutType::fsii2c);
346 }
347
348 // FSI-SPI
349 {
350
351 EXPECT_EQ(
352 util::getCalloutType(
353 "/sys/devices/platform/ahb/ahb:apb/1e79b000.fsi/fsi-master/"
354 "fsi0/slave@00:00/00:00:00:0a/fsi-master/fsi1/slave@08:00/"
355 "01:03:00:04/spi_master/spi9/spi9.0/spi9.00/nvmem"),
356 util::CalloutType::fsispi);
357 }
358}
Matt Spinler44c0a642020-06-03 11:28:25 -0500359
360// Test getting I2C search keys
361TEST_F(DeviceCalloutsTest, getI2CSearchKeysTest)
362{
363
364 {
365 EXPECT_EQ(util::getI2CSearchKeys(
366 "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/"
367 "1e78a340.i2c-bus/i2c-10/10-0022"),
368 (std::tuple{10, 0x22}));
369
370 EXPECT_EQ(util::getI2CSearchKeys(
371 "/sys/devices/platform/ahb/ahb:apb/1e79b000.fsi/"
372 "fsi-master/fsi0/slave@00:00/00:00:00:0a/fsi-master/fsi1/"
373 "slave@01:00/01:01:00:03/i2c-211/211-0055"),
374 (std::tuple{11, 0x55}));
375 }
376
377 {
378 EXPECT_THROW(util::getI2CSearchKeys("/sys/some/bad/path"),
379 std::invalid_argument);
380 }
381}
382//
383// Test getting SPI search keys
384TEST_F(DeviceCalloutsTest, getSPISearchKeysTest)
385{
386 {
387 EXPECT_EQ(
388 util::getSPISearchKeys(
389 "/sys/devices/platform/ahb/ahb:apb/1e79b000.fsi/fsi-master/"
390 "fsi0/slave@00:00/00:00:00:0a/fsi-master/fsi1/slave@08:00/"
391 "01:03:00:04/spi_master/spi9/spi9.0/spi9.00/nvmem"),
392 9);
393 }
394
395 {
396 EXPECT_THROW(util::getSPISearchKeys("/sys/some/bad/path"),
397 std::invalid_argument);
398 }
399}
400
401// Test getting FSI search keys
402TEST_F(DeviceCalloutsTest, getFSISearchKeysTest)
403{
404 {
405 EXPECT_EQ(util::getFSISearchKeys(
406 "/sys/devices/platform/ahb/ahb:apb/1e79b000.fsi/"
407 "fsi-master/fsi0/slave@00:00/00:00:00:04/spi_master/spi2/"
408 "spi2.0/spi2.00/nvmem"),
409 "0");
410 }
411
412 {
413 EXPECT_EQ(util::getFSISearchKeys(
414 "/sys/devices/platform/ahb/ahb:apb/1e79b000.fsi/"
415 "fsi-master/fsi0/slave@00:00/00:00:00:0a/fsi-master/fsi1/"
416 "slave@01:00/01:01:00:06/sbefifo2-dev0/occ-hwmon.2"),
417 "0-1");
418 }
419
420 {
421 EXPECT_EQ(
422 util::getFSISearchKeys(
423 "/sys/devices/platform/ahb/ahb:apb/1e79b000.fsi/"
424 "fsi-master/fsi0/slave@00:00/00:00:00:0a/fsi-master/fsi1/"
425 "slave@01:00/01:01:00:0a:/fsi-master/slave@04:00/01:01:00:0a"),
426 "0-1-4");
427 }
428
429 {
430 EXPECT_THROW(util::getFSISearchKeys("/sys/some/bad/path"),
431 std::invalid_argument);
432 }
433}
434
435// Test getting FSI-I2C search keys
436TEST_F(DeviceCalloutsTest, getFSII2CSearchKeysTest)
437{
438 {
439 // Link 0-1 bus 11 address 0x55
440 EXPECT_EQ(util::getFSII2CSearchKeys(
441 "/sys/devices/platform/ahb/ahb:apb/1e79b000.fsi/"
442 "fsi-master/fsi0/slave@00:00/00:00:00:0a/fsi-master/fsi1/"
443 "slave@01:00/01:01:00:03/i2c-211/211-0055"),
444 (std::tuple{"0-1", std::tuple{11, 0x55}}));
445 }
446
447 {
448 EXPECT_THROW(util::getFSII2CSearchKeys("/sys/some/bad/path"),
449 std::invalid_argument);
450 }
451}
452
453// Test getting FSI-SPI search keys
454TEST_F(DeviceCalloutsTest, getFSISPISearchKeysTest)
455{
456 {
457 // Link 0-8 SPI 9
458 EXPECT_EQ(
459 util::getFSISPISearchKeys(
460 "/sys/devices/platform/ahb/ahb:apb/1e79b000.fsi/fsi-master/"
461 "fsi0/slave@00:00/00:00:00:0a/fsi-master/fsi1/slave@08:00/"
462 "01:03:00:04/spi_master/spi9/spi9.0/spi9.00/nvmem"),
463 (std::tuple{"0-8", 9}));
464 }
465
466 {
467 EXPECT_THROW(util::getFSISPISearchKeys("/sys/some/bad/path"),
468 std::invalid_argument);
469 }
470}
Matt Spinler6bc74ae2020-06-03 15:13:59 -0500471
472TEST_F(DeviceCalloutsTest, getCalloutsTest)
473{
474 std::vector<std::string> systemTypes{"systemA", "systemB"};
475
476 // A really bogus path
477 {
478 EXPECT_THROW(getCallouts("/bad/path", systemTypes),
479 std::invalid_argument);
480 }
481
482 // I2C
483 {
484 auto callouts = getCallouts(
485 "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/"
486 "1e78a340.i2c-bus/i2c-14/14-0072",
487 systemTypes);
488
489 std::vector<Callout> expected{
490 {"H", "P1-C19", "/chassis/motherboard/cpu0", "core0",
491 "I2C: bus: 14 address: 114 dest: proc-0 target"},
492 {"M", "P1", "/chassis/motherboard", "", ""}};
493
494 EXPECT_EQ(callouts, expected);
495
496 // Use the bus/address API instead of the device path one
497 callouts = getI2CCallouts(14, 0x72, systemTypes);
498 EXPECT_EQ(callouts, expected);
499
500 // I2C address not in JSON
501 EXPECT_THROW(
502 getCallouts(
503 "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/"
504 "1e78a340.i2c-bus/i2c-14/14-0099",
505 systemTypes),
506 std::invalid_argument);
507
508 // A bad JSON entry, missing the location code
509 EXPECT_THROW(
510 getCallouts(
511 "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/"
512 "1e78a340.i2c-bus/i2c-0/0-005a",
513 systemTypes),
514 std::runtime_error);
515 }
516
517 // FSI
518 {
519 auto callouts = getCallouts(
520 "/sys/devices/platform/ahb/ahb:apb/1e79b000.fsi/"
521 "fsi-master/fsi0/slave@00:00/00:00:00:0a/fsi-master/fsi1/"
522 "slave@01:00/01:01:00:06/sbefifo2-dev0/occ-hwmon.2",
523 systemTypes);
524
525 std::vector<Callout> expected{{"H", "P1-C19",
526 "/chassis/motherboard/cpu0", "core",
527 "FSI: links: 0-1 dest: proc-0 target"}};
528
529 EXPECT_EQ(callouts, expected);
530
531 // link 9-1 not in JSON
532 EXPECT_THROW(
533 getCallouts(
534 "/sys/devices/platform/ahb/ahb:apb/1e79b000.fsi/"
535 "fsi-master/fsi0/slave@09:00/00:00:00:0a/fsi-master/fsi1/"
536 "slave@01:00/01:01:00:06/sbefifo2-dev0/occ-hwmon.2",
537 systemTypes),
538 std::invalid_argument);
539 }
540
541 // FSI-I2C
542 {
543 auto callouts = getCallouts(
544 "/sys/devices/platform/ahb/ahb:apb/1e79b000.fsi/"
545 "fsi-master/fsi0/slave@00:00/00:00:00:0a/fsi-master/fsi1/"
546 "slave@03:00/01:01:00:03/i2c-207/207-0019",
547 systemTypes);
548
549 std::vector<Callout> expected{
550 {"H", "P1-C25", "/chassis/motherboard/cpu5", "",
551 "FSI-I2C: links: 0-3 bus: 7 addr: 25 dest: proc-5 target"},
552 {"M", "P1", "/chassis/motherboard", "", ""},
553 {"L", "P2", "/chassis/motherboard/bmc", "", ""}};
554
555 EXPECT_EQ(callouts, expected);
556
557 // Bus 2 not in JSON
558 EXPECT_THROW(
559 getCallouts(
560 "/sys/devices/platform/ahb/ahb:apb/1e79b000.fsi/"
561 "fsi-master/fsi0/slave@00:00/00:00:00:0a/fsi-master/fsi1/"
562 "slave@03:00/01:01:00:03/i2c-202/202-0019",
563 systemTypes),
564 std::invalid_argument);
565 }
566
567 // FSI-SPI
568 {
569 auto callouts =
570 getCallouts("/sys/devices/platform/ahb/ahb:apb/1e79b000.fsi/"
571 "fsi-master/fsi0/slave@08:00/00:00:00:04/spi_master/"
572 "spi3/spi3.0/spi3.00/nvmem",
573 systemTypes);
574
575 std::vector<Callout> expected{
576 {"H", "P1-C19", "/chassis/motherboard/cpu0", "",
577 "FSI-SPI: links: 8 bus: 3 dest: proc-0 target"}};
578
579 EXPECT_EQ(callouts, expected);
580
581 // Bus 7 not in the JSON
582 EXPECT_THROW(
583 getCallouts("/sys/devices/platform/ahb/ahb:apb/1e79b000.fsi/"
584 "fsi-master/fsi0/slave@08:00/00:00:00:04/spi_master/"
585 "spi7/spi7.0/spi7.00/nvmem",
586 systemTypes),
587 std::invalid_argument);
588 }
589}