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