xref: /openbmc/phosphor-power/tools/power-utils/model.cpp (revision f8e8bc19fa720b6b348a3dddefd8eca7650b3e26)
1 /**
2  * Copyright © 2024 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "config.h"
17 
18 #include "model.hpp"
19 
20 #include "pmbus.hpp"
21 #include "utility.hpp"
22 #include "utils.hpp"
23 
24 #include <nlohmann/json.hpp>
25 #include <phosphor-logging/lg2.hpp>
26 
27 #include <exception>
28 #include <format>
29 #include <fstream>
30 #include <stdexcept>
31 
32 using json = nlohmann::json;
33 
34 using namespace utils;
35 using namespace phosphor::power::util;
36 
37 namespace model
38 {
39 
40 namespace internal
41 {
42 
43 /**
44  * @brief Get the PSU model from sysfs.
45  *
46  * Obtain PSU information from the PSU JSON file.
47  *
48  * Throws an exception if an error occurs.
49  *
50  * @param[in] psuInventoryPath - PSU D-Bus inventory path
51  *
52  * @return PSU model
53  */
getModelJson(const std::string & psuInventoryPath)54 std::string getModelJson(const std::string& psuInventoryPath)
55 {
56     // Parse PSU JSON file
57     std::ifstream file{PSU_JSON_PATH};
58     json data = json::parse(file);
59 
60     // Get PSU device path from JSON
61     auto it = data.find("psuDevices");
62     if (it == data.end())
63     {
64         throw std::runtime_error{"Unable to find psuDevices"};
65     }
66     auto device = it->find(psuInventoryPath);
67     if (device == it->end())
68     {
69         throw std::runtime_error{std::format(
70             "Unable to find device path for PSU {}", psuInventoryPath)};
71     }
72     std::string devicePath = *device;
73     if (devicePath.empty())
74     {
75         throw std::runtime_error{
76             std::format("Empty device path for PSU {}", psuInventoryPath)};
77     }
78 
79     // Get sysfs filename from JSON for Model information
80     it = data.find("fruConfigs");
81     if (it == data.end())
82     {
83         throw std::runtime_error{"Unable to find fruConfigs"};
84     }
85     std::string fileName;
86     for (const auto& fru : *it)
87     {
88         if (fru.contains("propertyName") && (fru["propertyName"] == "Model") &&
89             fru.contains("fileName"))
90         {
91             fileName = fru["fileName"];
92             break;
93         }
94     }
95     if (fileName.empty())
96     {
97         throw std::runtime_error{"Unable to find file name for Model"};
98     }
99 
100     // Get PMBus access type from JSON
101     phosphor::pmbus::Type type = getPMBusAccessType(data);
102 
103     // Read model from sysfs file
104     phosphor::pmbus::PMBus pmbus(devicePath);
105     std::string model = pmbus.readString(fileName, type);
106     return model;
107 }
108 
109 /**
110  * @brief Get the PSU model from sysfs.
111  *
112  * Obtain PSU information from D-Bus.
113  *
114  * Throws an exception if an error occurs.
115  *
116  * @param[in] bus - D-Bus connection
117  * @param[in] psuInventoryPath - PSU D-Bus inventory path
118  *
119  * @return PSU model
120  */
getModelDbus(sdbusplus::bus_t & bus,const std::string & psuInventoryPath)121 std::string getModelDbus(sdbusplus::bus_t& bus,
122                          const std::string& psuInventoryPath)
123 {
124     // Get PSU I2C bus/address and create PMBus interface
125     const auto [i2cBus, i2cAddr] = getPsuI2c(bus, psuInventoryPath);
126     auto pmbus = getPmbusIntf(i2cBus, i2cAddr);
127 
128     // Read model from sysfs file
129     std::string fileName = "ccin";
130     auto type = phosphor::pmbus::Type::HwmonDeviceDebug;
131     std::string model = pmbus->readString(fileName, type);
132     return model;
133 }
134 
135 } // namespace internal
136 
getModel(sdbusplus::bus_t & bus,const std::string & psuInventoryPath)137 std::string getModel(sdbusplus::bus_t& bus, const std::string& psuInventoryPath)
138 {
139     std::string model;
140     try
141     {
142         if (usePsuJsonFile())
143         {
144             // Obtain PSU information from JSON file
145             model = internal::getModelJson(psuInventoryPath);
146         }
147         else
148         {
149             // Obtain PSU information from D-Bus
150             model = internal::getModelDbus(bus, psuInventoryPath);
151         }
152     }
153     catch (const std::exception& e)
154     {
155         lg2::error("Error in getModel: {ERROR}", "ERROR", e);
156     }
157     return model;
158 }
159 
160 } // namespace model
161