blob: 3c6408be19b75d6cad1688ca975f45aa3ddffb44 [file] [log] [blame]
Brandon Wymana0f33ce2019-10-17 18:32:29 -05001#pragma once
2
Brandon Wyman8d195772020-01-27 15:03:51 -06003#include "pmbus.hpp"
Brandon Wymanaed1f752019-11-25 18:10:52 -06004#include "types.hpp"
B. J. Wyman681b2a32021-04-20 22:31:22 +00005#include "util.hpp"
Brandon Wyman3f1242f2020-01-28 13:11:25 -06006#include "utility.hpp"
Brandon Wymanaed1f752019-11-25 18:10:52 -06007
B. J. Wyman681b2a32021-04-20 22:31:22 +00008#include <gpiod.hpp>
Brandon Wymanaed1f752019-11-25 18:10:52 -06009#include <sdbusplus/bus/match.hpp>
Matt Spinler592bd272023-08-30 11:00:01 -050010#include <xyz/openbmc_project/Association/Definitions/server.hpp>
Matt Spinlera068f422023-03-10 13:06:49 -060011#include <xyz/openbmc_project/Sensor/Value/server.hpp>
Matt Spinler592bd272023-08-30 11:00:01 -050012#include <xyz/openbmc_project/State/Decorator/Availability/server.hpp>
13#include <xyz/openbmc_project/State/Decorator/OperationalStatus/server.hpp>
Brandon Wymanaed1f752019-11-25 18:10:52 -060014
B. J. Wyman681b2a32021-04-20 22:31:22 +000015#include <filesystem>
Brandon Wyman1d7a7df2020-03-26 10:14:05 -050016#include <stdexcept>
17
Brandon Wymana0f33ce2019-10-17 18:32:29 -050018namespace phosphor::power::psu
19{
Brandon Wyman3f1242f2020-01-28 13:11:25 -060020
Chanh Nguyenc12c53b2021-04-06 17:24:47 +070021#if IBM_VPD
Brandon Wyman1d7a7df2020-03-26 10:14:05 -050022// PMBus device driver "file name" to read for CCIN value.
23constexpr auto CCIN = "ccin";
Matt Spinlerb40f04c2023-03-20 11:07:44 -050024constexpr auto PART_NUMBER = "mfr_revision";
25constexpr auto FRU_NUMBER = "mfr_model";
26constexpr auto SERIAL_HEADER = "mfr_location";
27constexpr auto SERIAL_NUMBER = "mfr_serial";
Brandon Wyman1d7a7df2020-03-26 10:14:05 -050028constexpr auto FW_VERSION = "fw_version";
29
30// The D-Bus property name to update with the CCIN value.
31constexpr auto MODEL_PROP = "Model";
32constexpr auto PN_PROP = "PartNumber";
Brandon Wymana169b0f2021-12-07 20:18:06 +000033constexpr auto SPARE_PN_PROP = "SparePartNumber";
Brandon Wyman1d7a7df2020-03-26 10:14:05 -050034constexpr auto SN_PROP = "SerialNumber";
35constexpr auto VERSION_PROP = "Version";
36
37// ipzVPD Keyword sizes
38static constexpr auto FL_KW_SIZE = 20;
Brandon Wyman8393f462022-06-28 16:06:46 +000039static constexpr auto FN_KW_SIZE = 7;
40static constexpr auto PN_KW_SIZE = 7;
41// For IBM power supplies, the SN is 6-byte header + 6-byte serial.
42static constexpr auto SN_KW_SIZE = 12;
43static constexpr auto CC_KW_SIZE = 4;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -050044#endif
45
Brandon Wymanf65c4062020-08-19 13:15:53 -050046constexpr auto LOG_LIMIT = 3;
Brandon Wyman06ca4592021-12-06 22:52:23 +000047constexpr auto DEGLITCH_LIMIT = 3;
Brandon Wyman6d469fd2022-06-15 16:58:21 +000048constexpr auto PGOOD_DEGLITCH_LIMIT = 5;
Jim Wright4ab86562022-11-18 14:05:46 -060049// Number of polls to remember that an AC fault occured. Should remain greater
50// than PGOOD_DEGLITCH_LIMIT.
51constexpr auto AC_FAULT_LIMIT = 6;
Brandon Wymanf65c4062020-08-19 13:15:53 -050052
Faisal Awadab66ae502023-04-01 18:30:32 -050053constexpr auto IBMCFFPS_DD_NAME = "ibm-cffps";
Faisal Awada9582d9c2023-07-11 09:31:22 -050054constexpr auto ACBEL_FSG032_DD_NAME = "acbel-fsg032";
Faisal Awadab66ae502023-04-01 18:30:32 -050055
Matt Spinler592bd272023-08-30 11:00:01 -050056using AvailabilityInterface =
57 sdbusplus::xyz::openbmc_project::State::Decorator::server::Availability;
58using OperationalStatusInterface = sdbusplus::xyz::openbmc_project::State::
59 Decorator::server::OperationalStatus;
60using AssocDefInterface =
61 sdbusplus::xyz::openbmc_project::Association::server::Definitions;
Matt Spinlera068f422023-03-10 13:06:49 -060062using SensorInterface = sdbusplus::xyz::openbmc_project::Sensor::server::Value;
63using SensorObject = sdbusplus::server::object_t<SensorInterface>;
Matt Spinler592bd272023-08-30 11:00:01 -050064using PowerSensorObject =
65 sdbusplus::server::object_t<SensorInterface, OperationalStatusInterface,
66 AvailabilityInterface, AssocDefInterface>;
67
68using AssociationTuple = std::tuple<std::string, std::string, std::string>;
Matt Spinlera068f422023-03-10 13:06:49 -060069
Brandon Wymana0f33ce2019-10-17 18:32:29 -050070/**
71 * @class PowerSupply
72 * Represents a PMBus power supply device.
73 */
74class PowerSupply
75{
76 public:
Brandon Wymanaed1f752019-11-25 18:10:52 -060077 PowerSupply() = delete;
Brandon Wymana0f33ce2019-10-17 18:32:29 -050078 PowerSupply(const PowerSupply&) = delete;
79 PowerSupply(PowerSupply&&) = delete;
80 PowerSupply& operator=(const PowerSupply&) = delete;
81 PowerSupply& operator=(PowerSupply&&) = delete;
82 ~PowerSupply() = default;
83
84 /**
Brandon Wymanc63941c2020-01-27 16:49:33 -060085 * @param[in] invpath - String for inventory path to use
86 * @param[in] i2cbus - The bus number this power supply is on
87 * @param[in] i2caddr - The 16-bit I2C address of the power supply
Brandon Wymanc3324422022-03-24 20:30:57 +000088 * @param[in] driver - i2c driver name for power supply
B. J. Wyman681b2a32021-04-20 22:31:22 +000089 * @param[in] gpioLineName - The gpio-line-name to read for presence. See
90 * https://github.com/openbmc/docs/blob/master/designs/device-tree-gpio-naming.md
George Liu9464c422023-02-27 14:30:27 +080091 * @param[in] callback - Get the power on status of the psu manager class
Brandon Wymanaed1f752019-11-25 18:10:52 -060092 */
Patrick Williams7354ce62022-07-22 19:26:56 -050093 PowerSupply(sdbusplus::bus_t& bus, const std::string& invpath,
B. J. Wyman681b2a32021-04-20 22:31:22 +000094 std::uint8_t i2cbus, const std::uint16_t i2caddr,
George Liu9464c422023-02-27 14:30:27 +080095 const std::string& driver, const std::string& gpioLineName,
96 std::function<bool()>&& callback);
Brandon Wymanaed1f752019-11-25 18:10:52 -060097
Brandon Wyman3f1242f2020-01-28 13:11:25 -060098 phosphor::pmbus::PMBusBase& getPMBus()
99 {
100 return *pmbusIntf;
101 }
102
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000103 GPIOInterfaceBase* getPresenceGPIO()
B. J. Wyman681b2a32021-04-20 22:31:22 +0000104 {
105 return presenceGPIO.get();
106 }
107
B. J. Wymand8b8cb12021-07-15 22:03:34 +0000108 std::string getPresenceGPIOName() const
109 {
110 if (presenceGPIO != nullptr)
111 {
112 return presenceGPIO->getName();
113 }
114 else
115 {
116 return std::string();
117 }
118 }
119
Brandon Wymanaed1f752019-11-25 18:10:52 -0600120 /**
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500121 * Power supply specific function to analyze for faults/errors.
122 *
123 * Various PMBus status bits will be checked for fault conditions.
124 * If a certain fault bits are on, the appropriate error will be
125 * committed.
126 */
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600127 void analyze();
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500128
129 /**
Brandon Wyman59a35792020-06-04 12:37:40 -0500130 * Write PMBus ON_OFF_CONFIG
131 *
132 * This function will be called to cause the PMBus device driver to send the
133 * ON_OFF_CONFIG command. Takes one byte of data.
134 *
135 * @param[in] data - The ON_OFF_CONFIG data byte mask.
136 */
137 void onOffConfig(uint8_t data);
138
139 /**
Brandon Wymane3f7ad22021-12-21 20:27:45 +0000140 * Clears all the member variables that indicate if a fault bit was seen as
141 * on in the STATUS_WORD or STATUS_MFR_SPECIFIC response.
142 */
143 void clearFaultFlags()
144 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000145 inputFault = 0;
146 mfrFault = 0;
Brandon Wymane3f7ad22021-12-21 20:27:45 +0000147 statusMFR = 0;
Brandon Wymanc2906f42021-12-21 20:14:56 +0000148 vinUVFault = 0;
149 cmlFault = 0;
150 voutOVFault = 0;
151 ioutOCFault = 0;
152 voutUVFault = 0;
153 fanFault = 0;
154 tempFault = 0;
Brandon Wymane3f7ad22021-12-21 20:27:45 +0000155 pgoodFault = 0;
Brandon Wymanc2906f42021-12-21 20:14:56 +0000156 psKillFault = 0;
157 ps12VcsFault = 0;
158 psCS12VFault = 0;
Brandon Wymanba6d9602022-05-02 18:10:47 +0000159 faultLogged = false;
Brandon Wymane3f7ad22021-12-21 20:27:45 +0000160 }
161
162 /**
Brandon Wyman3225a452022-03-18 18:51:49 +0000163 * @brief Function to specifically clear VIN_UV/OFF fault(s).
164 *
165 * The PMBus HWMON device driver has various alarm "files" to read out of
166 * sysfs. Reading those files will indicate if various alarms are active or
167 * not, and then specifically clear those faults that go with that alarm.
168 *
169 * The VIN_UV fault, indicated in STATUS_INPUT, goes with in1_lcrit_alarm.
170 * When a VIN_UV fault occurs, the "Unit Off For Insufficient Input Voltage"
171 * may also be active. Reading in1_lcrit_alarm should clear both fault bits,
172 * resulting in the corresponding fault bits in STATUS_WORD also clearing.
173 *
174 * See: https://www.kernel.org/doc/html/latest/hwmon/pmbus.html
175 */
176 void clearVinUVFault();
177
178 /**
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500179 * Write PMBus CLEAR_FAULTS
180 *
181 * This function will be called in various situations in order to clear
182 * any fault status bits that may have been set, in order to start over
183 * with a clean state. Presence changes and power state changes will
184 * want to clear any faults logged.
185 */
Brandon Wyman3c208462020-05-13 16:25:58 -0500186 void clearFaults();
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500187
188 /**
189 * @brief Adds properties to the inventory.
190 *
191 * Reads the values from the device and writes them to the
192 * associated power supply D-Bus inventory object.
193 *
194 * This needs to be done on startup, and each time the presence
195 * state changes.
196 *
197 * Properties added:
198 * - Serial Number
199 * - Part Number
200 * - CCIN (Customer Card Identification Number) - added as the Model
201 * - Firmware version
202 */
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500203 void updateInventory();
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500204
Brandon Wymanaed1f752019-11-25 18:10:52 -0600205 /**
206 * @brief Accessor function to indicate present status
207 */
208 bool isPresent() const
209 {
210 return present;
211 }
212
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600213 /**
Brandon Wymanfed0ba22020-09-26 20:02:51 -0500214 * @brief Returns the last read value from STATUS_WORD.
215 */
216 uint64_t getStatusWord() const
217 {
218 return statusWord;
219 }
220
221 /**
Brandon Wymanf07bc792021-10-12 19:00:35 +0000222 * @brief Returns the last read value from STATUS_INPUT.
223 */
224 uint64_t getStatusInput() const
225 {
226 return statusInput;
227 }
228
229 /**
Jay Meyer10d94052020-11-30 14:41:21 -0600230 * @brief Returns the last read value from STATUS_MFR.
231 */
232 uint64_t getMFRFault() const
233 {
234 return statusMFR;
235 }
236
237 /**
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000238 * @brief Returns the last read value from STATUS_CML.
239 */
240 uint64_t getStatusCML() const
241 {
242 return statusCML;
243 }
244
245 /**
Brandon Wyman6710ba22021-10-27 17:39:31 +0000246 * @brief Returns the last read value from STATUS_VOUT.
247 */
248 uint64_t getStatusVout() const
249 {
250 return statusVout;
251 }
252
253 /**
Brandon Wymanb10b3be2021-11-09 22:12:15 +0000254 * @brief Returns the last value read from STATUS_IOUT.
255 */
256 uint64_t getStatusIout() const
257 {
258 return statusIout;
259 }
260
261 /**
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000262 * @brief Returns the last value read from STATUS_FANS_1_2.
263 */
264 uint64_t getStatusFans12() const
265 {
266 return statusFans12;
267 }
268
269 /**
Brandon Wyman96893a42021-11-05 19:56:57 +0000270 * @brief Returns the last value read from STATUS_TEMPERATURE.
271 */
272 uint64_t getStatusTemperature() const
273 {
274 return statusTemperature;
275 }
276
277 /**
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600278 * @brief Returns true if a fault was found.
279 */
280 bool isFaulted() const
281 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000282 return (hasCommFault() || (vinUVFault >= DEGLITCH_LIMIT) ||
283 (inputFault >= DEGLITCH_LIMIT) ||
284 (voutOVFault >= DEGLITCH_LIMIT) ||
285 (ioutOCFault >= DEGLITCH_LIMIT) ||
286 (voutUVFault >= DEGLITCH_LIMIT) ||
287 (fanFault >= DEGLITCH_LIMIT) || (tempFault >= DEGLITCH_LIMIT) ||
Brandon Wyman6d469fd2022-06-15 16:58:21 +0000288 (pgoodFault >= PGOOD_DEGLITCH_LIMIT) ||
289 (mfrFault >= DEGLITCH_LIMIT));
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600290 }
291
292 /**
Brandon Wymanb76ab242020-09-16 18:06:06 -0500293 * @brief Return whether a fault has been logged for this power supply
294 */
295 bool isFaultLogged() const
296 {
297 return faultLogged;
298 }
299
300 /**
301 * @brief Called when a fault for this power supply has been logged.
302 */
303 void setFaultLogged()
304 {
305 faultLogged = true;
306 }
307
308 /**
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600309 * @brief Returns true if INPUT fault occurred.
310 */
311 bool hasInputFault() const
312 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000313 return (inputFault >= DEGLITCH_LIMIT);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600314 }
315
316 /**
317 * @brief Returns true if MFRSPECIFIC occurred.
318 */
319 bool hasMFRFault() const
320 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000321 return (mfrFault >= DEGLITCH_LIMIT);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600322 }
323
324 /**
325 * @brief Returns true if VIN_UV_FAULT occurred.
326 */
327 bool hasVINUVFault() const
328 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000329 return (vinUVFault >= DEGLITCH_LIMIT);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600330 }
331
Brandon Wymanc9efe412020-10-09 15:42:50 -0500332 /**
Brandon Wyman6710ba22021-10-27 17:39:31 +0000333 * @brief Returns true if VOUT_OV_FAULT occurred.
334 */
335 bool hasVoutOVFault() const
336 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000337 return (voutOVFault >= DEGLITCH_LIMIT);
Brandon Wyman6710ba22021-10-27 17:39:31 +0000338 }
339
340 /**
Brandon Wymanb10b3be2021-11-09 22:12:15 +0000341 * @brief Returns true if IOUT_OC fault occurred (bit 4 STATUS_BYTE).
342 */
343 bool hasIoutOCFault() const
344 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000345 return (ioutOCFault >= DEGLITCH_LIMIT);
Brandon Wymanb10b3be2021-11-09 22:12:15 +0000346 }
347
348 /**
Brandon Wyman2cf46942021-10-28 19:09:16 +0000349 * @brief Returns true if VOUT_UV_FAULT occurred.
350 */
351 bool hasVoutUVFault() const
352 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000353 return (voutUVFault >= DEGLITCH_LIMIT);
Brandon Wyman2cf46942021-10-28 19:09:16 +0000354 }
355
356 /**
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000357 *@brief Returns true if fan fault occurred.
358 */
359 bool hasFanFault() const
360 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000361 return (fanFault >= DEGLITCH_LIMIT);
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000362 }
363
364 /**
Brandon Wyman96893a42021-11-05 19:56:57 +0000365 * @brief Returns true if TEMPERATURE fault occurred.
366 */
367 bool hasTempFault() const
368 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000369 return (tempFault >= DEGLITCH_LIMIT);
Brandon Wyman96893a42021-11-05 19:56:57 +0000370 }
371
372 /**
Brandon Wyman2916ea52021-11-06 03:31:18 +0000373 * @brief Returns true if there is a PGood fault (PGOOD# inactive, or OFF
374 * bit on).
375 */
376 bool hasPgoodFault() const
377 {
Brandon Wyman6d469fd2022-06-15 16:58:21 +0000378 return (pgoodFault >= PGOOD_DEGLITCH_LIMIT);
Brandon Wyman2916ea52021-11-06 03:31:18 +0000379 }
380
381 /**
Brandon Wyman39ea02b2021-11-23 23:22:23 +0000382 * @brief Return true if there is a PS_Kill fault.
383 */
384 bool hasPSKillFault() const
385 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000386 return (psKillFault >= DEGLITCH_LIMIT);
Brandon Wyman39ea02b2021-11-23 23:22:23 +0000387 }
388
389 /**
390 * @brief Returns true if there is a 12Vcs (standy power) fault.
391 */
392 bool hasPS12VcsFault() const
393 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000394 return (ps12VcsFault >= DEGLITCH_LIMIT);
Brandon Wyman39ea02b2021-11-23 23:22:23 +0000395 }
396
397 /**
398 * @brief Returns true if there is a 12V current-share fault.
399 */
400 bool hasPSCS12VFault() const
401 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000402 return (psCS12VFault >= DEGLITCH_LIMIT);
Brandon Wyman39ea02b2021-11-23 23:22:23 +0000403 }
404
405 /**
Jim Wright4ab86562022-11-18 14:05:46 -0600406 * @brief Returns true if an AC fault has occurred in the window of
407 * interest.
408 */
409 bool hasACFault() const
410 {
411 return acFault != 0;
412 }
413
414 /**
Brandon Wymanc9efe412020-10-09 15:42:50 -0500415 * @brief Returns the device path
416 *
417 * This can be used for error call outs.
418 * Example: /sys/bus/i2c/devices/3-0068
419 */
Brandon Wyman4176d6b2020-10-07 17:41:06 -0500420 const std::string getDevicePath() const
421 {
422 return pmbusIntf->path();
423 }
424
Brandon Wymanc9efe412020-10-09 15:42:50 -0500425 /**
Brandon Wyman321a6152022-03-19 00:11:44 +0000426 * @brief Returns this power supply's inventory path.
Brandon Wymanc9efe412020-10-09 15:42:50 -0500427 *
428 * This can be used for error call outs.
429 * Example:
430 * /xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply1
431 */
Brandon Wyman7e495272020-09-26 19:57:46 -0500432 const std::string& getInventoryPath() const
433 {
434 return inventoryPath;
435 }
436
Brandon Wymanc9efe412020-10-09 15:42:50 -0500437 /**
Brandon Wyman321a6152022-03-19 00:11:44 +0000438 * @brief Returns the short name (last part of inventoryPath).
439 */
440 const std::string& getShortName() const
441 {
442 return shortName;
443 }
444
445 /**
Brandon Wymanc9efe412020-10-09 15:42:50 -0500446 * @brief Returns the firmware revision version read from the power supply
447 */
448 const std::string& getFWVersion() const
449 {
450 return fwVersion;
451 }
452
Adriana Kobylak572a9052021-03-30 15:58:07 +0000453 /**
454 * @brief Returns the model name of the power supply
455 */
456 const std::string& getModelName() const
457 {
458 return modelName;
459 }
460
Jim Wright15300242022-11-17 16:37:04 -0600461 /**
462 * @brief Returns true if the number of failed reads exceeds limit
Brandon Wymanf65c4062020-08-19 13:15:53 -0500463 * TODO: or CML bit on.
464 */
465 bool hasCommFault() const
466 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000467 return ((readFail >= LOG_LIMIT) || (cmlFault >= DEGLITCH_LIMIT));
Brandon Wymanf65c4062020-08-19 13:15:53 -0500468 }
469
Adriana Kobylak4175ffb2021-08-02 14:51:05 +0000470 /**
471 * @brief Reads the pmbus input voltage and returns that actual voltage
472 * reading and the calculated input voltage based on thresholds.
473 * @param[out] actualInputVoltage - The actual voltage reading, in Volts.
474 * @param[out] inputVoltage - A rounded up/down value of the actual input
475 * voltage based on thresholds, in Volts.
476 */
477 void getInputVoltage(double& actualInputVoltage, int& inputVoltage) const;
478
Matt Spinler0975eaf2022-02-14 15:38:30 -0600479 /**
480 * @brief Check if the PS is considered to be available or not
481 *
482 * It is unavailable if any of:
483 * - not present
484 * - input fault active
485 * - Vin UV fault active
486 * - PS KILL fault active
487 * - Iout OC fault active
488 *
489 * Other faults will, through creating error logs with callouts, already
490 * be setting the Functional property to false.
491 *
492 * On changes, the Available property is updated in the inventory.
493 */
494 void checkAvailability();
495
Brandon Wymanc3324422022-03-24 20:30:57 +0000496 /**
Brandon Wyman18a24d92022-04-19 22:48:34 +0000497 * @brief Returns true when INPUT_HISTORY sync is required.
498 */
499 bool isSyncHistoryRequired() const
500 {
501 return syncHistoryRequired;
502 }
503
504 /**
505 * @brief Clears the indicator that sync required for INPUT_HISTORY.
506 *
507 * Sets variable to false to indicate that the sync is no longer required.
508 * This can be used after the PSUManager has reacted to the need for the
509 * INPUT_HISTORY data to be synchronized.
510 */
511 void clearSyncHistoryRequired()
512 {
513 syncHistoryRequired = false;
514 }
515
Matt Spinlera068f422023-03-10 13:06:49 -0600516 /**
517 * @brief Puts the input voltage rating on D-Bus.
518 *
519 * The rating is like 0, 110, 220.
520 */
521 void setInputVoltageRating();
522
Matt Spinler592bd272023-08-30 11:00:01 -0500523 /**
524 * @brief Returns the peak input power value if there is one,
525 * otherwise std::nullopt.
526 */
527 std::optional<double> getPeakInputPower() const
528 {
529 std::optional<double> value;
530 if (peakInputPowerSensor)
531 {
532 value = peakInputPowerSensor->value();
533 }
534 return value;
535 }
536
537 /**
538 * @brief Converts a Linear Format power number to an integer
539 *
540 * The PMBus spec describes a 2 byte Linear Format
541 * number that is composed of an exponent and mantissa
542 * in two's complement notation.
543 *
544 * Value = Mantissa * 2**Exponent
545 *
546 * @return double - The converted value
547 */
548 static double linearToInteger(uint16_t data);
549
Faisal Awadab7131a12023-10-26 19:38:45 -0500550 /**
551 * @brief Retrieve device driver name
552 */
553 const std::string& getDriverName() const
554 {
555 return driverName;
556 }
557
558 /**
559 * @brief Set device driver name
560 * @param[in] newDriver - device driver name.
561 */
562 void setDriverName(const std::string& newDriver)
563 {
564 driverName = newDriver;
565 }
566
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500567 private:
Jim Wright15300242022-11-17 16:37:04 -0600568 /**
Matt Spinlerd6760262023-08-30 10:13:05 -0500569 * @brief Examine STATUS_WORD for CML (communication, memory, logic fault).
570 */
571 void analyzeCMLFault();
572
573 /**
574 * @brief Examine STATUS_WORD for INPUT bit on.
575 *
576 * "An input voltage, input current, or input power fault or warning has
577 * occurred."
578 */
579 void analyzeInputFault();
580
581 /**
582 * @brief Examine STATUS_WORD for VOUT being set.
583 *
584 * If VOUT is on, "An output voltage fault or warning has occurred.", and
585 * VOUT_OV_FAULT is on, there is an output over-voltage fault.
586 */
587 void analyzeVoutOVFault();
588
589 /**
590 * @brief Examine STATUS_WORD value read for IOUT_OC_FAULT.
591 *
592 * "An output overcurrent fault has occurred." If it is on, and fault not
593 * set, trace STATUS_WORD, STATUS_MFR_SPECIFIC, and STATUS_IOUT values.
594 */
595 void analyzeIoutOCFault();
596
597 /**
598 * @brief Examines STATUS_WORD value read to see if there is a UV fault.
599 *
600 * Checks if the VOUT bit is on, indicating "An output voltage fault or
601 * warning has occurred", if it is on, but VOUT_OV_FAULT is off, it is
602 * determined to be an indication of an output under-voltage fault.
603 */
604 void analyzeVoutUVFault();
605
606 /**
607 * @brief Examine STATUS_WORD for the fan fault/warning bit.
608 *
609 * If fanFault is not on, trace that the bit now came on, include
610 * STATUS_WORD, STATUS_MFR_SPECIFIC, and STATUS_FANS_1_2 values as well, to
611 * help with understanding what may have caused it to be set.
612 */
613 void analyzeFanFault();
614
615 /**
616 * @brief Examine STATUS_WORD for temperature fault.
617 */
618 void analyzeTemperatureFault();
619
620 /**
621 * @brief Examine STATUS_WORD for pgood or unit off faults.
622 */
623 void analyzePgoodFault();
624
625 /**
626 * @brief Determine possible manufacturer-specific faults from bits in
627 * STATUS_MFR.
628 *
629 * The bits in the STATUS_MFR_SPECIFIC command response have "Manufacturer
630 * Defined" meanings. Determine which faults, if any, are present based on
631 * the power supply (device driver) type.
632 */
633 void determineMFRFault();
634
635 /**
636 * @brief Examine STATUS_WORD value read for MFRSPECIFIC bit on.
637 *
638 * "A manufacturer specific fault or warning has occurred."
639 *
640 * If it is on, call the determineMFRFault() helper function to examine the
641 * value read from STATUS_MFR_SPECIFIC.
642 */
643 void analyzeMFRFault();
644
645 /**
646 * @brief Analyzes the STATUS_WORD for a VIN_UV_FAULT indicator.
647 */
648 void analyzeVinUVFault();
649
650 /**
651 * @brief Given a full inventory path, returns the last node of the path as
652 * the "short name"
653 */
654 std::string findShortName(const std::string& invPath)
655 {
656 const auto lastSlashPos = invPath.find_last_of('/');
657
658 if ((lastSlashPos == std::string::npos) ||
659 ((lastSlashPos + 1) == invPath.size()))
660 {
661 return invPath;
662 }
663 else
664 {
665 return invPath.substr(lastSlashPos + 1);
666 }
667 }
668
669 /**
670 * @brief Binds or unbinds the power supply device driver
671 *
672 * Called when a presence change is detected to either bind the device
673 * driver for the power supply when it is installed, or unbind the device
674 * driver when the power supply is removed.
675 *
Faisal Awadab7131a12023-10-26 19:38:45 -0500676 * Note:
677 * Bind device when device present and i2cbus-i2caddr does not exist
678 * UnBind device when device not present and i2cbus-i2caddr exist
679
Matt Spinlerd6760262023-08-30 10:13:05 -0500680 * Writes <device> to <path>/bind (or unbind)
681 *
682 * @param present - when true, will bind the device driver
683 * when false, will unbind the device driver
684 */
685 void bindOrUnbindDriver(bool present);
686
687 /**
688 * @brief Updates the presence status by querying D-Bus
689 *
690 * The D-Bus inventory properties for this power supply will be read to
691 * determine if the power supply is present or not and update this
692 * object's present member variable to reflect current status.
693 **/
694 void updatePresence();
695
696 /**
697 * @brief Updates the power supply presence by reading the GPIO line.
698 */
699 void updatePresenceGPIO();
700
701 /**
702 * @brief Callback for inventory property changes
703 *
704 * Process change of Present property for power supply.
705 *
706 * This is used if we are watching the D-Bus properties instead of reading
707 * the GPIO presence line ourselves.
708 *
709 * @param[in] msg - Data associated with Present change signal
710 **/
711 void inventoryChanged(sdbusplus::message_t& msg);
712
713 /**
714 * @brief Callback for inventory property added.
715 *
716 * Process add of the interface with the Present property for power supply.
717 *
718 * This is used if we are watching the D-Bus properties instead of reading
719 * the GPIO presence line ourselves.
720 *
721 * @param[in] msg - Data associated with Present add signal
722 **/
723 void inventoryAdded(sdbusplus::message_t& msg);
724
725 /**
726 * @brief Reads the pmbus MFR_POUT_MAX value.
727 *
728 * "The MFR_POUT_MAX command sets or retrieves the maximum rated output
729 * power, in watts, that the unit is rated to supply."
730 *
731 * @return max_power_out value converted from string.
732 */
733 auto getMaxPowerOut() const;
734
735 /**
736 * @brief Reads a VPD value from PMBus, correct size, and contents.
737 *
738 * If the VPD data read is not the passed in size, resize and fill with
739 * spaces. If the data contains a non-alphanumeric value, replace any of
740 * those values with spaces.
741 *
742 * @param[in] vpdName - The name of the sysfs "file" to read data from.
743 * @param[in] type - The HWMON file type to read from.
744 * @param[in] vpdSize - The expacted size of the data for this VPD/property
745 *
746 * @return A string containing the VPD data read, resized if necessary
747 */
748 auto readVPDValue(const std::string& vpdName,
749 const phosphor::pmbus::Type& type,
750 const std::size_t& vpdSize);
751
752 /**
Matt Spinlerd6760262023-08-30 10:13:05 -0500753 * @brief Retrieve PSU VPD keyword from D-Bus
754 *
755 * It retrieves PSU VPD keyword from D-Bus and assign the associated
756 * string to vpdStr.
757 * @param[in] keyword - The VPD search keyword
758 * @param[out] vpdStr - The VPD string associated with the keyword.
759 */
760 void getPsuVpdFromDbus(const std::string& keyword, std::string& vpdStr);
761
762 /**
Matt Spinler592bd272023-08-30 11:00:01 -0500763 * @brief Creates the appropriate sensor D-Bus objects.
764 */
765 void setupSensors();
766
767 /**
768 * @brief Monitors sensor values and updates D-Bus.
769 * Called from analyze().
770 */
771 void monitorSensors();
772
773 /**
774 * @brief Creates the peak input power sensor D-Bus object
775 * if the PS supports it.
776 */
777 void setupInputPowerPeakSensor();
778
779 /**
780 * @brief Monitors the peak input power sensor
781 */
782 void monitorPeakInputPowerSensor();
783
784 /**
785 * @brief Sets any sensor objects to Available = false on D-Bus.
786 */
787 void setSensorsNotAvailable();
788
789 /**
790 * @brief Returns the associations to create for a sensor on this
791 * power supply.
792 */
793 std::vector<AssociationTuple> getSensorAssociations();
794
795 /**
Jim Wright15300242022-11-17 16:37:04 -0600796 * @brief systemd bus member
797 */
Patrick Williams7354ce62022-07-22 19:26:56 -0500798 sdbusplus::bus_t& bus;
Brandon Wymanaed1f752019-11-25 18:10:52 -0600799
Jim Wright15300242022-11-17 16:37:04 -0600800 /**
Matt Spinlerd6760262023-08-30 10:13:05 -0500801 * @brief D-Bus path to use for this power supply's inventory status.
802 **/
803 std::string inventoryPath;
804
805 /**
806 * @brief The file system path used for binding the device driver.
807 */
Faisal Awadab7131a12023-10-26 19:38:45 -0500808 std::filesystem::path bindPath;
Matt Spinlerd6760262023-08-30 10:13:05 -0500809
810 /**
811 * @brief Get the power on status of the psu manager class.
812 *
813 * This is a callback method used to get the power on status of the psu
814 * manager class.
815 */
816 std::function<bool()> isPowerOn;
817
818 /**
Matt Spinlerd6760262023-08-30 10:13:05 -0500819 * @brief Set to true when INPUT_HISTORY sync is required.
820 *
821 * A power supply will need to synchronize its INPUT_HISTORY data with the
822 * other power supplies installed in the system when it goes from missing to
823 * present.
824 */
825 bool syncHistoryRequired{false};
826
827 /**
828 * @brief Store the short name to avoid string processing.
829 *
830 * The short name will be something like powersupply1, the last part of the
831 * inventoryPath.
832 */
833 std::string shortName;
834
835 /**
836 * @brief The libgpiod object for monitoring PSU presence
837 */
838 std::unique_ptr<GPIOInterfaceBase> presenceGPIO = nullptr;
839
840 /**
841 * @brief True if the power supply is present.
842 */
843 bool present = false;
844
845 /**
846 * @brief Power supply model name.
847 */
848 std::string modelName;
849
850 /**
851 * @brief D-Bus match variable used to subscribe to Present property
852 * changes.
853 **/
854 std::unique_ptr<sdbusplus::bus::match_t> presentMatch;
855
856 /**
857 * @brief D-Bus match variable used to subscribe for Present property
858 * interface added.
859 */
860 std::unique_ptr<sdbusplus::bus::match_t> presentAddedMatch;
861
862 /**
863 * @brief Pointer to the PMBus interface
864 *
865 * Used to read or write to/from PMBus power supply devices.
866 */
867 std::unique_ptr<phosphor::pmbus::PMBusBase> pmbusIntf = nullptr;
868
869 /**
870 * @brief Stored copy of the firmware version/revision string
871 */
872 std::string fwVersion;
873
874 /**
875 * @brief The string to pass in for binding the device driver.
876 */
877 std::string bindDevice;
878
879 /**
880 * @brief The result of the most recent availability check
881 *
882 * Saved on the object so changes can be detected.
883 */
884 bool available = false;
885
886 /**
Jim Wright15300242022-11-17 16:37:04 -0600887 * @brief Will be updated to the latest/lastvalue read from STATUS_WORD.
888 */
Brandon Wymanfed0ba22020-09-26 20:02:51 -0500889 uint64_t statusWord = 0;
890
Jim Wright15300242022-11-17 16:37:04 -0600891 /**
892 * @brief Will be set to the last read value of STATUS_WORD.
893 */
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000894 uint64_t statusWordOld = 0;
895
Jim Wright15300242022-11-17 16:37:04 -0600896 /**
897 * @brief Will be updated to the latest/lastvalue read from STATUS_INPUT.
898 */
Brandon Wymanf07bc792021-10-12 19:00:35 +0000899 uint64_t statusInput = 0;
900
Jim Wright15300242022-11-17 16:37:04 -0600901 /**
902 * @brief Will be updated to the latest/lastvalue read from STATUS_MFR.
903 */
Jay Meyer10d94052020-11-30 14:41:21 -0600904 uint64_t statusMFR = 0;
905
Jim Wright15300242022-11-17 16:37:04 -0600906 /**
907 * @brief Will be updated to the latest/last value read from STATUS_CML.
908 */
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000909 uint64_t statusCML = 0;
910
Jim Wright15300242022-11-17 16:37:04 -0600911 /**
912 * @brief Will be updated to the latest/last value read from STATUS_VOUT.
913 */
Brandon Wyman6710ba22021-10-27 17:39:31 +0000914 uint64_t statusVout = 0;
915
Jim Wright15300242022-11-17 16:37:04 -0600916 /**
917 * @brief Will be updated to the latest/last value read from STATUS_IOUT.
918 */
Brandon Wymanb10b3be2021-11-09 22:12:15 +0000919 uint64_t statusIout = 0;
920
Jim Wright15300242022-11-17 16:37:04 -0600921 /**
922 * @brief Will be updated to the latest/last value read from
923 * STATUS_FANS_1_2.
924 */
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000925 uint64_t statusFans12 = 0;
926
Jim Wright15300242022-11-17 16:37:04 -0600927 /**
928 * @brief Will be updated to the latest/last value read from
929 * STATUS_TEMPERATURE.
930 */
Brandon Wyman96893a42021-11-05 19:56:57 +0000931 uint64_t statusTemperature = 0;
932
Jim Wright15300242022-11-17 16:37:04 -0600933 /**
934 * @brief Will be updated with latest converted value read from READ_VIN
935 */
Brandon Wyman82affd92021-11-24 19:12:49 +0000936 int inputVoltage = phosphor::pmbus::in_input::VIN_VOLTAGE_0;
937
Jim Wright15300242022-11-17 16:37:04 -0600938 /**
939 * @brief Will be updated with the actual voltage last read from READ_VIN
Brandon Wyman4fc191f2022-03-10 23:07:13 +0000940 */
941 double actualInputVoltage = 0;
942
Jim Wright15300242022-11-17 16:37:04 -0600943 /**
944 * @brief True if an error for a fault has already been logged.
945 */
Brandon Wymanb76ab242020-09-16 18:06:06 -0500946 bool faultLogged = false;
947
Jim Wright15300242022-11-17 16:37:04 -0600948 /**
949 * @brief Incremented if bit 1 of STATUS_WORD low byte is on.
Brandon Wymanc2906f42021-12-21 20:14:56 +0000950 *
951 * Considered faulted if reaches DEGLITCH_LIMIT.
952 */
953 size_t cmlFault = 0;
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000954
Jim Wright15300242022-11-17 16:37:04 -0600955 /**
956 * @brief Incremented if bit 5 of STATUS_WORD high byte is on.
Brandon Wymanc2906f42021-12-21 20:14:56 +0000957 *
958 * Considered faulted if reaches DEGLITCH_LIMIT.
959 */
960 size_t inputFault = 0;
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600961
Jim Wright15300242022-11-17 16:37:04 -0600962 /**
963 * @brief Incremented if bit 4 of STATUS_WORD high byte is on.
Brandon Wymanc2906f42021-12-21 20:14:56 +0000964 *
965 * Considered faulted if reaches DEGLITCH_LIMIT.
966 */
967 size_t mfrFault = 0;
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600968
Jim Wright15300242022-11-17 16:37:04 -0600969 /**
970 * @brief Incremented if bit 3 of STATUS_WORD low byte is on.
Brandon Wymanc2906f42021-12-21 20:14:56 +0000971 *
972 * Considered faulted if reaches DEGLITCH_LIMIT.
973 */
974 size_t vinUVFault = 0;
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600975
Jim Wright15300242022-11-17 16:37:04 -0600976 /**
977 * @brief Incremented if bit 5 of STATUS_WORD low byte is on.
Brandon Wymanc2906f42021-12-21 20:14:56 +0000978 *
979 * Considered faulted if reaches DEGLITCH_LIMIT.
980 */
981 size_t voutOVFault = 0;
Brandon Wyman6710ba22021-10-27 17:39:31 +0000982
Jim Wright15300242022-11-17 16:37:04 -0600983 /**
984 * @brief Incremented if bit 4 of STATUS_WORD low byte is on.
Brandon Wymanc2906f42021-12-21 20:14:56 +0000985 *
986 * Considered faulted if reaches DEGLITCH_LIMIT.
987 */
988 size_t ioutOCFault = 0;
Brandon Wymanb10b3be2021-11-09 22:12:15 +0000989
Jim Wright15300242022-11-17 16:37:04 -0600990 /**
991 * @brief Incremented if bit 7 of STATUS_WORD high byte is on and bit 5
Brandon Wymanc2906f42021-12-21 20:14:56 +0000992 * (VOUT_OV) of low byte is off.
993 *
994 * Considered faulted if reaches DEGLITCH_LIMIT.
995 */
996 size_t voutUVFault = 0;
Brandon Wyman2cf46942021-10-28 19:09:16 +0000997
Jim Wright15300242022-11-17 16:37:04 -0600998 /**
999 * @brief Incremented if FANS fault/warn bit on in STATUS_WORD.
Brandon Wymanc2906f42021-12-21 20:14:56 +00001000 *
1001 * Considered faulted if reaches DEGLITCH_LIMIT.
1002 */
1003 size_t fanFault = 0;
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +00001004
Jim Wright15300242022-11-17 16:37:04 -06001005 /**
1006 * @brief Incremented if bit 2 of STATUS_WORD low byte is on.
Brandon Wymanc2906f42021-12-21 20:14:56 +00001007 *
Jim Wright15300242022-11-17 16:37:04 -06001008 * Considered faulted if reaches DEGLITCH_LIMIT.
1009 */
Brandon Wymanc2906f42021-12-21 20:14:56 +00001010 size_t tempFault = 0;
Brandon Wyman96893a42021-11-05 19:56:57 +00001011
Brandon Wyman2cf46942021-10-28 19:09:16 +00001012 /**
Brandon Wyman06ca4592021-12-06 22:52:23 +00001013 * @brief Incremented if bit 11 or 6 of STATUS_WORD is on. PGOOD# is
1014 * inactive, or the unit is off.
1015 *
1016 * Considered faulted if reaches DEGLITCH_LIMIT.
Brandon Wyman2916ea52021-11-06 03:31:18 +00001017 */
Brandon Wyman925c0262021-12-21 20:15:36 +00001018 size_t pgoodFault = 0;
Brandon Wyman2916ea52021-11-06 03:31:18 +00001019
Brandon Wyman39ea02b2021-11-23 23:22:23 +00001020 /**
1021 * @brief Power Supply Kill fault.
Brandon Wymanc2906f42021-12-21 20:14:56 +00001022 *
1023 * Incremented based on bits in STATUS_MFR_SPECIFIC. IBM power supplies use
1024 * bit 4 to indicate this fault. Considered faulted if it reaches
1025 * DEGLITCH_LIMIT.
Brandon Wyman39ea02b2021-11-23 23:22:23 +00001026 */
Brandon Wymanc2906f42021-12-21 20:14:56 +00001027 size_t psKillFault = 0;
Brandon Wyman39ea02b2021-11-23 23:22:23 +00001028
1029 /**
1030 * @brief Power Supply 12Vcs fault (standby power).
Brandon Wymanc2906f42021-12-21 20:14:56 +00001031 *
1032 * Incremented based on bits in STATUS_MFR_SPECIFIC. IBM power supplies use
1033 * bit 6 to indicate this fault. Considered faulted if it reaches
1034 * DEGLITCH_LIMIT.
Brandon Wyman39ea02b2021-11-23 23:22:23 +00001035 */
Brandon Wymanc2906f42021-12-21 20:14:56 +00001036 size_t ps12VcsFault = 0;
Brandon Wyman39ea02b2021-11-23 23:22:23 +00001037
1038 /**
1039 * @brief Power Supply Current-Share fault in 12V domain.
Brandon Wymanc2906f42021-12-21 20:14:56 +00001040 *
1041 * Incremented based on bits in STATUS_MFR_SPECIFIC. IBM power supplies use
1042 * bit 7 to indicate this fault. Considered faulted if it reaches
1043 * DEGLITCH_LIMIT.
Brandon Wyman39ea02b2021-11-23 23:22:23 +00001044 */
Brandon Wymanc2906f42021-12-21 20:14:56 +00001045 size_t psCS12VFault = 0;
Brandon Wyman39ea02b2021-11-23 23:22:23 +00001046
Jim Wright15300242022-11-17 16:37:04 -06001047 /**
Jim Wright4ab86562022-11-18 14:05:46 -06001048 * @brief Set to AC_FAULT_LIMIT when AC fault is detected, decremented when
1049 * AC fault has cleared. Effectively forms a timer since last AC failure.
1050 * Zero indicates being outside the window of concern.
1051 */
1052 size_t acFault = 0;
1053
1054 /**
Jim Wright15300242022-11-17 16:37:04 -06001055 * @brief Count of the number of read failures.
1056 */
Brandon Wymanf65c4062020-08-19 13:15:53 -05001057 size_t readFail = 0;
1058
Brandon Wymanaed1f752019-11-25 18:10:52 -06001059 /**
Matt Spinlera068f422023-03-10 13:06:49 -06001060 * @brief The D-Bus object for the input voltage rating
1061 *
1062 * It is updated at startup and power on. If a power supply is
1063 * added or removed after that, it does not need to be updated
1064 * again (though that could be done as a future improvement).
1065 */
1066 std::unique_ptr<SensorObject> inputVoltageRatingIface;
Faisal Awadab66ae502023-04-01 18:30:32 -05001067
1068 /**
Matt Spinler592bd272023-08-30 11:00:01 -05001069 * @brief The D-Bus object for the peak input power sensor.
1070 */
1071 std::unique_ptr<PowerSensorObject> peakInputPowerSensor;
1072
1073 /**
Faisal Awadab66ae502023-04-01 18:30:32 -05001074 * @brief The device driver name
1075 */
1076 std::string driverName;
Brandon Wymana0f33ce2019-10-17 18:32:29 -05001077};
1078
1079} // namespace phosphor::power::psu