blob: 58bab676f4cbff91338e82e54803b92aeae09dba [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
B. J. Wyman681b2a32021-04-20 22:31:22 +00006#include <gpiod.hpp>
7#include <phosphor-logging/elog-errors.hpp>
8#include <phosphor-logging/elog.hpp>
Anwaar Hadib64228d2025-05-30 23:55:26 +00009#include <phosphor-logging/lg2.hpp>
Brandon Wyman3f1242f2020-01-28 13:11:25 -060010
Adriana Kobylak52245b62021-09-13 15:46:21 +000011#include <bitset>
Brandon Wyman18a24d92022-04-19 22:48:34 +000012#include <chrono>
Shawn McCarney768d2262024-07-09 15:02:59 -050013#include <format>
Adriana Kobylak52245b62021-09-13 15:46:21 +000014
Brandon Wyman3f1242f2020-01-28 13:11:25 -060015namespace phosphor::power::psu
16{
17
Matt Spinler0975eaf2022-02-14 15:38:30 -060018using Property = std::string;
19using Value = std::variant<bool, std::string>;
20using PropertyMap = std::map<Property, Value>;
21using Interface = std::string;
22using InterfaceMap = std::map<Interface, PropertyMap>;
23using Object = sdbusplus::message::object_path;
24using ObjectMap = std::map<Object, InterfaceMap>;
25
Brandon Wyman3f1242f2020-01-28 13:11:25 -060026class Util : public UtilBase
27{
28 public:
Patrick Williams7354ce62022-07-22 19:26:56 -050029 bool getPresence(sdbusplus::bus_t& bus,
Brandon Wyman3f1242f2020-01-28 13:11:25 -060030 const std::string& invpath) const override
31 {
32 bool present = false;
33
34 // Use getProperty utility function to get presence status.
35 util::getProperty(INVENTORY_IFACE, PRESENT_PROP, invpath,
36 INVENTORY_MGR_IFACE, bus, present);
37
38 return present;
39 }
B. J. Wyman681b2a32021-04-20 22:31:22 +000040
Patrick Williams7354ce62022-07-22 19:26:56 -050041 void setPresence(sdbusplus::bus_t& bus, const std::string& invpath,
B. J. Wyman681b2a32021-04-20 22:31:22 +000042 bool present, const std::string& name) const override
43 {
George Liue4fa48c2024-02-20 10:50:53 +080044 using namespace phosphor::logging;
Anwaar Hadib64228d2025-05-30 23:55:26 +000045 lg2::info("Updating inventory present property. "
46 "present:{PRESENT} invpath:{INVPATH} name:{NAME}",
47 "PRESENT", present, "INVPATH", invpath, "NAME", name);
George Liue4fa48c2024-02-20 10:50:53 +080048
B. J. Wyman681b2a32021-04-20 22:31:22 +000049 using InternalFailure =
50 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
B. J. Wyman681b2a32021-04-20 22:31:22 +000051 PropertyMap invProp;
52
53 invProp.emplace("Present", present);
54 invProp.emplace("PrettyName", name);
55
B. J. Wyman681b2a32021-04-20 22:31:22 +000056 InterfaceMap invIntf;
57 invIntf.emplace("xyz.openbmc_project.Inventory.Item",
58 std::move(invProp));
59
60 Interface extraIface = "xyz.openbmc_project.Inventory.Item.PowerSupply";
61
62 invIntf.emplace(extraIface, PropertyMap());
63
B. J. Wyman681b2a32021-04-20 22:31:22 +000064 ObjectMap invObj;
65 invObj.emplace(std::move(invpath), std::move(invIntf));
66
B. J. Wyman681b2a32021-04-20 22:31:22 +000067 try
68 {
69 auto invService = phosphor::power::util::getService(
70 INVENTORY_OBJ_PATH, INVENTORY_MGR_IFACE, bus);
71
72 // Update inventory
Patrick Williamsf5402192024-08-16 15:20:53 -040073 auto invMsg =
74 bus.new_method_call(invService.c_str(), INVENTORY_OBJ_PATH,
75 INVENTORY_MGR_IFACE, "Notify");
B. J. Wyman681b2a32021-04-20 22:31:22 +000076 invMsg.append(std::move(invObj));
77 auto invMgrResponseMsg = bus.call(invMsg);
78 }
79 catch (const std::exception& e)
80 {
Anwaar Hadib64228d2025-05-30 23:55:26 +000081 lg2::error(
82 "Error in inventory manager call to update inventory: {ERROR}",
83 "ERROR", e);
B. J. Wyman681b2a32021-04-20 22:31:22 +000084 elog<InternalFailure>();
85 }
86 }
Matt Spinler0975eaf2022-02-14 15:38:30 -060087
Patrick Williams7354ce62022-07-22 19:26:56 -050088 void setAvailable(sdbusplus::bus_t& bus, const std::string& invpath,
Matt Spinler0975eaf2022-02-14 15:38:30 -060089 bool available) const override
90 {
91 PropertyMap invProp;
92 InterfaceMap invIntf;
93 ObjectMap invObj;
94
95 invProp.emplace(AVAILABLE_PROP, available);
96 invIntf.emplace(AVAILABILITY_IFACE, std::move(invProp));
97
98 invObj.emplace(std::move(invpath), std::move(invIntf));
99
100 try
101 {
Matt Spinler0975eaf2022-02-14 15:38:30 -0600102 auto invService = phosphor::power::util::getService(
103 INVENTORY_OBJ_PATH, INVENTORY_MGR_IFACE, bus);
104
Patrick Williamsf5402192024-08-16 15:20:53 -0400105 auto invMsg =
106 bus.new_method_call(invService.c_str(), INVENTORY_OBJ_PATH,
107 INVENTORY_MGR_IFACE, "Notify");
Matt Spinler0975eaf2022-02-14 15:38:30 -0600108 invMsg.append(std::move(invObj));
109 auto invMgrResponseMsg = bus.call(invMsg);
110 }
Patrick Williams7354ce62022-07-22 19:26:56 -0500111 catch (const sdbusplus::exception_t& e)
Matt Spinler0975eaf2022-02-14 15:38:30 -0600112 {
113 using namespace phosphor::logging;
Anwaar Hadib64228d2025-05-30 23:55:26 +0000114 lg2::error("Error in inventory manager call to update "
115 "availability interface: {ERROR}",
116 "ERROR", e);
Matt Spinler0975eaf2022-02-14 15:38:30 -0600117 throw;
118 }
119 }
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600120
Patrick Williams7354ce62022-07-22 19:26:56 -0500121 void handleChassisHealthRollup(sdbusplus::bus_t& bus,
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600122 const std::string& invpath,
123 bool addRollup) const override
124 {
125 using AssociationTuple =
126 std::tuple<std::string, std::string, std::string>;
127 using AssociationsProperty = std::vector<AssociationTuple>;
128 try
129 {
130 auto chassisPath = getChassis(bus, invpath);
131
132 auto service = phosphor::power::util::getService(
133 invpath, ASSOC_DEF_IFACE, bus);
134
135 AssociationsProperty associations;
136 phosphor::power::util::getProperty<AssociationsProperty>(
137 ASSOC_DEF_IFACE, ASSOC_PROP, invpath, service, bus,
138 associations);
139
140 AssociationTuple critAssociation{"health_rollup", "critical",
141 chassisPath};
142
143 auto assocIt = std::find(associations.begin(), associations.end(),
144 critAssociation);
145 if (addRollup)
146 {
147 if (assocIt != associations.end())
148 {
149 // It's already there
150 return;
151 }
152
153 associations.push_back(critAssociation);
154 }
155 else
156 {
157 if (assocIt == associations.end())
158 {
159 // It's already been removed.
160 return;
161 }
162
163 // If the object still isn't functional, then don't clear
164 // the association.
165 bool functional = false;
166 phosphor::power::util::getProperty<bool>(
167 OPERATIONAL_STATE_IFACE, FUNCTIONAL_PROP, invpath, service,
168 bus, functional);
169
170 if (!functional)
171 {
172 return;
173 }
174
175 associations.erase(assocIt);
176 }
177
178 phosphor::power::util::setProperty(ASSOC_DEF_IFACE, ASSOC_PROP,
179 invpath, service, bus,
180 associations);
181 }
Patrick Williams7354ce62022-07-22 19:26:56 -0500182 catch (const sdbusplus::exception_t& e)
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600183 {
184 using namespace phosphor::logging;
Anwaar Hadib64228d2025-05-30 23:55:26 +0000185 lg2::info("Error trying to handle health rollup "
186 "associations for {INVPATH}: {ERROR}",
187 "INVPATH", invpath, "ERROR", e);
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600188 }
189 }
190
Patrick Williams7354ce62022-07-22 19:26:56 -0500191 std::string getChassis(sdbusplus::bus_t& bus,
Matt Spinler592bd272023-08-30 11:00:01 -0500192 const std::string& invpath) const override
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600193 {
Matt Spinler06594222023-05-01 10:44:43 -0500194 sdbusplus::message::object_path assocPath = invpath + "/powering";
195 sdbusplus::message::object_path basePath{"/"};
196 std::vector<std::string> interfaces{CHASSIS_IFACE};
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600197
Matt Spinler06594222023-05-01 10:44:43 -0500198 // Find the object path that implements the chassis interface
199 // and also shows up in the endpoints list of the powering assoc.
200 auto chassisPaths = phosphor::power::util::getAssociatedSubTreePaths(
201 bus, assocPath, basePath, interfaces, 0);
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600202
Matt Spinler06594222023-05-01 10:44:43 -0500203 if (chassisPaths.empty())
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600204 {
Shawn McCarney768d2262024-07-09 15:02:59 -0500205 throw std::runtime_error(std::format(
Matt Spinler06594222023-05-01 10:44:43 -0500206 "No association to a chassis found for {}", invpath));
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600207 }
208
Matt Spinler06594222023-05-01 10:44:43 -0500209 return chassisPaths[0];
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600210 }
B. J. Wyman681b2a32021-04-20 22:31:22 +0000211};
212
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000213std::unique_ptr<GPIOInterfaceBase> createGPIO(const std::string& namedGpio);
B. J. Wyman681b2a32021-04-20 22:31:22 +0000214
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000215class GPIOInterface : public GPIOInterfaceBase
B. J. Wyman681b2a32021-04-20 22:31:22 +0000216{
217 public:
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000218 GPIOInterface() = delete;
219 virtual ~GPIOInterface() = default;
220 GPIOInterface(const GPIOInterface&) = default;
221 GPIOInterface& operator=(const GPIOInterface&) = default;
222 GPIOInterface(GPIOInterface&&) = default;
223 GPIOInterface& operator=(GPIOInterface&&) = default;
B. J. Wyman681b2a32021-04-20 22:31:22 +0000224
225 /**
226 * Constructor
227 *
228 * @param[in] namedGpio - The string for the gpio-line-name
229 */
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000230 GPIOInterface(const std::string& namedGpio);
B. J. Wyman681b2a32021-04-20 22:31:22 +0000231
Patrick Williams92261f82025-02-01 08:22:34 -0500232 static std::unique_ptr<GPIOInterfaceBase> createGPIO(
233 const std::string& namedGpio);
B. J. Wyman681b2a32021-04-20 22:31:22 +0000234
235 /**
236 * @brief Attempts to read the state of the GPIO line.
237 *
238 * Throws an exception if line not found, request line fails, or get_value
239 * from line fails.
240 *
241 * @return 1 for active (low/present), 0 for not active (high/not present).
242 */
243 int read() override;
244
B. J. Wymand8b8cb12021-07-15 22:03:34 +0000245 /**
Adriana Kobylak52245b62021-09-13 15:46:21 +0000246 * @brief Attempts to set the state of the GPIO line to the specified value.
247 *
248 * Throws an exception if line not found, request line fails, or set_value
249 * to line fails.
250 *
251 * @param[in] value - The value to set the state of the GPIO line, 1 or 0.
252 * @param[in] flags - Additional line request flags as defined in gpiod.hpp.
253 */
254 void write(int value, std::bitset<32> flags) override;
255
256 /**
Brandon Wyman18a24d92022-04-19 22:48:34 +0000257 * @brief Attempts to toggle (write) a GPIO low then high.
258 *
259 * Relies on write, so throws exception if line not found, etc.
260 *
261 * @param[in] delay - Milliseconds to delay betwen low/high toggle.
262 */
263 void toggleLowHigh(const std::chrono::milliseconds& delay) override;
264
265 /**
B. J. Wymand8b8cb12021-07-15 22:03:34 +0000266 * @brief Returns the name of the GPIO, if not empty.
267 */
268 std::string getName() const override;
269
B. J. Wyman681b2a32021-04-20 22:31:22 +0000270 private:
271 gpiod::line line;
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600272};
273
274} // namespace phosphor::power::psu