blob: 293d44d39f553cf371caf9e986b5ca60c877b45b [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>
9#include <phosphor-logging/log.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;
Shawn McCarney768d2262024-07-09 15:02:59 -050045 log<level::INFO>(std::format("Updating inventory present property. "
George Liue4fa48c2024-02-20 10:50:53 +080046 "present:{} invpath:{} name:{}",
47 present, invpath, name)
48 .c_str());
49
B. J. Wyman681b2a32021-04-20 22:31:22 +000050 using InternalFailure =
51 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
B. J. Wyman681b2a32021-04-20 22:31:22 +000052 PropertyMap invProp;
53
54 invProp.emplace("Present", present);
55 invProp.emplace("PrettyName", name);
56
B. J. Wyman681b2a32021-04-20 22:31:22 +000057 InterfaceMap invIntf;
58 invIntf.emplace("xyz.openbmc_project.Inventory.Item",
59 std::move(invProp));
60
61 Interface extraIface = "xyz.openbmc_project.Inventory.Item.PowerSupply";
62
63 invIntf.emplace(extraIface, PropertyMap());
64
B. J. Wyman681b2a32021-04-20 22:31:22 +000065 ObjectMap invObj;
66 invObj.emplace(std::move(invpath), std::move(invIntf));
67
B. J. Wyman681b2a32021-04-20 22:31:22 +000068 try
69 {
70 auto invService = phosphor::power::util::getService(
71 INVENTORY_OBJ_PATH, INVENTORY_MGR_IFACE, bus);
72
73 // Update inventory
Patrick Williams48781ae2023-05-10 07:50:50 -050074 auto invMsg = bus.new_method_call(invService.c_str(),
75 INVENTORY_OBJ_PATH,
76 INVENTORY_MGR_IFACE, "Notify");
B. J. Wyman681b2a32021-04-20 22:31:22 +000077 invMsg.append(std::move(invObj));
78 auto invMgrResponseMsg = bus.call(invMsg);
79 }
80 catch (const std::exception& e)
81 {
82 log<level::ERR>(
Shawn McCarney768d2262024-07-09 15:02:59 -050083 std::format(
B. J. Wyman681b2a32021-04-20 22:31:22 +000084 "Error in inventory manager call to update inventory: {}",
85 e.what())
86 .c_str());
87 elog<InternalFailure>();
88 }
89 }
Matt Spinler0975eaf2022-02-14 15:38:30 -060090
Patrick Williams7354ce62022-07-22 19:26:56 -050091 void setAvailable(sdbusplus::bus_t& bus, const std::string& invpath,
Matt Spinler0975eaf2022-02-14 15:38:30 -060092 bool available) const override
93 {
94 PropertyMap invProp;
95 InterfaceMap invIntf;
96 ObjectMap invObj;
97
98 invProp.emplace(AVAILABLE_PROP, available);
99 invIntf.emplace(AVAILABILITY_IFACE, std::move(invProp));
100
101 invObj.emplace(std::move(invpath), std::move(invIntf));
102
103 try
104 {
Matt Spinler0975eaf2022-02-14 15:38:30 -0600105 auto invService = phosphor::power::util::getService(
106 INVENTORY_OBJ_PATH, INVENTORY_MGR_IFACE, bus);
107
Patrick Williams48781ae2023-05-10 07:50:50 -0500108 auto invMsg = bus.new_method_call(invService.c_str(),
109 INVENTORY_OBJ_PATH,
110 INVENTORY_MGR_IFACE, "Notify");
Matt Spinler0975eaf2022-02-14 15:38:30 -0600111 invMsg.append(std::move(invObj));
112 auto invMgrResponseMsg = bus.call(invMsg);
113 }
Patrick Williams7354ce62022-07-22 19:26:56 -0500114 catch (const sdbusplus::exception_t& e)
Matt Spinler0975eaf2022-02-14 15:38:30 -0600115 {
116 using namespace phosphor::logging;
117 log<level::ERR>(
Shawn McCarney768d2262024-07-09 15:02:59 -0500118 std::format("Error in inventory manager call to update "
Matt Spinler0975eaf2022-02-14 15:38:30 -0600119 "availability interface: {}",
120 e.what())
121 .c_str());
122 throw;
123 }
124 }
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600125
Patrick Williams7354ce62022-07-22 19:26:56 -0500126 void handleChassisHealthRollup(sdbusplus::bus_t& bus,
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600127 const std::string& invpath,
128 bool addRollup) const override
129 {
130 using AssociationTuple =
131 std::tuple<std::string, std::string, std::string>;
132 using AssociationsProperty = std::vector<AssociationTuple>;
133 try
134 {
135 auto chassisPath = getChassis(bus, invpath);
136
137 auto service = phosphor::power::util::getService(
138 invpath, ASSOC_DEF_IFACE, bus);
139
140 AssociationsProperty associations;
141 phosphor::power::util::getProperty<AssociationsProperty>(
142 ASSOC_DEF_IFACE, ASSOC_PROP, invpath, service, bus,
143 associations);
144
145 AssociationTuple critAssociation{"health_rollup", "critical",
146 chassisPath};
147
148 auto assocIt = std::find(associations.begin(), associations.end(),
149 critAssociation);
150 if (addRollup)
151 {
152 if (assocIt != associations.end())
153 {
154 // It's already there
155 return;
156 }
157
158 associations.push_back(critAssociation);
159 }
160 else
161 {
162 if (assocIt == associations.end())
163 {
164 // It's already been removed.
165 return;
166 }
167
168 // If the object still isn't functional, then don't clear
169 // the association.
170 bool functional = false;
171 phosphor::power::util::getProperty<bool>(
172 OPERATIONAL_STATE_IFACE, FUNCTIONAL_PROP, invpath, service,
173 bus, functional);
174
175 if (!functional)
176 {
177 return;
178 }
179
180 associations.erase(assocIt);
181 }
182
183 phosphor::power::util::setProperty(ASSOC_DEF_IFACE, ASSOC_PROP,
184 invpath, service, bus,
185 associations);
186 }
Patrick Williams7354ce62022-07-22 19:26:56 -0500187 catch (const sdbusplus::exception_t& e)
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600188 {
189 using namespace phosphor::logging;
Shawn McCarney768d2262024-07-09 15:02:59 -0500190 log<level::INFO>(std::format("Error trying to handle health rollup "
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600191 "associations for {}: {}",
192 invpath, e.what())
193 .c_str());
194 }
195 }
196
Patrick Williams7354ce62022-07-22 19:26:56 -0500197 std::string getChassis(sdbusplus::bus_t& bus,
Matt Spinler592bd272023-08-30 11:00:01 -0500198 const std::string& invpath) const override
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600199 {
Matt Spinler06594222023-05-01 10:44:43 -0500200 sdbusplus::message::object_path assocPath = invpath + "/powering";
201 sdbusplus::message::object_path basePath{"/"};
202 std::vector<std::string> interfaces{CHASSIS_IFACE};
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600203
Matt Spinler06594222023-05-01 10:44:43 -0500204 // Find the object path that implements the chassis interface
205 // and also shows up in the endpoints list of the powering assoc.
206 auto chassisPaths = phosphor::power::util::getAssociatedSubTreePaths(
207 bus, assocPath, basePath, interfaces, 0);
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600208
Matt Spinler06594222023-05-01 10:44:43 -0500209 if (chassisPaths.empty())
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600210 {
Shawn McCarney768d2262024-07-09 15:02:59 -0500211 throw std::runtime_error(std::format(
Matt Spinler06594222023-05-01 10:44:43 -0500212 "No association to a chassis found for {}", invpath));
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600213 }
214
Matt Spinler06594222023-05-01 10:44:43 -0500215 return chassisPaths[0];
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600216 }
B. J. Wyman681b2a32021-04-20 22:31:22 +0000217};
218
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000219std::unique_ptr<GPIOInterfaceBase> createGPIO(const std::string& namedGpio);
B. J. Wyman681b2a32021-04-20 22:31:22 +0000220
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000221class GPIOInterface : public GPIOInterfaceBase
B. J. Wyman681b2a32021-04-20 22:31:22 +0000222{
223 public:
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000224 GPIOInterface() = delete;
225 virtual ~GPIOInterface() = default;
226 GPIOInterface(const GPIOInterface&) = default;
227 GPIOInterface& operator=(const GPIOInterface&) = default;
228 GPIOInterface(GPIOInterface&&) = default;
229 GPIOInterface& operator=(GPIOInterface&&) = default;
B. J. Wyman681b2a32021-04-20 22:31:22 +0000230
231 /**
232 * Constructor
233 *
234 * @param[in] namedGpio - The string for the gpio-line-name
235 */
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000236 GPIOInterface(const std::string& namedGpio);
B. J. Wyman681b2a32021-04-20 22:31:22 +0000237
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000238 static std::unique_ptr<GPIOInterfaceBase>
B. J. Wyman681b2a32021-04-20 22:31:22 +0000239 createGPIO(const std::string& namedGpio);
240
241 /**
242 * @brief Attempts to read the state of the GPIO line.
243 *
244 * Throws an exception if line not found, request line fails, or get_value
245 * from line fails.
246 *
247 * @return 1 for active (low/present), 0 for not active (high/not present).
248 */
249 int read() override;
250
B. J. Wymand8b8cb12021-07-15 22:03:34 +0000251 /**
Adriana Kobylak52245b62021-09-13 15:46:21 +0000252 * @brief Attempts to set the state of the GPIO line to the specified value.
253 *
254 * Throws an exception if line not found, request line fails, or set_value
255 * to line fails.
256 *
257 * @param[in] value - The value to set the state of the GPIO line, 1 or 0.
258 * @param[in] flags - Additional line request flags as defined in gpiod.hpp.
259 */
260 void write(int value, std::bitset<32> flags) override;
261
262 /**
Brandon Wyman18a24d92022-04-19 22:48:34 +0000263 * @brief Attempts to toggle (write) a GPIO low then high.
264 *
265 * Relies on write, so throws exception if line not found, etc.
266 *
267 * @param[in] delay - Milliseconds to delay betwen low/high toggle.
268 */
269 void toggleLowHigh(const std::chrono::milliseconds& delay) override;
270
271 /**
B. J. Wymand8b8cb12021-07-15 22:03:34 +0000272 * @brief Returns the name of the GPIO, if not empty.
273 */
274 std::string getName() const override;
275
B. J. Wyman681b2a32021-04-20 22:31:22 +0000276 private:
277 gpiod::line line;
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600278};
279
280} // namespace phosphor::power::psu