114572cf4SShawn McCarney /**
214572cf4SShawn McCarney * Copyright © 2024 IBM Corporation
314572cf4SShawn McCarney *
414572cf4SShawn McCarney * Licensed under the Apache License, Version 2.0 (the "License");
514572cf4SShawn McCarney * you may not use this file except in compliance with the License.
614572cf4SShawn McCarney * You may obtain a copy of the License at
714572cf4SShawn McCarney *
814572cf4SShawn McCarney * http://www.apache.org/licenses/LICENSE-2.0
914572cf4SShawn McCarney *
1014572cf4SShawn McCarney * Unless required by applicable law or agreed to in writing, software
1114572cf4SShawn McCarney * distributed under the License is distributed on an "AS IS" BASIS,
1214572cf4SShawn McCarney * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1314572cf4SShawn McCarney * See the License for the specific language governing permissions and
1414572cf4SShawn McCarney * limitations under the License.
1514572cf4SShawn McCarney */
1623dee383SShawn McCarney #include "config.h"
1723dee383SShawn McCarney
1814572cf4SShawn McCarney #include "utils.hpp"
1914572cf4SShawn McCarney
2014572cf4SShawn McCarney #include "utility.hpp"
2114572cf4SShawn McCarney
22*72e584c5SAnwaar Hadi #include <phosphor-logging/lg2.hpp>
2314572cf4SShawn McCarney #include <xyz/openbmc_project/Common/Device/error.hpp>
2414572cf4SShawn McCarney
2523dee383SShawn McCarney #include <cassert>
2614572cf4SShawn McCarney #include <exception>
2723dee383SShawn McCarney #include <filesystem>
2823dee383SShawn McCarney #include <iomanip>
2923dee383SShawn McCarney #include <ios>
3014572cf4SShawn McCarney #include <iostream>
3114572cf4SShawn McCarney #include <regex>
3223dee383SShawn McCarney #include <sstream>
3314572cf4SShawn McCarney #include <stdexcept>
3414572cf4SShawn McCarney
3514572cf4SShawn McCarney using namespace phosphor::power::util;
3614572cf4SShawn McCarney using namespace sdbusplus::xyz::openbmc_project::Common::Device::Error;
3723dee383SShawn McCarney namespace fs = std::filesystem;
3814572cf4SShawn McCarney
3914572cf4SShawn McCarney namespace utils
4014572cf4SShawn McCarney {
4114572cf4SShawn McCarney
4214572cf4SShawn McCarney constexpr auto IBMCFFPSInterface =
4314572cf4SShawn McCarney "xyz.openbmc_project.Configuration.IBMCFFPSConnector";
4414572cf4SShawn McCarney constexpr auto i2cBusProp = "I2CBus";
4514572cf4SShawn McCarney constexpr auto i2cAddressProp = "I2CAddress";
4614572cf4SShawn McCarney
getPsuI2c(sdbusplus::bus_t & bus,const std::string & psuInventoryPath)4714572cf4SShawn McCarney PsuI2cInfo getPsuI2c(sdbusplus::bus_t& bus, const std::string& psuInventoryPath)
4814572cf4SShawn McCarney {
4914572cf4SShawn McCarney auto depth = 0;
5014572cf4SShawn McCarney auto objects = getSubTree(bus, "/", IBMCFFPSInterface, depth);
5114572cf4SShawn McCarney if (objects.empty())
5214572cf4SShawn McCarney {
5314572cf4SShawn McCarney throw std::runtime_error("Supported Configuration Not Found");
5414572cf4SShawn McCarney }
5514572cf4SShawn McCarney
5614572cf4SShawn McCarney std::optional<std::uint64_t> i2cbus;
5714572cf4SShawn McCarney std::optional<std::uint64_t> i2caddr;
5814572cf4SShawn McCarney
5914572cf4SShawn McCarney // GET a map of objects back.
6014572cf4SShawn McCarney // Each object will have a path, a service, and an interface.
6114572cf4SShawn McCarney for (const auto& [path, services] : objects)
6214572cf4SShawn McCarney {
6314572cf4SShawn McCarney auto service = services.begin()->first;
6414572cf4SShawn McCarney
6514572cf4SShawn McCarney if (path.empty() || service.empty())
6614572cf4SShawn McCarney {
6714572cf4SShawn McCarney continue;
6814572cf4SShawn McCarney }
6914572cf4SShawn McCarney
7014572cf4SShawn McCarney // Match the PSU identifier in the path with the passed PSU inventory
7114572cf4SShawn McCarney // path. Compare the last character of both paths to find the PSU bus
7214572cf4SShawn McCarney // and address. example: PSU path:
7314572cf4SShawn McCarney // /xyz/openbmc_project/inventory/system/board/Nisqually_Backplane/Power_Supply_Slot_0
7414572cf4SShawn McCarney // PSU inventory path:
7514572cf4SShawn McCarney // /xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply0
7614572cf4SShawn McCarney if (path.back() == psuInventoryPath.back())
7714572cf4SShawn McCarney {
7814572cf4SShawn McCarney // Retrieve i2cBus and i2cAddress from array of properties.
7914572cf4SShawn McCarney auto properties =
8014572cf4SShawn McCarney getAllProperties(bus, path, IBMCFFPSInterface, service);
8114572cf4SShawn McCarney for (const auto& property : properties)
8214572cf4SShawn McCarney {
8314572cf4SShawn McCarney try
8414572cf4SShawn McCarney {
8514572cf4SShawn McCarney if (property.first == i2cBusProp)
8614572cf4SShawn McCarney {
8714572cf4SShawn McCarney i2cbus = std::get<uint64_t>(properties.at(i2cBusProp));
8814572cf4SShawn McCarney }
8914572cf4SShawn McCarney else if (property.first == i2cAddressProp)
9014572cf4SShawn McCarney {
9114572cf4SShawn McCarney i2caddr =
9214572cf4SShawn McCarney std::get<uint64_t>(properties.at(i2cAddressProp));
9314572cf4SShawn McCarney }
9414572cf4SShawn McCarney }
9514572cf4SShawn McCarney catch (const std::exception& e)
9614572cf4SShawn McCarney {
97*72e584c5SAnwaar Hadi lg2::warning("Error reading property {PROPERTY}: {ERROR}",
98*72e584c5SAnwaar Hadi "PROPERTY", property.first, "ERROR", e);
9914572cf4SShawn McCarney }
10014572cf4SShawn McCarney }
10114572cf4SShawn McCarney
10214572cf4SShawn McCarney if (i2cbus.has_value() && i2caddr.has_value())
10314572cf4SShawn McCarney {
10414572cf4SShawn McCarney break;
10514572cf4SShawn McCarney }
10614572cf4SShawn McCarney }
10714572cf4SShawn McCarney }
10814572cf4SShawn McCarney
10914572cf4SShawn McCarney if (!i2cbus.has_value() || !i2caddr.has_value())
11014572cf4SShawn McCarney {
11114572cf4SShawn McCarney throw std::runtime_error("Failed to get I2C bus or address");
11214572cf4SShawn McCarney }
11314572cf4SShawn McCarney
11414572cf4SShawn McCarney return std::make_tuple(*i2cbus, *i2caddr);
11514572cf4SShawn McCarney }
11614572cf4SShawn McCarney
getPmbusIntf(std::uint64_t i2cBus,std::uint64_t i2cAddr)11792261f88SPatrick Williams std::unique_ptr<phosphor::pmbus::PMBusBase> getPmbusIntf(std::uint64_t i2cBus,
11892261f88SPatrick Williams std::uint64_t i2cAddr)
11914572cf4SShawn McCarney {
12014572cf4SShawn McCarney std::stringstream ss;
12114572cf4SShawn McCarney ss << std::hex << std::setw(4) << std::setfill('0') << i2cAddr;
12214572cf4SShawn McCarney return phosphor::pmbus::createPMBus(i2cBus, ss.str());
12314572cf4SShawn McCarney }
12414572cf4SShawn McCarney
readVPDValue(phosphor::pmbus::PMBusBase & pmbusIntf,const std::string & vpdName,const phosphor::pmbus::Type & type,const std::size_t & vpdSize)12514572cf4SShawn McCarney std::string readVPDValue(phosphor::pmbus::PMBusBase& pmbusIntf,
12614572cf4SShawn McCarney const std::string& vpdName,
12714572cf4SShawn McCarney const phosphor::pmbus::Type& type,
12814572cf4SShawn McCarney const std::size_t& vpdSize)
12914572cf4SShawn McCarney {
13014572cf4SShawn McCarney std::string vpdValue;
13114572cf4SShawn McCarney const std::regex illegalVPDRegex =
13214572cf4SShawn McCarney std::regex("[^[:alnum:]]", std::regex::basic);
13314572cf4SShawn McCarney
13414572cf4SShawn McCarney try
13514572cf4SShawn McCarney {
13614572cf4SShawn McCarney vpdValue = pmbusIntf.readString(vpdName, type);
13714572cf4SShawn McCarney }
13814572cf4SShawn McCarney catch (const ReadFailure& e)
13914572cf4SShawn McCarney {
14014572cf4SShawn McCarney // Ignore the read failure, let pmbus code indicate failure.
14114572cf4SShawn McCarney }
14214572cf4SShawn McCarney
14314572cf4SShawn McCarney if (vpdValue.size() != vpdSize)
14414572cf4SShawn McCarney {
145*72e584c5SAnwaar Hadi lg2::info(" {VPDNAME} resize needed. size: {SIZE}", "VPDNAME", vpdName,
146*72e584c5SAnwaar Hadi "SIZE", vpdValue.size());
14714572cf4SShawn McCarney vpdValue.resize(vpdSize, ' ');
14814572cf4SShawn McCarney }
14914572cf4SShawn McCarney
15014572cf4SShawn McCarney // Replace any illegal values with space(s).
15114572cf4SShawn McCarney std::regex_replace(vpdValue.begin(), vpdValue.begin(), vpdValue.end(),
15214572cf4SShawn McCarney illegalVPDRegex, " ");
15314572cf4SShawn McCarney
15414572cf4SShawn McCarney return vpdValue;
15514572cf4SShawn McCarney }
15614572cf4SShawn McCarney
checkFileExists(const std::string & filePath)15714572cf4SShawn McCarney bool checkFileExists(const std::string& filePath)
15814572cf4SShawn McCarney {
15914572cf4SShawn McCarney try
16014572cf4SShawn McCarney {
16114572cf4SShawn McCarney return std::filesystem::exists(filePath);
16214572cf4SShawn McCarney }
16314572cf4SShawn McCarney catch (const std::exception& e)
16414572cf4SShawn McCarney {
165*72e584c5SAnwaar Hadi lg2::error("Unable to check for existence of {FILEPATH}: {ERROR}",
166*72e584c5SAnwaar Hadi "FILEPATH", filePath, "ERROR", e);
16714572cf4SShawn McCarney }
16814572cf4SShawn McCarney return false;
16914572cf4SShawn McCarney }
17014572cf4SShawn McCarney
getDeviceName(std::string devPath)17123dee383SShawn McCarney std::string getDeviceName(std::string devPath)
17223dee383SShawn McCarney {
1735ace9fb7SFaisal Awada if (devPath.empty())
1745ace9fb7SFaisal Awada {
1755ace9fb7SFaisal Awada return devPath;
1765ace9fb7SFaisal Awada }
17723dee383SShawn McCarney if (devPath.back() == '/')
17823dee383SShawn McCarney {
17923dee383SShawn McCarney devPath.pop_back();
18023dee383SShawn McCarney }
18123dee383SShawn McCarney return fs::path(devPath).stem().string();
18223dee383SShawn McCarney }
18323dee383SShawn McCarney
getDevicePath(sdbusplus::bus_t & bus,const std::string & psuInventoryPath)18423dee383SShawn McCarney std::string getDevicePath(sdbusplus::bus_t& bus,
18523dee383SShawn McCarney const std::string& psuInventoryPath)
18623dee383SShawn McCarney {
18723dee383SShawn McCarney try
18823dee383SShawn McCarney {
18923dee383SShawn McCarney if (usePsuJsonFile())
19023dee383SShawn McCarney {
19123dee383SShawn McCarney auto data = loadJSONFromFile(PSU_JSON_PATH);
19223dee383SShawn McCarney if (data == nullptr)
19323dee383SShawn McCarney {
19423dee383SShawn McCarney return {};
19523dee383SShawn McCarney }
19623dee383SShawn McCarney auto devicePath = data["psuDevices"][psuInventoryPath];
19723dee383SShawn McCarney if (devicePath.empty())
19823dee383SShawn McCarney {
199*72e584c5SAnwaar Hadi lg2::warning("Unable to find psu devices or path");
20023dee383SShawn McCarney }
20123dee383SShawn McCarney return devicePath;
20223dee383SShawn McCarney }
20323dee383SShawn McCarney else
20423dee383SShawn McCarney {
20523dee383SShawn McCarney const auto [i2cbus, i2caddr] = getPsuI2c(bus, psuInventoryPath);
20623dee383SShawn McCarney const auto DevicePath = "/sys/bus/i2c/devices/";
20723dee383SShawn McCarney std::ostringstream ss;
20823dee383SShawn McCarney ss << std::hex << std::setw(4) << std::setfill('0') << i2caddr;
20923dee383SShawn McCarney std::string addrStr = ss.str();
21023dee383SShawn McCarney std::string busStr = std::to_string(i2cbus);
21123dee383SShawn McCarney std::string devPath = DevicePath + busStr + "-" + addrStr;
21223dee383SShawn McCarney return devPath;
21323dee383SShawn McCarney }
21423dee383SShawn McCarney }
21523dee383SShawn McCarney catch (const std::exception& e)
21623dee383SShawn McCarney {
217*72e584c5SAnwaar Hadi lg2::error("Error in getDevicePath: {ERROR}", "ERROR", e);
21823dee383SShawn McCarney return {};
21923dee383SShawn McCarney }
22023dee383SShawn McCarney catch (...)
22123dee383SShawn McCarney {
222*72e584c5SAnwaar Hadi lg2::error("Unknown error occurred in getDevicePath");
22323dee383SShawn McCarney return {};
22423dee383SShawn McCarney }
22523dee383SShawn McCarney }
22623dee383SShawn McCarney
parseDeviceName(const std::string & devName)22723dee383SShawn McCarney std::pair<uint8_t, uint8_t> parseDeviceName(const std::string& devName)
22823dee383SShawn McCarney {
22923dee383SShawn McCarney // Get I2C bus and device address, e.g. 3-0068
23023dee383SShawn McCarney // is parsed to bus 3, device address 0x68
23123dee383SShawn McCarney auto pos = devName.find('-');
23223dee383SShawn McCarney assert(pos != std::string::npos);
23323dee383SShawn McCarney uint8_t busId = std::stoi(devName.substr(0, pos));
23423dee383SShawn McCarney uint8_t devAddr = std::stoi(devName.substr(pos + 1), nullptr, 16);
23523dee383SShawn McCarney return {busId, devAddr};
23623dee383SShawn McCarney }
23723dee383SShawn McCarney
usePsuJsonFile()23823dee383SShawn McCarney bool usePsuJsonFile()
23923dee383SShawn McCarney {
24023dee383SShawn McCarney return checkFileExists(PSU_JSON_PATH);
24123dee383SShawn McCarney }
24223dee383SShawn McCarney
24314572cf4SShawn McCarney } // namespace utils
244