blob: ec523ae0a76bb3504899ab4bcb0a2378a1619695 [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>
10
B. J. Wyman681b2a32021-04-20 22:31:22 +000011#include <filesystem>
Brandon Wyman1d7a7df2020-03-26 10:14:05 -050012#include <stdexcept>
13
Brandon Wymana0f33ce2019-10-17 18:32:29 -050014namespace phosphor::power::psu
15{
Brandon Wyman3f1242f2020-01-28 13:11:25 -060016
Chanh Nguyenc12c53b2021-04-06 17:24:47 +070017#if IBM_VPD
Brandon Wyman1d7a7df2020-03-26 10:14:05 -050018// PMBus device driver "file name" to read for CCIN value.
19constexpr auto CCIN = "ccin";
20constexpr auto PART_NUMBER = "part_number";
21constexpr auto FRU_NUMBER = "fru";
22constexpr auto SERIAL_HEADER = "header";
23constexpr auto SERIAL_NUMBER = "serial_number";
24constexpr auto FW_VERSION = "fw_version";
25
26// The D-Bus property name to update with the CCIN value.
27constexpr auto MODEL_PROP = "Model";
28constexpr auto PN_PROP = "PartNumber";
Brandon Wymana169b0f2021-12-07 20:18:06 +000029constexpr auto SPARE_PN_PROP = "SparePartNumber";
Brandon Wyman1d7a7df2020-03-26 10:14:05 -050030constexpr auto SN_PROP = "SerialNumber";
31constexpr auto VERSION_PROP = "Version";
32
33// ipzVPD Keyword sizes
34static constexpr auto FL_KW_SIZE = 20;
35#endif
36
Brandon Wymanf65c4062020-08-19 13:15:53 -050037constexpr auto LOG_LIMIT = 3;
Brandon Wyman06ca4592021-12-06 22:52:23 +000038constexpr auto DEGLITCH_LIMIT = 3;
Brandon Wymanf65c4062020-08-19 13:15:53 -050039
Brandon Wymana0f33ce2019-10-17 18:32:29 -050040/**
41 * @class PowerSupply
42 * Represents a PMBus power supply device.
43 */
44class PowerSupply
45{
46 public:
Brandon Wymanaed1f752019-11-25 18:10:52 -060047 PowerSupply() = delete;
Brandon Wymana0f33ce2019-10-17 18:32:29 -050048 PowerSupply(const PowerSupply&) = delete;
49 PowerSupply(PowerSupply&&) = delete;
50 PowerSupply& operator=(const PowerSupply&) = delete;
51 PowerSupply& operator=(PowerSupply&&) = delete;
52 ~PowerSupply() = default;
53
54 /**
Brandon Wymanc63941c2020-01-27 16:49:33 -060055 * @param[in] invpath - String for inventory path to use
56 * @param[in] i2cbus - The bus number this power supply is on
57 * @param[in] i2caddr - The 16-bit I2C address of the power supply
B. J. Wyman681b2a32021-04-20 22:31:22 +000058 * @param[in] gpioLineName - The gpio-line-name to read for presence. See
59 * https://github.com/openbmc/docs/blob/master/designs/device-tree-gpio-naming.md
Brandon Wymanaed1f752019-11-25 18:10:52 -060060 */
Brandon Wymanc63941c2020-01-27 16:49:33 -060061 PowerSupply(sdbusplus::bus::bus& bus, const std::string& invpath,
B. J. Wyman681b2a32021-04-20 22:31:22 +000062 std::uint8_t i2cbus, const std::uint16_t i2caddr,
63 const std::string& gpioLineName);
Brandon Wymanaed1f752019-11-25 18:10:52 -060064
Brandon Wyman3f1242f2020-01-28 13:11:25 -060065 phosphor::pmbus::PMBusBase& getPMBus()
66 {
67 return *pmbusIntf;
68 }
69
Adriana Kobylak3ca062a2021-10-20 15:27:23 +000070 GPIOInterfaceBase* getPresenceGPIO()
B. J. Wyman681b2a32021-04-20 22:31:22 +000071 {
72 return presenceGPIO.get();
73 }
74
B. J. Wymand8b8cb12021-07-15 22:03:34 +000075 std::string getPresenceGPIOName() const
76 {
77 if (presenceGPIO != nullptr)
78 {
79 return presenceGPIO->getName();
80 }
81 else
82 {
83 return std::string();
84 }
85 }
86
Brandon Wymanaed1f752019-11-25 18:10:52 -060087 /**
Brandon Wymana0f33ce2019-10-17 18:32:29 -050088 * Power supply specific function to analyze for faults/errors.
89 *
90 * Various PMBus status bits will be checked for fault conditions.
91 * If a certain fault bits are on, the appropriate error will be
92 * committed.
93 */
Brandon Wyman3f1242f2020-01-28 13:11:25 -060094 void analyze();
Brandon Wymana0f33ce2019-10-17 18:32:29 -050095
96 /**
Brandon Wyman59a35792020-06-04 12:37:40 -050097 * Write PMBus ON_OFF_CONFIG
98 *
99 * This function will be called to cause the PMBus device driver to send the
100 * ON_OFF_CONFIG command. Takes one byte of data.
101 *
102 * @param[in] data - The ON_OFF_CONFIG data byte mask.
103 */
104 void onOffConfig(uint8_t data);
105
106 /**
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500107 * Write PMBus CLEAR_FAULTS
108 *
109 * This function will be called in various situations in order to clear
110 * any fault status bits that may have been set, in order to start over
111 * with a clean state. Presence changes and power state changes will
112 * want to clear any faults logged.
113 */
Brandon Wyman3c208462020-05-13 16:25:58 -0500114 void clearFaults();
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500115
116 /**
117 * @brief Adds properties to the inventory.
118 *
119 * Reads the values from the device and writes them to the
120 * associated power supply D-Bus inventory object.
121 *
122 * This needs to be done on startup, and each time the presence
123 * state changes.
124 *
125 * Properties added:
126 * - Serial Number
127 * - Part Number
128 * - CCIN (Customer Card Identification Number) - added as the Model
129 * - Firmware version
130 */
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500131 void updateInventory();
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500132
Brandon Wymanaed1f752019-11-25 18:10:52 -0600133 /**
134 * @brief Accessor function to indicate present status
135 */
136 bool isPresent() const
137 {
138 return present;
139 }
140
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600141 /**
Brandon Wymanfed0ba22020-09-26 20:02:51 -0500142 * @brief Returns the last read value from STATUS_WORD.
143 */
144 uint64_t getStatusWord() const
145 {
146 return statusWord;
147 }
148
149 /**
Brandon Wymanf07bc792021-10-12 19:00:35 +0000150 * @brief Returns the last read value from STATUS_INPUT.
151 */
152 uint64_t getStatusInput() const
153 {
154 return statusInput;
155 }
156
157 /**
Jay Meyer10d94052020-11-30 14:41:21 -0600158 * @brief Returns the last read value from STATUS_MFR.
159 */
160 uint64_t getMFRFault() const
161 {
162 return statusMFR;
163 }
164
165 /**
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000166 * @brief Returns the last read value from STATUS_CML.
167 */
168 uint64_t getStatusCML() const
169 {
170 return statusCML;
171 }
172
173 /**
Brandon Wyman6710ba22021-10-27 17:39:31 +0000174 * @brief Returns the last read value from STATUS_VOUT.
175 */
176 uint64_t getStatusVout() const
177 {
178 return statusVout;
179 }
180
181 /**
Brandon Wymanb10b3be2021-11-09 22:12:15 +0000182 * @brief Returns the last value read from STATUS_IOUT.
183 */
184 uint64_t getStatusIout() const
185 {
186 return statusIout;
187 }
188
189 /**
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000190 * @brief Returns the last value read from STATUS_FANS_1_2.
191 */
192 uint64_t getStatusFans12() const
193 {
194 return statusFans12;
195 }
196
197 /**
Brandon Wyman96893a42021-11-05 19:56:57 +0000198 * @brief Returns the last value read from STATUS_TEMPERATURE.
199 */
200 uint64_t getStatusTemperature() const
201 {
202 return statusTemperature;
203 }
204
205 /**
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600206 * @brief Returns true if a fault was found.
207 */
208 bool isFaulted() const
209 {
Brandon Wyman9ddc6222021-10-28 17:28:01 +0000210 return (hasCommFault() || vinUVFault || inputFault || voutOVFault ||
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000211 ioutOCFault || voutUVFault || fanFault || tempFault ||
Brandon Wyman06ca4592021-12-06 22:52:23 +0000212 (pgoodFault >= DEGLITCH_LIMIT) || mfrFault);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600213 }
214
215 /**
Brandon Wymanb76ab242020-09-16 18:06:06 -0500216 * @brief Return whether a fault has been logged for this power supply
217 */
218 bool isFaultLogged() const
219 {
220 return faultLogged;
221 }
222
223 /**
224 * @brief Called when a fault for this power supply has been logged.
225 */
226 void setFaultLogged()
227 {
228 faultLogged = true;
229 }
230
231 /**
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600232 * @brief Returns true if INPUT fault occurred.
233 */
234 bool hasInputFault() const
235 {
236 return inputFault;
237 }
238
239 /**
240 * @brief Returns true if MFRSPECIFIC occurred.
241 */
242 bool hasMFRFault() const
243 {
244 return mfrFault;
245 }
246
247 /**
248 * @brief Returns true if VIN_UV_FAULT occurred.
249 */
250 bool hasVINUVFault() const
251 {
252 return vinUVFault;
253 }
254
Brandon Wymanc9efe412020-10-09 15:42:50 -0500255 /**
Brandon Wyman6710ba22021-10-27 17:39:31 +0000256 * @brief Returns true if VOUT_OV_FAULT occurred.
257 */
258 bool hasVoutOVFault() const
259 {
260 return voutOVFault;
261 }
262
263 /**
Brandon Wymanb10b3be2021-11-09 22:12:15 +0000264 * @brief Returns true if IOUT_OC fault occurred (bit 4 STATUS_BYTE).
265 */
266 bool hasIoutOCFault() const
267 {
268 return ioutOCFault;
269 }
270
271 /**
Brandon Wyman2cf46942021-10-28 19:09:16 +0000272 * @brief Returns true if VOUT_UV_FAULT occurred.
273 */
274 bool hasVoutUVFault() const
275 {
276 return voutUVFault;
277 }
278
279 /**
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000280 *@brief Returns true if fan fault occurred.
281 */
282 bool hasFanFault() const
283 {
284 return fanFault;
285 }
286
287 /**
Brandon Wyman96893a42021-11-05 19:56:57 +0000288 * @brief Returns true if TEMPERATURE fault occurred.
289 */
290 bool hasTempFault() const
291 {
292 return tempFault;
293 }
294
295 /**
Brandon Wyman2916ea52021-11-06 03:31:18 +0000296 * @brief Returns true if there is a PGood fault (PGOOD# inactive, or OFF
297 * bit on).
298 */
299 bool hasPgoodFault() const
300 {
Brandon Wyman06ca4592021-12-06 22:52:23 +0000301 return (pgoodFault >= DEGLITCH_LIMIT);
Brandon Wyman2916ea52021-11-06 03:31:18 +0000302 }
303
304 /**
Brandon Wymanc9efe412020-10-09 15:42:50 -0500305 * @brief Returns the device path
306 *
307 * This can be used for error call outs.
308 * Example: /sys/bus/i2c/devices/3-0068
309 */
Brandon Wyman4176d6b2020-10-07 17:41:06 -0500310 const std::string getDevicePath() const
311 {
312 return pmbusIntf->path();
313 }
314
Brandon Wymanc9efe412020-10-09 15:42:50 -0500315 /**
316 * @brief Returns this power supplies inventory path.
317 *
318 * This can be used for error call outs.
319 * Example:
320 * /xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply1
321 */
Brandon Wyman7e495272020-09-26 19:57:46 -0500322 const std::string& getInventoryPath() const
323 {
324 return inventoryPath;
325 }
326
Brandon Wymanc9efe412020-10-09 15:42:50 -0500327 /**
328 * @brief Returns the firmware revision version read from the power supply
329 */
330 const std::string& getFWVersion() const
331 {
332 return fwVersion;
333 }
334
Adriana Kobylak572a9052021-03-30 15:58:07 +0000335 /**
336 * @brief Returns the model name of the power supply
337 */
338 const std::string& getModelName() const
339 {
340 return modelName;
341 }
342
Brandon Wymanf65c4062020-08-19 13:15:53 -0500343 /** @brief Returns true if the number of failed reads exceeds limit
344 * TODO: or CML bit on.
345 */
346 bool hasCommFault() const
347 {
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000348 return ((readFail >= LOG_LIMIT) || (cmlFault));
Brandon Wymanf65c4062020-08-19 13:15:53 -0500349 }
350
Adriana Kobylak4175ffb2021-08-02 14:51:05 +0000351 /**
352 * @brief Reads the pmbus input voltage and returns that actual voltage
353 * reading and the calculated input voltage based on thresholds.
354 * @param[out] actualInputVoltage - The actual voltage reading, in Volts.
355 * @param[out] inputVoltage - A rounded up/down value of the actual input
356 * voltage based on thresholds, in Volts.
357 */
358 void getInputVoltage(double& actualInputVoltage, int& inputVoltage) const;
359
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500360 private:
Brandon Wymanaed1f752019-11-25 18:10:52 -0600361 /** @brief systemd bus member */
362 sdbusplus::bus::bus& bus;
363
Brandon Wyman9564e942020-11-10 14:01:42 -0600364 /** @brief Will be updated to the latest/lastvalue read from STATUS_WORD.*/
Brandon Wymanfed0ba22020-09-26 20:02:51 -0500365 uint64_t statusWord = 0;
366
Brandon Wymanf07bc792021-10-12 19:00:35 +0000367 /** @brief Will be updated to the latest/lastvalue read from STATUS_INPUT.*/
368 uint64_t statusInput = 0;
369
Jay Meyer10d94052020-11-30 14:41:21 -0600370 /** @brief Will be updated to the latest/lastvalue read from STATUS_MFR.*/
371 uint64_t statusMFR = 0;
372
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000373 /** @brief Will be updated to the latest/last value read from STATUS_CML.*/
374 uint64_t statusCML = 0;
375
Brandon Wyman6710ba22021-10-27 17:39:31 +0000376 /** @brief Will be updated to the latest/last value read from STATUS_VOUT.*/
377 uint64_t statusVout = 0;
378
Brandon Wymanb10b3be2021-11-09 22:12:15 +0000379 /** @brief Will be updated to the latest/last value read from STATUS_IOUT.*/
380 uint64_t statusIout = 0;
381
Brandon Wyman96893a42021-11-05 19:56:57 +0000382 /** @brief Will be updated to the latest/last value read from
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000383 * STATUS_FANS_1_2. */
384 uint64_t statusFans12 = 0;
385
386 /** @brief Will be updated to the latest/last value read from
Brandon Wyman96893a42021-11-05 19:56:57 +0000387 * STATUS_TEMPERATURE.*/
388 uint64_t statusTemperature = 0;
389
Brandon Wymanb76ab242020-09-16 18:06:06 -0500390 /** @brief True if an error for a fault has already been logged. */
391 bool faultLogged = false;
392
Brandon Wyman96893a42021-11-05 19:56:57 +0000393 /** @brief True if bit 1 of STATUS_WORD low byte is on. */
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000394 bool cmlFault = false;
395
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600396 /** @brief True if bit 5 of STATUS_WORD high byte is on. */
397 bool inputFault = false;
398
399 /** @brief True if bit 4 of STATUS_WORD high byte is on. */
400 bool mfrFault = false;
401
402 /** @brief True if bit 3 of STATUS_WORD low byte is on. */
403 bool vinUVFault = false;
404
Brandon Wyman6710ba22021-10-27 17:39:31 +0000405 /** @brief True if bit 5 of STATUS_WORD low byte is on. */
406 bool voutOVFault = false;
407
Brandon Wymanb10b3be2021-11-09 22:12:15 +0000408 /** @brief True if bit 4 of STATUS_WORD low byte is on. */
409 bool ioutOCFault = false;
410
Brandon Wyman2cf46942021-10-28 19:09:16 +0000411 /** @brief True if bit 7 of STATUS_WORD high byte is on and bit 5 (VOUT_OV)
412 * of low byte is off. */
413 bool voutUVFault = false;
414
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000415 /** @brief True if FANS fault/warn bit on in STATUS_WORD. */
416 bool fanFault = false;
417
Brandon Wyman96893a42021-11-05 19:56:57 +0000418 /** @brief True if bit 2 of STATUS_WORD low byte is on. */
419 bool tempFault = false;
420
Brandon Wyman2cf46942021-10-28 19:09:16 +0000421 /**
Brandon Wyman06ca4592021-12-06 22:52:23 +0000422 * @brief Incremented if bit 11 or 6 of STATUS_WORD is on. PGOOD# is
423 * inactive, or the unit is off.
424 *
425 * Considered faulted if reaches DEGLITCH_LIMIT.
Brandon Wyman2916ea52021-11-06 03:31:18 +0000426 */
Brandon Wyman06ca4592021-12-06 22:52:23 +0000427 int pgoodFault = 0;
Brandon Wyman2916ea52021-11-06 03:31:18 +0000428
Brandon Wymanf65c4062020-08-19 13:15:53 -0500429 /** @brief Count of the number of read failures. */
430 size_t readFail = 0;
431
Brandon Wymanaed1f752019-11-25 18:10:52 -0600432 /**
433 * @brief D-Bus path to use for this power supply's inventory status.
434 **/
435 std::string inventoryPath;
436
B. J. Wyman681b2a32021-04-20 22:31:22 +0000437 /**
438 * @brief The libgpiod object for monitoring PSU presence
439 */
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000440 std::unique_ptr<GPIOInterfaceBase> presenceGPIO = nullptr;
B. J. Wyman681b2a32021-04-20 22:31:22 +0000441
Brandon Wymanaed1f752019-11-25 18:10:52 -0600442 /** @brief True if the power supply is present. */
443 bool present = false;
444
Adriana Kobylak572a9052021-03-30 15:58:07 +0000445 /** @brief Power supply model name. */
446 std::string modelName;
447
Brandon Wymanaed1f752019-11-25 18:10:52 -0600448 /** @brief D-Bus match variable used to subscribe to Present property
449 * changes.
450 **/
451 std::unique_ptr<sdbusplus::bus::match_t> presentMatch;
452
453 /** @brief D-Bus match variable used to subscribe for Present property
454 * interface added.
455 */
456 std::unique_ptr<sdbusplus::bus::match_t> presentAddedMatch;
457
458 /**
Brandon Wyman8d195772020-01-27 15:03:51 -0600459 * @brief Pointer to the PMBus interface
460 *
461 * Used to read or write to/from PMBus power supply devices.
462 */
Brandon Wyman9564e942020-11-10 14:01:42 -0600463 std::unique_ptr<phosphor::pmbus::PMBusBase> pmbusIntf = nullptr;
Brandon Wyman8d195772020-01-27 15:03:51 -0600464
Brandon Wymanc9efe412020-10-09 15:42:50 -0500465 /** @brief Stored copy of the firmware version/revision string */
466 std::string fwVersion;
467
Brandon Wyman8d195772020-01-27 15:03:51 -0600468 /**
B. J. Wyman681b2a32021-04-20 22:31:22 +0000469 * @brief The file system path used for binding the device driver.
470 */
471 const std::filesystem::path bindPath;
472
473 /* @brief The string to pass in for binding the device driver. */
474 std::string bindDevice;
475
476 /**
477 * @brief Binds or unbinds the power supply device driver
478 *
479 * Called when a presence change is detected to either bind the device
480 * driver for the power supply when it is installed, or unbind the device
481 * driver when the power supply is removed.
482 *
483 * Writes <device> to <path>/bind (or unbind)
484 *
485 * @param present - when true, will bind the device driver
486 * when false, will unbind the device driver
487 */
488 void bindOrUnbindDriver(bool present);
489
490 /**
Brandon Wymanaed1f752019-11-25 18:10:52 -0600491 * @brief Updates the presence status by querying D-Bus
492 *
493 * The D-Bus inventory properties for this power supply will be read to
494 * determine if the power supply is present or not and update this
495 * object's present member variable to reflect current status.
496 **/
497 void updatePresence();
498
499 /**
B. J. Wyman681b2a32021-04-20 22:31:22 +0000500 * @brief Updates the power supply presence by reading the GPIO line.
501 */
502 void updatePresenceGPIO();
503
504 /**
Brandon Wymanaed1f752019-11-25 18:10:52 -0600505 * @brief Callback for inventory property changes
506 *
507 * Process change of Present property for power supply.
508 *
B. J. Wyman681b2a32021-04-20 22:31:22 +0000509 * This is used if we are watching the D-Bus properties instead of reading
510 * the GPIO presence line ourselves.
511 *
Brandon Wymanaed1f752019-11-25 18:10:52 -0600512 * @param[in] msg - Data associated with Present change signal
513 **/
514 void inventoryChanged(sdbusplus::message::message& msg);
Brandon Wyman9a507db2021-02-25 16:15:22 -0600515
516 /**
517 * @brief Callback for inventory property added.
518 *
519 * Process add of the interface with the Present property for power supply.
520 *
B. J. Wyman681b2a32021-04-20 22:31:22 +0000521 * This is used if we are watching the D-Bus properties instead of reading
522 * the GPIO presence line ourselves.
523 *
Brandon Wyman9a507db2021-02-25 16:15:22 -0600524 * @param[in] msg - Data associated with Present add signal
525 **/
526 void inventoryAdded(sdbusplus::message::message& msg);
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500527};
528
529} // namespace phosphor::power::psu