blob: dc28ffe45f117e50cb7868dc34955da7668245b8 [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 {
Anwaar Hadib64228d2025-05-30 23:55:26 +000044 lg2::info("Updating inventory present property. "
45 "present:{PRESENT} invpath:{INVPATH} name:{NAME}",
46 "PRESENT", present, "INVPATH", invpath, "NAME", name);
George Liue4fa48c2024-02-20 10:50:53 +080047
B. J. Wyman681b2a32021-04-20 22:31:22 +000048 using InternalFailure =
49 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
B. J. Wyman681b2a32021-04-20 22:31:22 +000050 PropertyMap invProp;
51
52 invProp.emplace("Present", present);
53 invProp.emplace("PrettyName", name);
54
B. J. Wyman681b2a32021-04-20 22:31:22 +000055 InterfaceMap invIntf;
56 invIntf.emplace("xyz.openbmc_project.Inventory.Item",
57 std::move(invProp));
58
59 Interface extraIface = "xyz.openbmc_project.Inventory.Item.PowerSupply";
60
61 invIntf.emplace(extraIface, PropertyMap());
62
B. J. Wyman681b2a32021-04-20 22:31:22 +000063 ObjectMap invObj;
64 invObj.emplace(std::move(invpath), std::move(invIntf));
65
B. J. Wyman681b2a32021-04-20 22:31:22 +000066 try
67 {
68 auto invService = phosphor::power::util::getService(
69 INVENTORY_OBJ_PATH, INVENTORY_MGR_IFACE, bus);
70
71 // Update inventory
Patrick Williamsf5402192024-08-16 15:20:53 -040072 auto invMsg =
73 bus.new_method_call(invService.c_str(), INVENTORY_OBJ_PATH,
74 INVENTORY_MGR_IFACE, "Notify");
B. J. Wyman681b2a32021-04-20 22:31:22 +000075 invMsg.append(std::move(invObj));
76 auto invMgrResponseMsg = bus.call(invMsg);
77 }
78 catch (const std::exception& e)
79 {
Anwaar Hadib64228d2025-05-30 23:55:26 +000080 lg2::error(
81 "Error in inventory manager call to update inventory: {ERROR}",
82 "ERROR", e);
Anwaar Hadif8e8bc12025-06-05 21:08:06 +000083 phosphor::logging::elog<InternalFailure>();
B. J. Wyman681b2a32021-04-20 22:31:22 +000084 }
85 }
Matt Spinler0975eaf2022-02-14 15:38:30 -060086
Patrick Williams7354ce62022-07-22 19:26:56 -050087 void setAvailable(sdbusplus::bus_t& bus, const std::string& invpath,
Matt Spinler0975eaf2022-02-14 15:38:30 -060088 bool available) const override
89 {
90 PropertyMap invProp;
91 InterfaceMap invIntf;
92 ObjectMap invObj;
93
94 invProp.emplace(AVAILABLE_PROP, available);
95 invIntf.emplace(AVAILABILITY_IFACE, std::move(invProp));
96
97 invObj.emplace(std::move(invpath), std::move(invIntf));
98
99 try
100 {
Matt Spinler0975eaf2022-02-14 15:38:30 -0600101 auto invService = phosphor::power::util::getService(
102 INVENTORY_OBJ_PATH, INVENTORY_MGR_IFACE, bus);
103
Patrick Williamsf5402192024-08-16 15:20:53 -0400104 auto invMsg =
105 bus.new_method_call(invService.c_str(), INVENTORY_OBJ_PATH,
106 INVENTORY_MGR_IFACE, "Notify");
Matt Spinler0975eaf2022-02-14 15:38:30 -0600107 invMsg.append(std::move(invObj));
108 auto invMgrResponseMsg = bus.call(invMsg);
109 }
Patrick Williams7354ce62022-07-22 19:26:56 -0500110 catch (const sdbusplus::exception_t& e)
Matt Spinler0975eaf2022-02-14 15:38:30 -0600111 {
Anwaar Hadib64228d2025-05-30 23:55:26 +0000112 lg2::error("Error in inventory manager call to update "
113 "availability interface: {ERROR}",
114 "ERROR", e);
Matt Spinler0975eaf2022-02-14 15:38:30 -0600115 throw;
116 }
117 }
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600118
Patrick Williams7354ce62022-07-22 19:26:56 -0500119 void handleChassisHealthRollup(sdbusplus::bus_t& bus,
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600120 const std::string& invpath,
121 bool addRollup) const override
122 {
123 using AssociationTuple =
124 std::tuple<std::string, std::string, std::string>;
125 using AssociationsProperty = std::vector<AssociationTuple>;
126 try
127 {
128 auto chassisPath = getChassis(bus, invpath);
129
130 auto service = phosphor::power::util::getService(
131 invpath, ASSOC_DEF_IFACE, bus);
132
133 AssociationsProperty associations;
134 phosphor::power::util::getProperty<AssociationsProperty>(
135 ASSOC_DEF_IFACE, ASSOC_PROP, invpath, service, bus,
136 associations);
137
138 AssociationTuple critAssociation{"health_rollup", "critical",
139 chassisPath};
140
141 auto assocIt = std::find(associations.begin(), associations.end(),
142 critAssociation);
143 if (addRollup)
144 {
145 if (assocIt != associations.end())
146 {
147 // It's already there
148 return;
149 }
150
151 associations.push_back(critAssociation);
152 }
153 else
154 {
155 if (assocIt == associations.end())
156 {
157 // It's already been removed.
158 return;
159 }
160
161 // If the object still isn't functional, then don't clear
162 // the association.
163 bool functional = false;
164 phosphor::power::util::getProperty<bool>(
165 OPERATIONAL_STATE_IFACE, FUNCTIONAL_PROP, invpath, service,
166 bus, functional);
167
168 if (!functional)
169 {
170 return;
171 }
172
173 associations.erase(assocIt);
174 }
175
176 phosphor::power::util::setProperty(ASSOC_DEF_IFACE, ASSOC_PROP,
177 invpath, service, bus,
178 associations);
179 }
Patrick Williams7354ce62022-07-22 19:26:56 -0500180 catch (const sdbusplus::exception_t& e)
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600181 {
Anwaar Hadib64228d2025-05-30 23:55:26 +0000182 lg2::info("Error trying to handle health rollup "
183 "associations for {INVPATH}: {ERROR}",
184 "INVPATH", invpath, "ERROR", e);
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600185 }
186 }
187
Patrick Williams7354ce62022-07-22 19:26:56 -0500188 std::string getChassis(sdbusplus::bus_t& bus,
Matt Spinler592bd272023-08-30 11:00:01 -0500189 const std::string& invpath) const override
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600190 {
Matt Spinler06594222023-05-01 10:44:43 -0500191 sdbusplus::message::object_path assocPath = invpath + "/powering";
192 sdbusplus::message::object_path basePath{"/"};
193 std::vector<std::string> interfaces{CHASSIS_IFACE};
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600194
Matt Spinler06594222023-05-01 10:44:43 -0500195 // Find the object path that implements the chassis interface
196 // and also shows up in the endpoints list of the powering assoc.
197 auto chassisPaths = phosphor::power::util::getAssociatedSubTreePaths(
198 bus, assocPath, basePath, interfaces, 0);
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600199
Matt Spinler06594222023-05-01 10:44:43 -0500200 if (chassisPaths.empty())
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600201 {
Shawn McCarney768d2262024-07-09 15:02:59 -0500202 throw std::runtime_error(std::format(
Matt Spinler06594222023-05-01 10:44:43 -0500203 "No association to a chassis found for {}", invpath));
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600204 }
205
Matt Spinler06594222023-05-01 10:44:43 -0500206 return chassisPaths[0];
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600207 }
B. J. Wyman681b2a32021-04-20 22:31:22 +0000208};
209
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000210std::unique_ptr<GPIOInterfaceBase> createGPIO(const std::string& namedGpio);
B. J. Wyman681b2a32021-04-20 22:31:22 +0000211
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000212class GPIOInterface : public GPIOInterfaceBase
B. J. Wyman681b2a32021-04-20 22:31:22 +0000213{
214 public:
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000215 GPIOInterface() = delete;
216 virtual ~GPIOInterface() = default;
217 GPIOInterface(const GPIOInterface&) = default;
218 GPIOInterface& operator=(const GPIOInterface&) = default;
219 GPIOInterface(GPIOInterface&&) = default;
220 GPIOInterface& operator=(GPIOInterface&&) = default;
B. J. Wyman681b2a32021-04-20 22:31:22 +0000221
222 /**
223 * Constructor
224 *
225 * @param[in] namedGpio - The string for the gpio-line-name
226 */
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000227 GPIOInterface(const std::string& namedGpio);
B. J. Wyman681b2a32021-04-20 22:31:22 +0000228
Patrick Williams92261f82025-02-01 08:22:34 -0500229 static std::unique_ptr<GPIOInterfaceBase> createGPIO(
230 const std::string& namedGpio);
B. J. Wyman681b2a32021-04-20 22:31:22 +0000231
232 /**
233 * @brief Attempts to read the state of the GPIO line.
234 *
235 * Throws an exception if line not found, request line fails, or get_value
236 * from line fails.
237 *
238 * @return 1 for active (low/present), 0 for not active (high/not present).
239 */
240 int read() override;
241
B. J. Wymand8b8cb12021-07-15 22:03:34 +0000242 /**
Adriana Kobylak52245b62021-09-13 15:46:21 +0000243 * @brief Attempts to set the state of the GPIO line to the specified value.
244 *
245 * Throws an exception if line not found, request line fails, or set_value
246 * to line fails.
247 *
248 * @param[in] value - The value to set the state of the GPIO line, 1 or 0.
249 * @param[in] flags - Additional line request flags as defined in gpiod.hpp.
250 */
251 void write(int value, std::bitset<32> flags) override;
252
253 /**
Brandon Wyman18a24d92022-04-19 22:48:34 +0000254 * @brief Attempts to toggle (write) a GPIO low then high.
255 *
256 * Relies on write, so throws exception if line not found, etc.
257 *
258 * @param[in] delay - Milliseconds to delay betwen low/high toggle.
259 */
260 void toggleLowHigh(const std::chrono::milliseconds& delay) override;
261
262 /**
B. J. Wymand8b8cb12021-07-15 22:03:34 +0000263 * @brief Returns the name of the GPIO, if not empty.
264 */
265 std::string getName() const override;
266
B. J. Wyman681b2a32021-04-20 22:31:22 +0000267 private:
268 gpiod::line line;
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600269};
270
271} // namespace phosphor::power::psu