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 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 */ 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 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 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>> 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 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 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 */ 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 */ 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 */ 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> 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> 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> 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> 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 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 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> 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