xref: /openbmc/phosphor-logging/extensions/openpower-pels/device_callouts.cpp (revision 70e8a11beb0b2783f609872a197b1dbca6636009)
118c42b0fSMatt Spinler /**
218c42b0fSMatt Spinler  * Copyright © 2020 IBM Corporation
318c42b0fSMatt Spinler  *
418c42b0fSMatt Spinler  * Licensed under the Apache License, Version 2.0 (the "License");
518c42b0fSMatt Spinler  * you may not use this file except in compliance with the License.
618c42b0fSMatt Spinler  * You may obtain a copy of the License at
718c42b0fSMatt Spinler  *
818c42b0fSMatt Spinler  *     http://www.apache.org/licenses/LICENSE-2.0
918c42b0fSMatt Spinler  *
1018c42b0fSMatt Spinler  * Unless required by applicable law or agreed to in writing, software
1118c42b0fSMatt Spinler  * distributed under the License is distributed on an "AS IS" BASIS,
1218c42b0fSMatt Spinler  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1318c42b0fSMatt Spinler  * See the License for the specific language governing permissions and
1418c42b0fSMatt Spinler  * limitations under the License.
1518c42b0fSMatt Spinler  */
1618c42b0fSMatt Spinler #include "device_callouts.hpp"
1718c42b0fSMatt Spinler 
1818c42b0fSMatt Spinler #include "paths.hpp"
1918c42b0fSMatt Spinler 
205bc26533SArya K Padman #include <phosphor-logging/lg2.hpp>
212544b419SPatrick Williams 
222544b419SPatrick Williams #include <fstream>
2318c42b0fSMatt Spinler #include <regex>
2418c42b0fSMatt Spinler 
2518c42b0fSMatt Spinler namespace openpower::pels::device_callouts
2618c42b0fSMatt Spinler {
2718c42b0fSMatt Spinler 
2818c42b0fSMatt Spinler constexpr auto debugFilePath = "/etc/phosphor-logging/";
2918c42b0fSMatt Spinler constexpr auto calloutFileSuffix = "_dev_callouts.json";
3018c42b0fSMatt Spinler 
3118c42b0fSMatt Spinler namespace fs = std::filesystem;
3218c42b0fSMatt Spinler 
3318c42b0fSMatt Spinler namespace util
3418c42b0fSMatt Spinler {
3518c42b0fSMatt Spinler 
getJSONFilename(const std::vector<std::string> & compatibleList)3618c42b0fSMatt Spinler fs::path getJSONFilename(const std::vector<std::string>& compatibleList)
3718c42b0fSMatt Spinler {
380f8a7382SMatt Spinler     std::vector<std::string> names{compatibleList};
3918c42b0fSMatt Spinler     auto basePath = getPELReadOnlyDataPath();
4018c42b0fSMatt Spinler     fs::path fullPath;
4118c42b0fSMatt Spinler 
4218c42b0fSMatt Spinler     // Find an entry in the list of compatible system names that
4318c42b0fSMatt Spinler     // matches a filename we have.
4418c42b0fSMatt Spinler 
450f8a7382SMatt Spinler     // Also match on just _dev_callouts.json, which may be present
460f8a7382SMatt Spinler     // when it's known that compatibleList won't be correct.
470f8a7382SMatt Spinler     names.push_back("");
480f8a7382SMatt Spinler 
490f8a7382SMatt Spinler     for (const auto& name : names)
5018c42b0fSMatt Spinler     {
5118c42b0fSMatt Spinler         fs::path filename = name + calloutFileSuffix;
5218c42b0fSMatt Spinler 
5318c42b0fSMatt Spinler         // Check the debug path first
5418c42b0fSMatt Spinler         fs::path path{fs::path{debugFilePath} / filename};
5518c42b0fSMatt Spinler 
5618c42b0fSMatt Spinler         if (fs::exists(path))
5718c42b0fSMatt Spinler         {
585bc26533SArya K Padman             lg2::info("Found device callout debug file");
5918c42b0fSMatt Spinler             fullPath = path;
6018c42b0fSMatt Spinler             break;
6118c42b0fSMatt Spinler         }
6218c42b0fSMatt Spinler 
6318c42b0fSMatt Spinler         path = basePath / filename;
6418c42b0fSMatt Spinler 
6518c42b0fSMatt Spinler         if (fs::exists(path))
6618c42b0fSMatt Spinler         {
6718c42b0fSMatt Spinler             fullPath = path;
6818c42b0fSMatt Spinler             break;
6918c42b0fSMatt Spinler         }
7018c42b0fSMatt Spinler     }
7118c42b0fSMatt Spinler 
7218c42b0fSMatt Spinler     if (fullPath.empty())
7318c42b0fSMatt Spinler     {
7418c42b0fSMatt Spinler         throw std::invalid_argument(
7518c42b0fSMatt Spinler             "No JSON dev path callout file for this system");
7618c42b0fSMatt Spinler     }
7718c42b0fSMatt Spinler 
7818c42b0fSMatt Spinler     return fullPath;
7918c42b0fSMatt Spinler }
8018c42b0fSMatt Spinler 
8118c42b0fSMatt Spinler /**
8218c42b0fSMatt Spinler  * @brief Reads the callout JSON into an object based on the
8318c42b0fSMatt Spinler  *        compatible system names list.
8418c42b0fSMatt Spinler  *
8518c42b0fSMatt Spinler  * @param[in] compatibleList - The list of compatible names for this
8618c42b0fSMatt Spinler  *                             system.
8718c42b0fSMatt Spinler  *
8818c42b0fSMatt Spinler  * @return nlohmann::json - The JSON object
8918c42b0fSMatt Spinler  */
loadJSON(const std::vector<std::string> & compatibleList)9018c42b0fSMatt Spinler nlohmann::json loadJSON(const std::vector<std::string>& compatibleList)
9118c42b0fSMatt Spinler {
9218c42b0fSMatt Spinler     auto filename = getJSONFilename(compatibleList);
9318c42b0fSMatt Spinler     std::ifstream file{filename};
9418c42b0fSMatt Spinler     return nlohmann::json::parse(file);
9518c42b0fSMatt Spinler }
9618c42b0fSMatt Spinler 
getI2CSearchKeys(const std::string & devPath)9744c0a643SMatt Spinler std::tuple<size_t, uint8_t> getI2CSearchKeys(const std::string& devPath)
9844c0a643SMatt Spinler {
9944c0a643SMatt Spinler     std::smatch match;
10044c0a643SMatt Spinler 
10144c0a643SMatt Spinler     // Look for i2c-A/A-00BB
10244c0a643SMatt Spinler     // where A = bus number and BB = address
10344c0a643SMatt Spinler     std::regex regex{"i2c-[0-9]+/([0-9]+)-00([0-9a-f]{2})"};
10444c0a643SMatt Spinler 
10544c0a643SMatt Spinler     regex_search(devPath, match, regex);
10644c0a643SMatt Spinler 
10744c0a643SMatt Spinler     if (match.size() != 3)
10844c0a643SMatt Spinler     {
10944c0a643SMatt Spinler         std::string msg = "Could not get I2C bus and address from " + devPath;
11044c0a643SMatt Spinler         throw std::invalid_argument{msg.c_str()};
11144c0a643SMatt Spinler     }
11244c0a643SMatt Spinler 
11344c0a643SMatt Spinler     size_t bus = std::stoul(match[1].str(), nullptr, 0);
11444c0a643SMatt Spinler 
11544c0a643SMatt Spinler     // An I2C bus on a CFAM has everything greater than the 10s digit
11644c0a643SMatt Spinler     // as the CFAM number, so strip it off.  Like:
11744c0a643SMatt Spinler     //    112 = cfam1 bus 12
11844c0a643SMatt Spinler     //    1001 = cfam10 bus 1
11944c0a643SMatt Spinler     bus = bus % 100;
12044c0a643SMatt Spinler 
12144c0a643SMatt Spinler     uint8_t address = std::stoul(match[2].str(), nullptr, 16);
12244c0a643SMatt Spinler 
12344c0a643SMatt Spinler     return {bus, address};
12444c0a643SMatt Spinler }
12544c0a643SMatt Spinler 
getFSISearchKeys(const std::string & devPath)12644c0a643SMatt Spinler std::string getFSISearchKeys(const std::string& devPath)
12744c0a643SMatt Spinler {
12844c0a643SMatt Spinler     std::string links;
12944c0a643SMatt Spinler     std::smatch match;
13044c0a643SMatt Spinler     auto search = devPath;
13144c0a643SMatt Spinler 
13244c0a643SMatt Spinler     // Look for slave@XX:
13344c0a643SMatt Spinler     // where XX = link number in hex
13444c0a643SMatt Spinler     std::regex regex{"slave@([0-9a-f]{2}):"};
13544c0a643SMatt Spinler 
13644c0a643SMatt Spinler     // Find all links in the path and separate them with hyphens.
13744c0a643SMatt Spinler     while (regex_search(search, match, regex))
13844c0a643SMatt Spinler     {
13944c0a643SMatt Spinler         // Convert to an int first to handle a hex number like "0a"
14044c0a643SMatt Spinler         // though in reality there won't be more than links 0 - 9.
14144c0a643SMatt Spinler         auto linkNum = std::stoul(match[1].str(), nullptr, 16);
14244c0a643SMatt Spinler         links += std::to_string(linkNum) + '-';
14344c0a643SMatt Spinler 
14444c0a643SMatt Spinler         search = match.suffix();
14544c0a643SMatt Spinler     }
14644c0a643SMatt Spinler 
14744c0a643SMatt Spinler     if (links.empty())
14844c0a643SMatt Spinler     {
14944c0a643SMatt Spinler         std::string msg = "Could not get FSI links from " + devPath;
15044c0a643SMatt Spinler         throw std::invalid_argument{msg.c_str()};
15144c0a643SMatt Spinler     }
15244c0a643SMatt Spinler 
15344c0a643SMatt Spinler     // Remove the trailing '-'
15444c0a643SMatt Spinler     links.pop_back();
15544c0a643SMatt Spinler 
15644c0a643SMatt Spinler     return links;
15744c0a643SMatt Spinler }
15844c0a643SMatt Spinler 
15944c0a643SMatt Spinler std::tuple<std::string, std::tuple<size_t, uint8_t>>
getFSII2CSearchKeys(const std::string & devPath)16044c0a643SMatt Spinler     getFSII2CSearchKeys(const std::string& devPath)
16144c0a643SMatt Spinler {
16244c0a643SMatt Spinler     // This combines the FSI and i2C search keys
16344c0a643SMatt Spinler 
16444c0a643SMatt Spinler     auto links = getFSISearchKeys(devPath);
16544c0a643SMatt Spinler     auto busAndAddr = getI2CSearchKeys(devPath);
16644c0a643SMatt Spinler 
16744c0a643SMatt Spinler     return {std::move(links), std::move(busAndAddr)};
16844c0a643SMatt Spinler }
16944c0a643SMatt Spinler 
getSPISearchKeys(const std::string & devPath)17044c0a643SMatt Spinler size_t getSPISearchKeys(const std::string& devPath)
17144c0a643SMatt Spinler {
17244c0a643SMatt Spinler     std::smatch match;
17344c0a643SMatt Spinler 
17444c0a643SMatt Spinler     // Look for spi_master/spiX/ where X is the SPI bus/port number
17544c0a643SMatt Spinler     // Note: This doesn't distinguish between multiple chips on
17644c0a643SMatt Spinler     // the same port as no need for it yet.
17744c0a643SMatt Spinler     std::regex regex{"spi_master/spi(\\d+)/"};
17844c0a643SMatt Spinler 
17944c0a643SMatt Spinler     regex_search(devPath, match, regex);
18044c0a643SMatt Spinler 
18144c0a643SMatt Spinler     if (match.size() != 2)
18244c0a643SMatt Spinler     {
18344c0a643SMatt Spinler         std::string msg = "Could not get SPI bus from " + devPath;
18444c0a643SMatt Spinler         throw std::invalid_argument{msg.c_str()};
18544c0a643SMatt Spinler     }
18644c0a643SMatt Spinler 
18744c0a643SMatt Spinler     size_t port = std::stoul(match[1].str());
18844c0a643SMatt Spinler 
18944c0a643SMatt Spinler     return port;
19044c0a643SMatt Spinler }
19144c0a643SMatt Spinler 
getFSISPISearchKeys(const std::string & devPath)19244c0a643SMatt Spinler std::tuple<std::string, size_t> getFSISPISearchKeys(const std::string& devPath)
19344c0a643SMatt Spinler {
19444c0a643SMatt Spinler     // Combine the FSI and SPI search keys.
19544c0a643SMatt Spinler     auto links = getFSISearchKeys(devPath);
19644c0a643SMatt Spinler     auto bus = getSPISearchKeys(devPath);
19744c0a643SMatt Spinler 
19844c0a643SMatt Spinler     return {std::move(links), std::move(bus)};
19944c0a643SMatt Spinler }
20044c0a643SMatt Spinler 
2016bc74ae6SMatt Spinler /**
2026bc74ae6SMatt Spinler  * @brief Pull the callouts out of the JSON callout array passed in
2036bc74ae6SMatt Spinler  *
2046bc74ae6SMatt Spinler  * Create a vector of Callout objects based on the JSON.
2056bc74ae6SMatt Spinler  *
2066bc74ae6SMatt Spinler  * This will also fill in the 'debug' member on the first callout
2076bc74ae6SMatt Spinler  * in the list, which could contain things like the I2C address and
2086bc74ae6SMatt Spinler  * bus extracted from the device path.
2096bc74ae6SMatt Spinler  *
2106bc74ae6SMatt Spinler  * The callouts are in the order they should be added to the PEL.
2116bc74ae6SMatt Spinler  *
2126bc74ae6SMatt Spinler  * @param[in] calloutJSON - The Callouts JSON array to extract from
2136bc74ae6SMatt Spinler  * @param[in] debug - The debug message to add to the first callout
2146bc74ae6SMatt Spinler  *
2156bc74ae6SMatt Spinler  * @return std::vector<Callout> - The Callout objects
2166bc74ae6SMatt Spinler  */
extractCallouts(const nlohmann::json & calloutJSON,const std::string & debug)2176bc74ae6SMatt Spinler std::vector<Callout> extractCallouts(const nlohmann::json& calloutJSON,
2186bc74ae6SMatt Spinler                                      const std::string& debug)
2196bc74ae6SMatt Spinler {
2206bc74ae6SMatt Spinler     std::vector<Callout> callouts;
2216bc74ae6SMatt Spinler     bool addDebug = true;
2226bc74ae6SMatt Spinler 
2236bc74ae6SMatt Spinler     // The JSON element passed in is the array of callouts
2246bc74ae6SMatt Spinler     if (!calloutJSON.is_array())
2256bc74ae6SMatt Spinler     {
2266bc74ae6SMatt Spinler         throw std::runtime_error(
2276bc74ae6SMatt Spinler             "Dev path callout JSON entry doesn't contain a 'Callouts' array");
2286bc74ae6SMatt Spinler     }
2296bc74ae6SMatt Spinler 
2306bc74ae6SMatt Spinler     for (auto& callout : calloutJSON)
2316bc74ae6SMatt Spinler     {
2326bc74ae6SMatt Spinler         Callout c;
2336bc74ae6SMatt Spinler 
2346bc74ae6SMatt Spinler         // Add any debug data to the first callout
2356bc74ae6SMatt Spinler         if (addDebug && !debug.empty())
2366bc74ae6SMatt Spinler         {
2376bc74ae6SMatt Spinler             addDebug = false;
2386bc74ae6SMatt Spinler             c.debug = debug;
2396bc74ae6SMatt Spinler         }
2406bc74ae6SMatt Spinler 
2416bc74ae6SMatt Spinler         try
2426bc74ae6SMatt Spinler         {
2436bc74ae6SMatt Spinler             c.locationCode = callout.at("LocationCode").get<std::string>();
2446bc74ae6SMatt Spinler             c.name = callout.at("Name").get<std::string>();
2456bc74ae6SMatt Spinler             c.priority = callout.at("Priority").get<std::string>();
2466bc74ae6SMatt Spinler 
2476bc74ae6SMatt Spinler             if (callout.contains("MRU"))
2486bc74ae6SMatt Spinler             {
2496bc74ae6SMatt Spinler                 c.mru = callout.at("MRU").get<std::string>();
2506bc74ae6SMatt Spinler             }
2516bc74ae6SMatt Spinler         }
2526bc74ae6SMatt Spinler         catch (const nlohmann::json::out_of_range& e)
2536bc74ae6SMatt Spinler         {
2546bc74ae6SMatt Spinler             std::string msg =
2556bc74ae6SMatt Spinler                 "Callout entry missing either LocationCode, Name, or Priority "
2566bc74ae6SMatt Spinler                 "properties: " +
2576bc74ae6SMatt Spinler                 callout.dump();
2586bc74ae6SMatt Spinler             throw std::runtime_error(msg.c_str());
2596bc74ae6SMatt Spinler         }
2606bc74ae6SMatt Spinler 
2616bc74ae6SMatt Spinler         callouts.push_back(c);
2626bc74ae6SMatt Spinler     }
2636bc74ae6SMatt Spinler 
2646bc74ae6SMatt Spinler     return callouts;
2656bc74ae6SMatt Spinler }
2666bc74ae6SMatt Spinler 
2676bc74ae6SMatt Spinler /**
2686bc74ae6SMatt Spinler  * @brief Looks up the callouts in the JSON using the I2C keys.
2696bc74ae6SMatt Spinler  *
2706bc74ae6SMatt Spinler  * @param[in] i2cBus - The I2C bus
2716bc74ae6SMatt Spinler  * @param[in] i2cAddress - The I2C address
2726bc74ae6SMatt Spinler  * @param[in] calloutJSON - The JSON containing the callouts
2736bc74ae6SMatt Spinler  *
2746bc74ae6SMatt Spinler  * @return std::vector<Callout> - The callouts
2756bc74ae6SMatt Spinler  */
calloutI2C(size_t i2cBus,uint8_t i2cAddress,const nlohmann::json & calloutJSON)276075c7923SPatrick Williams std::vector<device_callouts::Callout> calloutI2C(
277075c7923SPatrick Williams     size_t i2cBus, uint8_t i2cAddress, const nlohmann::json& calloutJSON)
27818c42b0fSMatt Spinler {
2796bc74ae6SMatt Spinler     auto busString = std::to_string(i2cBus);
2806bc74ae6SMatt Spinler     auto addrString = std::to_string(i2cAddress);
2816bc74ae6SMatt Spinler 
2826bc74ae6SMatt Spinler     try
2836bc74ae6SMatt Spinler     {
2846bc74ae6SMatt Spinler         const auto& callouts =
2856bc74ae6SMatt Spinler             calloutJSON.at("I2C").at(busString).at(addrString).at("Callouts");
2866bc74ae6SMatt Spinler 
2876bc74ae6SMatt Spinler         auto dest = calloutJSON.at("I2C")
2886bc74ae6SMatt Spinler                         .at(busString)
2896bc74ae6SMatt Spinler                         .at(addrString)
2906bc74ae6SMatt Spinler                         .at("Dest")
2916bc74ae6SMatt Spinler                         .get<std::string>();
2926bc74ae6SMatt Spinler 
2936bc74ae6SMatt Spinler         std::string msg = "I2C: bus: " + busString + " address: " + addrString +
2946bc74ae6SMatt Spinler                           " dest: " + dest;
2956bc74ae6SMatt Spinler 
2966bc74ae6SMatt Spinler         return extractCallouts(callouts, msg);
2976bc74ae6SMatt Spinler     }
2986bc74ae6SMatt Spinler     catch (const nlohmann::json::out_of_range& e)
2996bc74ae6SMatt Spinler     {
3006bc74ae6SMatt Spinler         std::string msg = "Problem looking up I2C callouts on " + busString +
3016bc74ae6SMatt Spinler                           " " + addrString + ": " + std::string{e.what()};
3026bc74ae6SMatt Spinler         throw std::invalid_argument(msg.c_str());
3036bc74ae6SMatt Spinler     }
30418c42b0fSMatt Spinler }
30518c42b0fSMatt Spinler 
3066bc74ae6SMatt Spinler /**
3076bc74ae6SMatt Spinler  * @brief Looks up the callouts in the JSON for this I2C path.
3086bc74ae6SMatt Spinler  *
3096bc74ae6SMatt Spinler  * @param[in] devPath - The device path
3106bc74ae6SMatt Spinler  * @param[in] calloutJSON - The JSON containing the callouts
3116bc74ae6SMatt Spinler  *
3126bc74ae6SMatt Spinler  * @return std::vector<Callout> - The callouts
3136bc74ae6SMatt Spinler  */
calloutI2CUsingPath(const std::string & devPath,const nlohmann::json & calloutJSON)314075c7923SPatrick Williams std::vector<device_callouts::Callout> calloutI2CUsingPath(
315075c7923SPatrick Williams     const std::string& devPath, const nlohmann::json& calloutJSON)
3166bc74ae6SMatt Spinler {
3176bc74ae6SMatt Spinler     auto [bus, address] = getI2CSearchKeys(devPath);
3186bc74ae6SMatt Spinler 
3196bc74ae6SMatt Spinler     return calloutI2C(bus, address, calloutJSON);
3206bc74ae6SMatt Spinler }
3216bc74ae6SMatt Spinler 
3226bc74ae6SMatt Spinler /**
3236bc74ae6SMatt Spinler  * @brief Looks up the callouts in the JSON for this FSI path.
3246bc74ae6SMatt Spinler  *
3256bc74ae6SMatt Spinler  * @param[in] devPath - The device path
3266bc74ae6SMatt Spinler  * @param[in] calloutJSON - The JSON containing the callouts
3276bc74ae6SMatt Spinler  *
3286bc74ae6SMatt Spinler  * @return std::vector<Callout> - The callouts
3296bc74ae6SMatt Spinler  */
3306bc74ae6SMatt Spinler std::vector<device_callouts::Callout>
calloutFSI(const std::string & devPath,const nlohmann::json & calloutJSON)3316bc74ae6SMatt Spinler     calloutFSI(const std::string& devPath, const nlohmann::json& calloutJSON)
3326bc74ae6SMatt Spinler {
3336bc74ae6SMatt Spinler     auto links = getFSISearchKeys(devPath);
3346bc74ae6SMatt Spinler 
3356bc74ae6SMatt Spinler     try
3366bc74ae6SMatt Spinler     {
3376bc74ae6SMatt Spinler         const auto& callouts = calloutJSON.at("FSI").at(links).at("Callouts");
3386bc74ae6SMatt Spinler 
3396bc74ae6SMatt Spinler         auto dest =
3406bc74ae6SMatt Spinler             calloutJSON.at("FSI").at(links).at("Dest").get<std::string>();
3416bc74ae6SMatt Spinler 
3426bc74ae6SMatt Spinler         std::string msg = "FSI: links: " + links + " dest: " + dest;
3436bc74ae6SMatt Spinler 
3446bc74ae6SMatt Spinler         return extractCallouts(callouts, msg);
3456bc74ae6SMatt Spinler     }
3466bc74ae6SMatt Spinler     catch (const nlohmann::json::out_of_range& e)
3476bc74ae6SMatt Spinler     {
3486bc74ae6SMatt Spinler         std::string msg = "Problem looking up FSI callouts on " + links + ": " +
3496bc74ae6SMatt Spinler                           std::string{e.what()};
3506bc74ae6SMatt Spinler         throw std::invalid_argument(msg.c_str());
3516bc74ae6SMatt Spinler     }
3526bc74ae6SMatt Spinler }
3536bc74ae6SMatt Spinler 
3546bc74ae6SMatt Spinler /**
3556bc74ae6SMatt Spinler  * @brief Looks up the callouts in the JSON for this FSI-I2C path.
3566bc74ae6SMatt Spinler  *
3576bc74ae6SMatt Spinler  * @param[in] devPath - The device path
3586bc74ae6SMatt Spinler  * @param[in] calloutJSON - The JSON containing the callouts
3596bc74ae6SMatt Spinler  *
3606bc74ae6SMatt Spinler  * @return std::vector<Callout> - The callouts
3616bc74ae6SMatt Spinler  */
3626bc74ae6SMatt Spinler std::vector<device_callouts::Callout>
calloutFSII2C(const std::string & devPath,const nlohmann::json & calloutJSON)3636bc74ae6SMatt Spinler     calloutFSII2C(const std::string& devPath, const nlohmann::json& calloutJSON)
3646bc74ae6SMatt Spinler {
3656bc74ae6SMatt Spinler     auto linksAndI2C = getFSII2CSearchKeys(devPath);
3666bc74ae6SMatt Spinler     auto links = std::get<std::string>(linksAndI2C);
3676bc74ae6SMatt Spinler     const auto& busAndAddr = std::get<1>(linksAndI2C);
3686bc74ae6SMatt Spinler 
3696bc74ae6SMatt Spinler     auto busString = std::to_string(std::get<size_t>(busAndAddr));
3706bc74ae6SMatt Spinler     auto addrString = std::to_string(std::get<uint8_t>(busAndAddr));
3716bc74ae6SMatt Spinler 
3726bc74ae6SMatt Spinler     try
3736bc74ae6SMatt Spinler     {
3746bc74ae6SMatt Spinler         auto& callouts = calloutJSON.at("FSI-I2C")
3756bc74ae6SMatt Spinler                              .at(links)
3766bc74ae6SMatt Spinler                              .at(busString)
3776bc74ae6SMatt Spinler                              .at(addrString)
3786bc74ae6SMatt Spinler                              .at("Callouts");
3796bc74ae6SMatt Spinler 
3806bc74ae6SMatt Spinler         auto dest = calloutJSON.at("FSI-I2C")
3816bc74ae6SMatt Spinler                         .at(links)
3826bc74ae6SMatt Spinler                         .at(busString)
3836bc74ae6SMatt Spinler                         .at(addrString)
3846bc74ae6SMatt Spinler                         .at("Dest")
3856bc74ae6SMatt Spinler                         .get<std::string>();
3866bc74ae6SMatt Spinler 
3876bc74ae6SMatt Spinler         std::string msg = "FSI-I2C: links: " + links + " bus: " + busString +
3886bc74ae6SMatt Spinler                           " addr: " + addrString + " dest: " + dest;
3896bc74ae6SMatt Spinler 
3906bc74ae6SMatt Spinler         return extractCallouts(callouts, msg);
3916bc74ae6SMatt Spinler     }
3926bc74ae6SMatt Spinler     catch (const nlohmann::json::out_of_range& e)
3936bc74ae6SMatt Spinler     {
3946bc74ae6SMatt Spinler         std::string msg = "Problem looking up FSI-I2C callouts on " + links +
3956bc74ae6SMatt Spinler                           " " + busString + " " + addrString + ": " + e.what();
3966bc74ae6SMatt Spinler         throw std::invalid_argument(msg.c_str());
3976bc74ae6SMatt Spinler     }
3986bc74ae6SMatt Spinler }
3996bc74ae6SMatt Spinler 
4006bc74ae6SMatt Spinler /**
4016bc74ae6SMatt Spinler  * @brief Looks up the callouts in the JSON for this FSI-SPI path.
4026bc74ae6SMatt Spinler  *
4036bc74ae6SMatt Spinler  * @param[in] devPath - The device path
4046bc74ae6SMatt Spinler  * @param[in] calloutJSON - The JSON containing the callouts
4056bc74ae6SMatt Spinler  *
4066bc74ae6SMatt Spinler  * @return std::vector<Callout> - The callouts
4076bc74ae6SMatt Spinler  */
4086bc74ae6SMatt Spinler std::vector<device_callouts::Callout>
calloutFSISPI(const std::string & devPath,const nlohmann::json & calloutJSON)4096bc74ae6SMatt Spinler     calloutFSISPI(const std::string& devPath, const nlohmann::json& calloutJSON)
4106bc74ae6SMatt Spinler {
4116bc74ae6SMatt Spinler     auto linksAndSPI = getFSISPISearchKeys(devPath);
4126bc74ae6SMatt Spinler     auto links = std::get<std::string>(linksAndSPI);
4136bc74ae6SMatt Spinler     auto busString = std::to_string(std::get<size_t>(linksAndSPI));
4146bc74ae6SMatt Spinler 
4156bc74ae6SMatt Spinler     try
4166bc74ae6SMatt Spinler     {
4176bc74ae6SMatt Spinler         auto& callouts =
4186bc74ae6SMatt Spinler             calloutJSON.at("FSI-SPI").at(links).at(busString).at("Callouts");
4196bc74ae6SMatt Spinler 
4206bc74ae6SMatt Spinler         auto dest = calloutJSON.at("FSI-SPI")
4216bc74ae6SMatt Spinler                         .at(links)
4226bc74ae6SMatt Spinler                         .at(busString)
4236bc74ae6SMatt Spinler                         .at("Dest")
4246bc74ae6SMatt Spinler                         .get<std::string>();
4256bc74ae6SMatt Spinler 
4266bc74ae6SMatt Spinler         std::string msg = "FSI-SPI: links: " + links + " bus: " + busString +
4276bc74ae6SMatt Spinler                           " dest: " + dest;
4286bc74ae6SMatt Spinler 
4296bc74ae6SMatt Spinler         return extractCallouts(callouts, msg);
4306bc74ae6SMatt Spinler     }
4316bc74ae6SMatt Spinler     catch (const nlohmann::json::out_of_range& e)
4326bc74ae6SMatt Spinler     {
4336bc74ae6SMatt Spinler         std::string msg = "Problem looking up FSI-SPI callouts on " + links +
4346bc74ae6SMatt Spinler                           " " + busString + ": " + std::string{e.what()};
4356bc74ae6SMatt Spinler         throw std::invalid_argument(msg.c_str());
4366bc74ae6SMatt Spinler     }
4376bc74ae6SMatt Spinler }
4386bc74ae6SMatt Spinler 
4396bc74ae6SMatt Spinler /**
4406bc74ae6SMatt Spinler  * @brief Returns the callouts from the JSON based on the input
4416bc74ae6SMatt Spinler  *        device path.
4426bc74ae6SMatt Spinler  *
4436bc74ae6SMatt Spinler  * @param[in] devPath - The device path
4446bc74ae6SMatt Spinler  * @param[in] json - The callout JSON
4456bc74ae6SMatt Spinler  *
4466bc74ae6SMatt Spinler  * @return std::vector<Callout> - The list of callouts
4476bc74ae6SMatt Spinler  */
448075c7923SPatrick Williams std::vector<device_callouts::Callout>
findCallouts(const std::string & devPath,const nlohmann::json & json)449075c7923SPatrick Williams     findCallouts(const std::string& devPath, const nlohmann::json& json)
45018c42b0fSMatt Spinler {
45118c42b0fSMatt Spinler     std::vector<Callout> callouts;
452a307089cSMatt Spinler     fs::path path;
45318c42b0fSMatt Spinler 
454a307089cSMatt Spinler     // Gives the /sys/devices/platform/ path
455a307089cSMatt Spinler     try
456a307089cSMatt Spinler     {
457a307089cSMatt Spinler         path = fs::canonical(devPath);
458a307089cSMatt Spinler     }
459a307089cSMatt Spinler     catch (const fs::filesystem_error& e)
460a307089cSMatt Spinler     {
461a307089cSMatt Spinler         // Path not there, still try to do the callout
462a307089cSMatt Spinler         path = devPath;
463a307089cSMatt Spinler     }
464a307089cSMatt Spinler 
465a307089cSMatt Spinler     switch (util::getCalloutType(path))
466a307089cSMatt Spinler     {
467a307089cSMatt Spinler         case util::CalloutType::i2c:
4686bc74ae6SMatt Spinler             callouts = calloutI2CUsingPath(path, json);
469a307089cSMatt Spinler             break;
470a307089cSMatt Spinler         case util::CalloutType::fsi:
4716bc74ae6SMatt Spinler             callouts = calloutFSI(path, json);
472a307089cSMatt Spinler             break;
473a307089cSMatt Spinler         case util::CalloutType::fsii2c:
4746bc74ae6SMatt Spinler             callouts = calloutFSII2C(path, json);
475a307089cSMatt Spinler             break;
476a307089cSMatt Spinler         case util::CalloutType::fsispi:
4776bc74ae6SMatt Spinler             callouts = calloutFSISPI(path, json);
478a307089cSMatt Spinler             break;
479a307089cSMatt Spinler         default:
480075c7923SPatrick Williams             std::string msg =
481075c7923SPatrick Williams                 "Could not get callout type from device path: " + path.string();
482a307089cSMatt Spinler             throw std::invalid_argument{msg.c_str()};
483a307089cSMatt Spinler             break;
484a307089cSMatt Spinler     }
48518c42b0fSMatt Spinler 
48618c42b0fSMatt Spinler     return callouts;
48718c42b0fSMatt Spinler }
48818c42b0fSMatt Spinler 
getCalloutType(const std::string & devPath)489a307089cSMatt Spinler CalloutType getCalloutType(const std::string& devPath)
490a307089cSMatt Spinler {
491a307089cSMatt Spinler     if ((devPath.find("fsi-master") != std::string::npos) &&
492a307089cSMatt Spinler         (devPath.find("i2c-") != std::string::npos))
493a307089cSMatt Spinler     {
494a307089cSMatt Spinler         return CalloutType::fsii2c;
495a307089cSMatt Spinler     }
496a307089cSMatt Spinler 
497a307089cSMatt Spinler     if ((devPath.find("fsi-master") != std::string::npos) &&
498a307089cSMatt Spinler         (devPath.find("spi") != std::string::npos))
499a307089cSMatt Spinler     {
500a307089cSMatt Spinler         return CalloutType::fsispi;
501a307089cSMatt Spinler     }
502a307089cSMatt Spinler 
503a307089cSMatt Spinler     // Treat anything else FSI related as plain FSI
504a307089cSMatt Spinler     if (devPath.find("fsi-master") != std::string::npos)
505a307089cSMatt Spinler     {
506a307089cSMatt Spinler         return CalloutType::fsi;
507a307089cSMatt Spinler     }
508a307089cSMatt Spinler 
509*70e8a11bSMatt Spinler     if (devPath.find("i2c-") != std::string::npos)
510a307089cSMatt Spinler     {
511a307089cSMatt Spinler         return CalloutType::i2c;
512a307089cSMatt Spinler     }
513a307089cSMatt Spinler 
514a307089cSMatt Spinler     return CalloutType::unknown;
515a307089cSMatt Spinler }
516a307089cSMatt Spinler 
51718c42b0fSMatt Spinler } // namespace util
51818c42b0fSMatt Spinler 
getCallouts(const std::string & devPath,const std::vector<std::string> & compatibleList)51918c42b0fSMatt Spinler std::vector<Callout> getCallouts(const std::string& devPath,
52018c42b0fSMatt Spinler                                  const std::vector<std::string>& compatibleList)
52118c42b0fSMatt Spinler {
52218c42b0fSMatt Spinler     auto json = util::loadJSON(compatibleList);
52318c42b0fSMatt Spinler     return util::findCallouts(devPath, json);
52418c42b0fSMatt Spinler }
52518c42b0fSMatt Spinler 
52618c42b0fSMatt Spinler std::vector<Callout>
getI2CCallouts(size_t i2cBus,uint8_t i2cAddress,const std::vector<std::string> & compatibleList)52718c42b0fSMatt Spinler     getI2CCallouts(size_t i2cBus, uint8_t i2cAddress,
52818c42b0fSMatt Spinler                    const std::vector<std::string>& compatibleList)
52918c42b0fSMatt Spinler {
53018c42b0fSMatt Spinler     auto json = util::loadJSON(compatibleList);
53118c42b0fSMatt Spinler     return util::calloutI2C(i2cBus, i2cAddress, json);
53218c42b0fSMatt Spinler }
53318c42b0fSMatt Spinler 
53418c42b0fSMatt Spinler } // namespace openpower::pels::device_callouts
535