blob: 320fb65120289f709e7da703f487be4111b0420f [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";
29constexpr auto SN_PROP = "SerialNumber";
30constexpr auto VERSION_PROP = "Version";
31
32// ipzVPD Keyword sizes
33static constexpr auto FL_KW_SIZE = 20;
34#endif
35
Brandon Wymanf65c4062020-08-19 13:15:53 -050036constexpr auto LOG_LIMIT = 3;
Brandon Wyman06ca4592021-12-06 22:52:23 +000037constexpr auto DEGLITCH_LIMIT = 3;
Brandon Wymanf65c4062020-08-19 13:15:53 -050038
Brandon Wymana0f33ce2019-10-17 18:32:29 -050039/**
40 * @class PowerSupply
41 * Represents a PMBus power supply device.
42 */
43class PowerSupply
44{
45 public:
Brandon Wymanaed1f752019-11-25 18:10:52 -060046 PowerSupply() = delete;
Brandon Wymana0f33ce2019-10-17 18:32:29 -050047 PowerSupply(const PowerSupply&) = delete;
48 PowerSupply(PowerSupply&&) = delete;
49 PowerSupply& operator=(const PowerSupply&) = delete;
50 PowerSupply& operator=(PowerSupply&&) = delete;
51 ~PowerSupply() = default;
52
53 /**
Brandon Wymanc63941c2020-01-27 16:49:33 -060054 * @param[in] invpath - String for inventory path to use
55 * @param[in] i2cbus - The bus number this power supply is on
56 * @param[in] i2caddr - The 16-bit I2C address of the power supply
B. J. Wyman681b2a32021-04-20 22:31:22 +000057 * @param[in] gpioLineName - The gpio-line-name to read for presence. See
58 * https://github.com/openbmc/docs/blob/master/designs/device-tree-gpio-naming.md
Brandon Wymanaed1f752019-11-25 18:10:52 -060059 */
Brandon Wymanc63941c2020-01-27 16:49:33 -060060 PowerSupply(sdbusplus::bus::bus& bus, const std::string& invpath,
B. J. Wyman681b2a32021-04-20 22:31:22 +000061 std::uint8_t i2cbus, const std::uint16_t i2caddr,
62 const std::string& gpioLineName);
Brandon Wymanaed1f752019-11-25 18:10:52 -060063
Brandon Wyman3f1242f2020-01-28 13:11:25 -060064 phosphor::pmbus::PMBusBase& getPMBus()
65 {
66 return *pmbusIntf;
67 }
68
Adriana Kobylak3ca062a2021-10-20 15:27:23 +000069 GPIOInterfaceBase* getPresenceGPIO()
B. J. Wyman681b2a32021-04-20 22:31:22 +000070 {
71 return presenceGPIO.get();
72 }
73
B. J. Wymand8b8cb12021-07-15 22:03:34 +000074 std::string getPresenceGPIOName() const
75 {
76 if (presenceGPIO != nullptr)
77 {
78 return presenceGPIO->getName();
79 }
80 else
81 {
82 return std::string();
83 }
84 }
85
Brandon Wymanaed1f752019-11-25 18:10:52 -060086 /**
Brandon Wymana0f33ce2019-10-17 18:32:29 -050087 * Power supply specific function to analyze for faults/errors.
88 *
89 * Various PMBus status bits will be checked for fault conditions.
90 * If a certain fault bits are on, the appropriate error will be
91 * committed.
92 */
Brandon Wyman3f1242f2020-01-28 13:11:25 -060093 void analyze();
Brandon Wymana0f33ce2019-10-17 18:32:29 -050094
95 /**
Brandon Wyman59a35792020-06-04 12:37:40 -050096 * Write PMBus ON_OFF_CONFIG
97 *
98 * This function will be called to cause the PMBus device driver to send the
99 * ON_OFF_CONFIG command. Takes one byte of data.
100 *
101 * @param[in] data - The ON_OFF_CONFIG data byte mask.
102 */
103 void onOffConfig(uint8_t data);
104
105 /**
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500106 * Write PMBus CLEAR_FAULTS
107 *
108 * This function will be called in various situations in order to clear
109 * any fault status bits that may have been set, in order to start over
110 * with a clean state. Presence changes and power state changes will
111 * want to clear any faults logged.
112 */
Brandon Wyman3c208462020-05-13 16:25:58 -0500113 void clearFaults();
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500114
115 /**
116 * @brief Adds properties to the inventory.
117 *
118 * Reads the values from the device and writes them to the
119 * associated power supply D-Bus inventory object.
120 *
121 * This needs to be done on startup, and each time the presence
122 * state changes.
123 *
124 * Properties added:
125 * - Serial Number
126 * - Part Number
127 * - CCIN (Customer Card Identification Number) - added as the Model
128 * - Firmware version
129 */
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500130 void updateInventory();
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500131
Brandon Wymanaed1f752019-11-25 18:10:52 -0600132 /**
133 * @brief Accessor function to indicate present status
134 */
135 bool isPresent() const
136 {
137 return present;
138 }
139
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600140 /**
Brandon Wymanfed0ba22020-09-26 20:02:51 -0500141 * @brief Returns the last read value from STATUS_WORD.
142 */
143 uint64_t getStatusWord() const
144 {
145 return statusWord;
146 }
147
148 /**
Brandon Wymanf07bc792021-10-12 19:00:35 +0000149 * @brief Returns the last read value from STATUS_INPUT.
150 */
151 uint64_t getStatusInput() const
152 {
153 return statusInput;
154 }
155
156 /**
Jay Meyer10d94052020-11-30 14:41:21 -0600157 * @brief Returns the last read value from STATUS_MFR.
158 */
159 uint64_t getMFRFault() const
160 {
161 return statusMFR;
162 }
163
164 /**
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000165 * @brief Returns the last read value from STATUS_CML.
166 */
167 uint64_t getStatusCML() const
168 {
169 return statusCML;
170 }
171
172 /**
Brandon Wyman6710ba22021-10-27 17:39:31 +0000173 * @brief Returns the last read value from STATUS_VOUT.
174 */
175 uint64_t getStatusVout() const
176 {
177 return statusVout;
178 }
179
180 /**
Brandon Wymanb10b3be2021-11-09 22:12:15 +0000181 * @brief Returns the last value read from STATUS_IOUT.
182 */
183 uint64_t getStatusIout() const
184 {
185 return statusIout;
186 }
187
188 /**
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000189 * @brief Returns the last value read from STATUS_FANS_1_2.
190 */
191 uint64_t getStatusFans12() const
192 {
193 return statusFans12;
194 }
195
196 /**
Brandon Wyman96893a42021-11-05 19:56:57 +0000197 * @brief Returns the last value read from STATUS_TEMPERATURE.
198 */
199 uint64_t getStatusTemperature() const
200 {
201 return statusTemperature;
202 }
203
204 /**
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600205 * @brief Returns true if a fault was found.
206 */
207 bool isFaulted() const
208 {
Brandon Wyman9ddc6222021-10-28 17:28:01 +0000209 return (hasCommFault() || vinUVFault || inputFault || voutOVFault ||
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000210 ioutOCFault || voutUVFault || fanFault || tempFault ||
Brandon Wyman06ca4592021-12-06 22:52:23 +0000211 (pgoodFault >= DEGLITCH_LIMIT) || mfrFault);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600212 }
213
214 /**
Brandon Wymanb76ab242020-09-16 18:06:06 -0500215 * @brief Return whether a fault has been logged for this power supply
216 */
217 bool isFaultLogged() const
218 {
219 return faultLogged;
220 }
221
222 /**
223 * @brief Called when a fault for this power supply has been logged.
224 */
225 void setFaultLogged()
226 {
227 faultLogged = true;
228 }
229
230 /**
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600231 * @brief Returns true if INPUT fault occurred.
232 */
233 bool hasInputFault() const
234 {
235 return inputFault;
236 }
237
238 /**
239 * @brief Returns true if MFRSPECIFIC occurred.
240 */
241 bool hasMFRFault() const
242 {
243 return mfrFault;
244 }
245
246 /**
247 * @brief Returns true if VIN_UV_FAULT occurred.
248 */
249 bool hasVINUVFault() const
250 {
251 return vinUVFault;
252 }
253
Brandon Wymanc9efe412020-10-09 15:42:50 -0500254 /**
Brandon Wyman6710ba22021-10-27 17:39:31 +0000255 * @brief Returns true if VOUT_OV_FAULT occurred.
256 */
257 bool hasVoutOVFault() const
258 {
259 return voutOVFault;
260 }
261
262 /**
Brandon Wymanb10b3be2021-11-09 22:12:15 +0000263 * @brief Returns true if IOUT_OC fault occurred (bit 4 STATUS_BYTE).
264 */
265 bool hasIoutOCFault() const
266 {
267 return ioutOCFault;
268 }
269
270 /**
Brandon Wyman2cf46942021-10-28 19:09:16 +0000271 * @brief Returns true if VOUT_UV_FAULT occurred.
272 */
273 bool hasVoutUVFault() const
274 {
275 return voutUVFault;
276 }
277
278 /**
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000279 *@brief Returns true if fan fault occurred.
280 */
281 bool hasFanFault() const
282 {
283 return fanFault;
284 }
285
286 /**
Brandon Wyman96893a42021-11-05 19:56:57 +0000287 * @brief Returns true if TEMPERATURE fault occurred.
288 */
289 bool hasTempFault() const
290 {
291 return tempFault;
292 }
293
294 /**
Brandon Wyman2916ea52021-11-06 03:31:18 +0000295 * @brief Returns true if there is a PGood fault (PGOOD# inactive, or OFF
296 * bit on).
297 */
298 bool hasPgoodFault() const
299 {
Brandon Wyman06ca4592021-12-06 22:52:23 +0000300 return (pgoodFault >= DEGLITCH_LIMIT);
Brandon Wyman2916ea52021-11-06 03:31:18 +0000301 }
302
303 /**
Brandon Wymanc9efe412020-10-09 15:42:50 -0500304 * @brief Returns the device path
305 *
306 * This can be used for error call outs.
307 * Example: /sys/bus/i2c/devices/3-0068
308 */
Brandon Wyman4176d6b2020-10-07 17:41:06 -0500309 const std::string getDevicePath() const
310 {
311 return pmbusIntf->path();
312 }
313
Brandon Wymanc9efe412020-10-09 15:42:50 -0500314 /**
315 * @brief Returns this power supplies inventory path.
316 *
317 * This can be used for error call outs.
318 * Example:
319 * /xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply1
320 */
Brandon Wyman7e495272020-09-26 19:57:46 -0500321 const std::string& getInventoryPath() const
322 {
323 return inventoryPath;
324 }
325
Brandon Wymanc9efe412020-10-09 15:42:50 -0500326 /**
327 * @brief Returns the firmware revision version read from the power supply
328 */
329 const std::string& getFWVersion() const
330 {
331 return fwVersion;
332 }
333
Adriana Kobylak572a9052021-03-30 15:58:07 +0000334 /**
335 * @brief Returns the model name of the power supply
336 */
337 const std::string& getModelName() const
338 {
339 return modelName;
340 }
341
Brandon Wymanf65c4062020-08-19 13:15:53 -0500342 /** @brief Returns true if the number of failed reads exceeds limit
343 * TODO: or CML bit on.
344 */
345 bool hasCommFault() const
346 {
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000347 return ((readFail >= LOG_LIMIT) || (cmlFault));
Brandon Wymanf65c4062020-08-19 13:15:53 -0500348 }
349
Adriana Kobylak4175ffb2021-08-02 14:51:05 +0000350 /**
351 * @brief Reads the pmbus input voltage and returns that actual voltage
352 * reading and the calculated input voltage based on thresholds.
353 * @param[out] actualInputVoltage - The actual voltage reading, in Volts.
354 * @param[out] inputVoltage - A rounded up/down value of the actual input
355 * voltage based on thresholds, in Volts.
356 */
357 void getInputVoltage(double& actualInputVoltage, int& inputVoltage) const;
358
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500359 private:
Brandon Wymanaed1f752019-11-25 18:10:52 -0600360 /** @brief systemd bus member */
361 sdbusplus::bus::bus& bus;
362
Brandon Wyman9564e942020-11-10 14:01:42 -0600363 /** @brief Will be updated to the latest/lastvalue read from STATUS_WORD.*/
Brandon Wymanfed0ba22020-09-26 20:02:51 -0500364 uint64_t statusWord = 0;
365
Brandon Wymanf07bc792021-10-12 19:00:35 +0000366 /** @brief Will be updated to the latest/lastvalue read from STATUS_INPUT.*/
367 uint64_t statusInput = 0;
368
Jay Meyer10d94052020-11-30 14:41:21 -0600369 /** @brief Will be updated to the latest/lastvalue read from STATUS_MFR.*/
370 uint64_t statusMFR = 0;
371
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000372 /** @brief Will be updated to the latest/last value read from STATUS_CML.*/
373 uint64_t statusCML = 0;
374
Brandon Wyman6710ba22021-10-27 17:39:31 +0000375 /** @brief Will be updated to the latest/last value read from STATUS_VOUT.*/
376 uint64_t statusVout = 0;
377
Brandon Wymanb10b3be2021-11-09 22:12:15 +0000378 /** @brief Will be updated to the latest/last value read from STATUS_IOUT.*/
379 uint64_t statusIout = 0;
380
Brandon Wyman96893a42021-11-05 19:56:57 +0000381 /** @brief Will be updated to the latest/last value read from
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000382 * STATUS_FANS_1_2. */
383 uint64_t statusFans12 = 0;
384
385 /** @brief Will be updated to the latest/last value read from
Brandon Wyman96893a42021-11-05 19:56:57 +0000386 * STATUS_TEMPERATURE.*/
387 uint64_t statusTemperature = 0;
388
Brandon Wymanb76ab242020-09-16 18:06:06 -0500389 /** @brief True if an error for a fault has already been logged. */
390 bool faultLogged = false;
391
Brandon Wyman96893a42021-11-05 19:56:57 +0000392 /** @brief True if bit 1 of STATUS_WORD low byte is on. */
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000393 bool cmlFault = false;
394
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600395 /** @brief True if bit 5 of STATUS_WORD high byte is on. */
396 bool inputFault = false;
397
398 /** @brief True if bit 4 of STATUS_WORD high byte is on. */
399 bool mfrFault = false;
400
401 /** @brief True if bit 3 of STATUS_WORD low byte is on. */
402 bool vinUVFault = false;
403
Brandon Wyman6710ba22021-10-27 17:39:31 +0000404 /** @brief True if bit 5 of STATUS_WORD low byte is on. */
405 bool voutOVFault = false;
406
Brandon Wymanb10b3be2021-11-09 22:12:15 +0000407 /** @brief True if bit 4 of STATUS_WORD low byte is on. */
408 bool ioutOCFault = false;
409
Brandon Wyman2cf46942021-10-28 19:09:16 +0000410 /** @brief True if bit 7 of STATUS_WORD high byte is on and bit 5 (VOUT_OV)
411 * of low byte is off. */
412 bool voutUVFault = false;
413
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000414 /** @brief True if FANS fault/warn bit on in STATUS_WORD. */
415 bool fanFault = false;
416
Brandon Wyman96893a42021-11-05 19:56:57 +0000417 /** @brief True if bit 2 of STATUS_WORD low byte is on. */
418 bool tempFault = false;
419
Brandon Wyman2cf46942021-10-28 19:09:16 +0000420 /**
Brandon Wyman06ca4592021-12-06 22:52:23 +0000421 * @brief Incremented if bit 11 or 6 of STATUS_WORD is on. PGOOD# is
422 * inactive, or the unit is off.
423 *
424 * Considered faulted if reaches DEGLITCH_LIMIT.
Brandon Wyman2916ea52021-11-06 03:31:18 +0000425 */
Brandon Wyman06ca4592021-12-06 22:52:23 +0000426 int pgoodFault = 0;
Brandon Wyman2916ea52021-11-06 03:31:18 +0000427
Brandon Wymanf65c4062020-08-19 13:15:53 -0500428 /** @brief Count of the number of read failures. */
429 size_t readFail = 0;
430
Brandon Wymanaed1f752019-11-25 18:10:52 -0600431 /**
432 * @brief D-Bus path to use for this power supply's inventory status.
433 **/
434 std::string inventoryPath;
435
B. J. Wyman681b2a32021-04-20 22:31:22 +0000436 /**
437 * @brief The libgpiod object for monitoring PSU presence
438 */
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000439 std::unique_ptr<GPIOInterfaceBase> presenceGPIO = nullptr;
B. J. Wyman681b2a32021-04-20 22:31:22 +0000440
Brandon Wymanaed1f752019-11-25 18:10:52 -0600441 /** @brief True if the power supply is present. */
442 bool present = false;
443
Adriana Kobylak572a9052021-03-30 15:58:07 +0000444 /** @brief Power supply model name. */
445 std::string modelName;
446
Brandon Wymanaed1f752019-11-25 18:10:52 -0600447 /** @brief D-Bus match variable used to subscribe to Present property
448 * changes.
449 **/
450 std::unique_ptr<sdbusplus::bus::match_t> presentMatch;
451
452 /** @brief D-Bus match variable used to subscribe for Present property
453 * interface added.
454 */
455 std::unique_ptr<sdbusplus::bus::match_t> presentAddedMatch;
456
457 /**
Brandon Wyman8d195772020-01-27 15:03:51 -0600458 * @brief Pointer to the PMBus interface
459 *
460 * Used to read or write to/from PMBus power supply devices.
461 */
Brandon Wyman9564e942020-11-10 14:01:42 -0600462 std::unique_ptr<phosphor::pmbus::PMBusBase> pmbusIntf = nullptr;
Brandon Wyman8d195772020-01-27 15:03:51 -0600463
Brandon Wymanc9efe412020-10-09 15:42:50 -0500464 /** @brief Stored copy of the firmware version/revision string */
465 std::string fwVersion;
466
Brandon Wyman8d195772020-01-27 15:03:51 -0600467 /**
B. J. Wyman681b2a32021-04-20 22:31:22 +0000468 * @brief The file system path used for binding the device driver.
469 */
470 const std::filesystem::path bindPath;
471
472 /* @brief The string to pass in for binding the device driver. */
473 std::string bindDevice;
474
475 /**
476 * @brief Binds or unbinds the power supply device driver
477 *
478 * Called when a presence change is detected to either bind the device
479 * driver for the power supply when it is installed, or unbind the device
480 * driver when the power supply is removed.
481 *
482 * Writes <device> to <path>/bind (or unbind)
483 *
484 * @param present - when true, will bind the device driver
485 * when false, will unbind the device driver
486 */
487 void bindOrUnbindDriver(bool present);
488
489 /**
Brandon Wymanaed1f752019-11-25 18:10:52 -0600490 * @brief Updates the presence status by querying D-Bus
491 *
492 * The D-Bus inventory properties for this power supply will be read to
493 * determine if the power supply is present or not and update this
494 * object's present member variable to reflect current status.
495 **/
496 void updatePresence();
497
498 /**
B. J. Wyman681b2a32021-04-20 22:31:22 +0000499 * @brief Updates the power supply presence by reading the GPIO line.
500 */
501 void updatePresenceGPIO();
502
503 /**
Brandon Wymanaed1f752019-11-25 18:10:52 -0600504 * @brief Callback for inventory property changes
505 *
506 * Process change of Present property for power supply.
507 *
B. J. Wyman681b2a32021-04-20 22:31:22 +0000508 * This is used if we are watching the D-Bus properties instead of reading
509 * the GPIO presence line ourselves.
510 *
Brandon Wymanaed1f752019-11-25 18:10:52 -0600511 * @param[in] msg - Data associated with Present change signal
512 **/
513 void inventoryChanged(sdbusplus::message::message& msg);
Brandon Wyman9a507db2021-02-25 16:15:22 -0600514
515 /**
516 * @brief Callback for inventory property added.
517 *
518 * Process add of the interface with the Present property for power supply.
519 *
B. J. Wyman681b2a32021-04-20 22:31:22 +0000520 * This is used if we are watching the D-Bus properties instead of reading
521 * the GPIO presence line ourselves.
522 *
Brandon Wyman9a507db2021-02-25 16:15:22 -0600523 * @param[in] msg - Data associated with Present add signal
524 **/
525 void inventoryAdded(sdbusplus::message::message& msg);
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500526};
527
528} // namespace phosphor::power::psu