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