blob: b2b27f5ed03305ab990d4e05fb0e0862ada36746 [file] [log] [blame]
Brandon Wyman3f1242f2020-01-28 13:11:25 -06001#pragma once
Brandon Wyman3f1242f2020-01-28 13:11:25 -06002#include "util_base.hpp"
3#include "utility.hpp"
B. J. Wyman681b2a32021-04-20 22:31:22 +00004#include "xyz/openbmc_project/Common/error.hpp"
5
6#include <fmt/format.h>
7
8#include <gpiod.hpp>
9#include <phosphor-logging/elog-errors.hpp>
10#include <phosphor-logging/elog.hpp>
11#include <phosphor-logging/log.hpp>
Brandon Wyman3f1242f2020-01-28 13:11:25 -060012
Adriana Kobylak52245b62021-09-13 15:46:21 +000013#include <bitset>
Brandon Wyman18a24d92022-04-19 22:48:34 +000014#include <chrono>
Adriana Kobylak52245b62021-09-13 15:46:21 +000015
Brandon Wyman3f1242f2020-01-28 13:11:25 -060016namespace phosphor::power::psu
17{
18
Matt Spinler0975eaf2022-02-14 15:38:30 -060019using Property = std::string;
20using Value = std::variant<bool, std::string>;
21using PropertyMap = std::map<Property, Value>;
22using Interface = std::string;
23using InterfaceMap = std::map<Interface, PropertyMap>;
24using Object = sdbusplus::message::object_path;
25using ObjectMap = std::map<Object, InterfaceMap>;
26
Brandon Wyman3f1242f2020-01-28 13:11:25 -060027class Util : public UtilBase
28{
29 public:
Patrick Williams7354ce62022-07-22 19:26:56 -050030 bool getPresence(sdbusplus::bus_t& bus,
Brandon Wyman3f1242f2020-01-28 13:11:25 -060031 const std::string& invpath) const override
32 {
33 bool present = false;
34
35 // Use getProperty utility function to get presence status.
36 util::getProperty(INVENTORY_IFACE, PRESENT_PROP, invpath,
37 INVENTORY_MGR_IFACE, bus, present);
38
39 return present;
40 }
B. J. Wyman681b2a32021-04-20 22:31:22 +000041
Patrick Williams7354ce62022-07-22 19:26:56 -050042 void setPresence(sdbusplus::bus_t& bus, const std::string& invpath,
B. J. Wyman681b2a32021-04-20 22:31:22 +000043 bool present, const std::string& name) const override
44 {
45 using InternalFailure =
46 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
B. J. Wyman681b2a32021-04-20 22:31:22 +000047 PropertyMap invProp;
48
49 invProp.emplace("Present", present);
50 invProp.emplace("PrettyName", name);
51
B. J. Wyman681b2a32021-04-20 22:31:22 +000052 InterfaceMap invIntf;
53 invIntf.emplace("xyz.openbmc_project.Inventory.Item",
54 std::move(invProp));
55
56 Interface extraIface = "xyz.openbmc_project.Inventory.Item.PowerSupply";
57
58 invIntf.emplace(extraIface, PropertyMap());
59
B. J. Wyman681b2a32021-04-20 22:31:22 +000060 ObjectMap invObj;
61 invObj.emplace(std::move(invpath), std::move(invIntf));
62
63 using namespace phosphor::logging;
64 log<level::INFO>(fmt::format("Updating inventory present property. "
65 "present:{} invpath:{} name:{}",
66 present, invpath, name)
67 .c_str());
68
69 try
70 {
71 auto invService = phosphor::power::util::getService(
72 INVENTORY_OBJ_PATH, INVENTORY_MGR_IFACE, bus);
73
74 // Update inventory
Patrick Williams48781ae2023-05-10 07:50:50 -050075 auto invMsg = bus.new_method_call(invService.c_str(),
76 INVENTORY_OBJ_PATH,
77 INVENTORY_MGR_IFACE, "Notify");
B. J. Wyman681b2a32021-04-20 22:31:22 +000078 invMsg.append(std::move(invObj));
79 auto invMgrResponseMsg = bus.call(invMsg);
80 }
81 catch (const std::exception& e)
82 {
83 log<level::ERR>(
84 fmt::format(
85 "Error in inventory manager call to update inventory: {}",
86 e.what())
87 .c_str());
88 elog<InternalFailure>();
89 }
90 }
Matt Spinler0975eaf2022-02-14 15:38:30 -060091
Patrick Williams7354ce62022-07-22 19:26:56 -050092 void setAvailable(sdbusplus::bus_t& bus, const std::string& invpath,
Matt Spinler0975eaf2022-02-14 15:38:30 -060093 bool available) const override
94 {
95 PropertyMap invProp;
96 InterfaceMap invIntf;
97 ObjectMap invObj;
98
99 invProp.emplace(AVAILABLE_PROP, available);
100 invIntf.emplace(AVAILABILITY_IFACE, std::move(invProp));
101
102 invObj.emplace(std::move(invpath), std::move(invIntf));
103
104 try
105 {
Matt Spinler0975eaf2022-02-14 15:38:30 -0600106 auto invService = phosphor::power::util::getService(
107 INVENTORY_OBJ_PATH, INVENTORY_MGR_IFACE, bus);
108
Patrick Williams48781ae2023-05-10 07:50:50 -0500109 auto invMsg = bus.new_method_call(invService.c_str(),
110 INVENTORY_OBJ_PATH,
111 INVENTORY_MGR_IFACE, "Notify");
Matt Spinler0975eaf2022-02-14 15:38:30 -0600112 invMsg.append(std::move(invObj));
113 auto invMgrResponseMsg = bus.call(invMsg);
114 }
Patrick Williams7354ce62022-07-22 19:26:56 -0500115 catch (const sdbusplus::exception_t& e)
Matt Spinler0975eaf2022-02-14 15:38:30 -0600116 {
117 using namespace phosphor::logging;
118 log<level::ERR>(
119 fmt::format("Error in inventory manager call to update "
120 "availability interface: {}",
121 e.what())
122 .c_str());
123 throw;
124 }
125 }
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600126
Patrick Williams7354ce62022-07-22 19:26:56 -0500127 void handleChassisHealthRollup(sdbusplus::bus_t& bus,
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600128 const std::string& invpath,
129 bool addRollup) const override
130 {
131 using AssociationTuple =
132 std::tuple<std::string, std::string, std::string>;
133 using AssociationsProperty = std::vector<AssociationTuple>;
134 try
135 {
136 auto chassisPath = getChassis(bus, invpath);
137
138 auto service = phosphor::power::util::getService(
139 invpath, ASSOC_DEF_IFACE, bus);
140
141 AssociationsProperty associations;
142 phosphor::power::util::getProperty<AssociationsProperty>(
143 ASSOC_DEF_IFACE, ASSOC_PROP, invpath, service, bus,
144 associations);
145
146 AssociationTuple critAssociation{"health_rollup", "critical",
147 chassisPath};
148
149 auto assocIt = std::find(associations.begin(), associations.end(),
150 critAssociation);
151 if (addRollup)
152 {
153 if (assocIt != associations.end())
154 {
155 // It's already there
156 return;
157 }
158
159 associations.push_back(critAssociation);
160 }
161 else
162 {
163 if (assocIt == associations.end())
164 {
165 // It's already been removed.
166 return;
167 }
168
169 // If the object still isn't functional, then don't clear
170 // the association.
171 bool functional = false;
172 phosphor::power::util::getProperty<bool>(
173 OPERATIONAL_STATE_IFACE, FUNCTIONAL_PROP, invpath, service,
174 bus, functional);
175
176 if (!functional)
177 {
178 return;
179 }
180
181 associations.erase(assocIt);
182 }
183
184 phosphor::power::util::setProperty(ASSOC_DEF_IFACE, ASSOC_PROP,
185 invpath, service, bus,
186 associations);
187 }
Patrick Williams7354ce62022-07-22 19:26:56 -0500188 catch (const sdbusplus::exception_t& e)
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600189 {
190 using namespace phosphor::logging;
191 log<level::INFO>(fmt::format("Error trying to handle health rollup "
192 "associations for {}: {}",
193 invpath, e.what())
194 .c_str());
195 }
196 }
197
Patrick Williams7354ce62022-07-22 19:26:56 -0500198 std::string getChassis(sdbusplus::bus_t& bus,
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600199 const std::string& invpath) const
200 {
Matt Spinler06594222023-05-01 10:44:43 -0500201 sdbusplus::message::object_path assocPath = invpath + "/powering";
202 sdbusplus::message::object_path basePath{"/"};
203 std::vector<std::string> interfaces{CHASSIS_IFACE};
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600204
Matt Spinler06594222023-05-01 10:44:43 -0500205 // Find the object path that implements the chassis interface
206 // and also shows up in the endpoints list of the powering assoc.
207 auto chassisPaths = phosphor::power::util::getAssociatedSubTreePaths(
208 bus, assocPath, basePath, interfaces, 0);
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600209
Matt Spinler06594222023-05-01 10:44:43 -0500210 if (chassisPaths.empty())
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600211 {
Matt Spinler06594222023-05-01 10:44:43 -0500212 throw std::runtime_error(fmt::format(
213 "No association to a chassis found for {}", invpath));
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600214 }
215
Matt Spinler06594222023-05-01 10:44:43 -0500216 return chassisPaths[0];
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600217 }
B. J. Wyman681b2a32021-04-20 22:31:22 +0000218};
219
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000220std::unique_ptr<GPIOInterfaceBase> createGPIO(const std::string& namedGpio);
B. J. Wyman681b2a32021-04-20 22:31:22 +0000221
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000222class GPIOInterface : public GPIOInterfaceBase
B. J. Wyman681b2a32021-04-20 22:31:22 +0000223{
224 public:
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000225 GPIOInterface() = delete;
226 virtual ~GPIOInterface() = default;
227 GPIOInterface(const GPIOInterface&) = default;
228 GPIOInterface& operator=(const GPIOInterface&) = default;
229 GPIOInterface(GPIOInterface&&) = default;
230 GPIOInterface& operator=(GPIOInterface&&) = default;
B. J. Wyman681b2a32021-04-20 22:31:22 +0000231
232 /**
233 * Constructor
234 *
235 * @param[in] namedGpio - The string for the gpio-line-name
236 */
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000237 GPIOInterface(const std::string& namedGpio);
B. J. Wyman681b2a32021-04-20 22:31:22 +0000238
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000239 static std::unique_ptr<GPIOInterfaceBase>
B. J. Wyman681b2a32021-04-20 22:31:22 +0000240 createGPIO(const std::string& namedGpio);
241
242 /**
243 * @brief Attempts to read the state of the GPIO line.
244 *
245 * Throws an exception if line not found, request line fails, or get_value
246 * from line fails.
247 *
248 * @return 1 for active (low/present), 0 for not active (high/not present).
249 */
250 int read() override;
251
B. J. Wymand8b8cb12021-07-15 22:03:34 +0000252 /**
Adriana Kobylak52245b62021-09-13 15:46:21 +0000253 * @brief Attempts to set the state of the GPIO line to the specified value.
254 *
255 * Throws an exception if line not found, request line fails, or set_value
256 * to line fails.
257 *
258 * @param[in] value - The value to set the state of the GPIO line, 1 or 0.
259 * @param[in] flags - Additional line request flags as defined in gpiod.hpp.
260 */
261 void write(int value, std::bitset<32> flags) override;
262
263 /**
Brandon Wyman18a24d92022-04-19 22:48:34 +0000264 * @brief Attempts to toggle (write) a GPIO low then high.
265 *
266 * Relies on write, so throws exception if line not found, etc.
267 *
268 * @param[in] delay - Milliseconds to delay betwen low/high toggle.
269 */
270 void toggleLowHigh(const std::chrono::milliseconds& delay) override;
271
272 /**
B. J. Wymand8b8cb12021-07-15 22:03:34 +0000273 * @brief Returns the name of the GPIO, if not empty.
274 */
275 std::string getName() const override;
276
B. J. Wyman681b2a32021-04-20 22:31:22 +0000277 private:
278 gpiod::line line;
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600279};
280
281} // namespace phosphor::power::psu