xref: /openbmc/phosphor-power/phosphor-power-supply/power_supply.hpp (revision b3ba516f3f418b9b1a98d4bd27210799383262b2)
1 #pragma once
2 
3 #include "pmbus.hpp"
4 #include "types.hpp"
5 #include "util.hpp"
6 #include "utility.hpp"
7 
8 #include <gpiod.hpp>
9 #include <sdbusplus/bus/match.hpp>
10 
11 #include <filesystem>
12 #include <stdexcept>
13 
14 namespace phosphor::power::psu
15 {
16 
17 #if IBM_VPD
18 // PMBus device driver "file name" to read for CCIN value.
19 constexpr auto CCIN = "ccin";
20 constexpr auto PART_NUMBER = "part_number";
21 constexpr auto FRU_NUMBER = "fru";
22 constexpr auto SERIAL_HEADER = "header";
23 constexpr auto SERIAL_NUMBER = "serial_number";
24 constexpr auto FW_VERSION = "fw_version";
25 
26 // The D-Bus property name to update with the CCIN value.
27 constexpr auto MODEL_PROP = "Model";
28 constexpr auto PN_PROP = "PartNumber";
29 constexpr auto SN_PROP = "SerialNumber";
30 constexpr auto VERSION_PROP = "Version";
31 
32 // ipzVPD Keyword sizes
33 static constexpr auto FL_KW_SIZE = 20;
34 #endif
35 
36 constexpr auto LOG_LIMIT = 3;
37 
38 /**
39  * @class PowerSupply
40  * Represents a PMBus power supply device.
41  */
42 class PowerSupply
43 {
44   public:
45     PowerSupply() = delete;
46     PowerSupply(const PowerSupply&) = delete;
47     PowerSupply(PowerSupply&&) = delete;
48     PowerSupply& operator=(const PowerSupply&) = delete;
49     PowerSupply& operator=(PowerSupply&&) = delete;
50     ~PowerSupply() = default;
51 
52     /**
53      * @param[in] invpath - String for inventory path to use
54      * @param[in] i2cbus - The bus number this power supply is on
55      * @param[in] i2caddr - The 16-bit I2C address of the power supply
56      * @param[in] gpioLineName - The gpio-line-name to read for presence. See
57      * https://github.com/openbmc/docs/blob/master/designs/device-tree-gpio-naming.md
58      */
59     PowerSupply(sdbusplus::bus::bus& bus, const std::string& invpath,
60                 std::uint8_t i2cbus, const std::uint16_t i2caddr,
61                 const std::string& gpioLineName);
62 
63     phosphor::pmbus::PMBusBase& getPMBus()
64     {
65         return *pmbusIntf;
66     }
67 
68     GPIOInterfaceBase* getPresenceGPIO()
69     {
70         return presenceGPIO.get();
71     }
72 
73     std::string getPresenceGPIOName() const
74     {
75         if (presenceGPIO != nullptr)
76         {
77             return presenceGPIO->getName();
78         }
79         else
80         {
81             return std::string();
82         }
83     }
84 
85     /**
86      * Power supply specific function to analyze for faults/errors.
87      *
88      * Various PMBus status bits will be checked for fault conditions.
89      * If a certain fault bits are on, the appropriate error will be
90      * committed.
91      */
92     void analyze();
93 
94     /**
95      * Write PMBus ON_OFF_CONFIG
96      *
97      * This function will be called to cause the PMBus device driver to send the
98      * ON_OFF_CONFIG command. Takes one byte of data.
99      *
100      * @param[in] data - The ON_OFF_CONFIG data byte mask.
101      */
102     void onOffConfig(uint8_t data);
103 
104     /**
105      * Write PMBus CLEAR_FAULTS
106      *
107      * This function will be called in various situations in order to clear
108      * any fault status bits that may have been set, in order to start over
109      * with a clean state. Presence changes and power state changes will
110      * want to clear any faults logged.
111      */
112     void clearFaults();
113 
114     /**
115      * @brief Adds properties to the inventory.
116      *
117      * Reads the values from the device and writes them to the
118      * associated power supply D-Bus inventory object.
119      *
120      * This needs to be done on startup, and each time the presence
121      * state changes.
122      *
123      * Properties added:
124      * - Serial Number
125      * - Part Number
126      * - CCIN (Customer Card Identification Number) - added as the Model
127      * - Firmware version
128      */
129     void updateInventory();
130 
131     /**
132      * @brief Accessor function to indicate present status
133      */
134     bool isPresent() const
135     {
136         return present;
137     }
138 
139     /**
140      * @brief Returns the last read value from STATUS_WORD.
141      */
142     uint64_t getStatusWord() const
143     {
144         return statusWord;
145     }
146 
147     /**
148      * @brief Returns the last read value from STATUS_INPUT.
149      */
150     uint64_t getStatusInput() const
151     {
152         return statusInput;
153     }
154 
155     /**
156      * @brief Returns the last read value from STATUS_MFR.
157      */
158     uint64_t getMFRFault() const
159     {
160         return statusMFR;
161     }
162 
163     /**
164      * @brief Returns the last read value from STATUS_CML.
165      */
166     uint64_t getStatusCML() const
167     {
168         return statusCML;
169     }
170 
171     /**
172      * @brief Returns the last read value from STATUS_VOUT.
173      */
174     uint64_t getStatusVout() const
175     {
176         return statusVout;
177     }
178 
179     /**
180      * @brief Returns the last value read from STATUS_IOUT.
181      */
182     uint64_t getStatusIout() const
183     {
184         return statusIout;
185     }
186 
187     /**
188      * @brief Returns the last value read from STATUS_FANS_1_2.
189      */
190     uint64_t getStatusFans12() const
191     {
192         return statusFans12;
193     }
194 
195     /**
196      * @brief Returns the last value read from STATUS_TEMPERATURE.
197      */
198     uint64_t getStatusTemperature() const
199     {
200         return statusTemperature;
201     }
202 
203     /**
204      * @brief Returns true if a fault was found.
205      */
206     bool isFaulted() const
207     {
208         return (hasCommFault() || vinUVFault || inputFault || voutOVFault ||
209                 ioutOCFault || voutUVFault || fanFault || tempFault ||
210                 pgoodFault || mfrFault);
211     }
212 
213     /**
214      * @brief Return whether a fault has been logged for this power supply
215      */
216     bool isFaultLogged() const
217     {
218         return faultLogged;
219     }
220 
221     /**
222      * @brief Called when a fault for this power supply has been logged.
223      */
224     void setFaultLogged()
225     {
226         faultLogged = true;
227     }
228 
229     /**
230      * @brief Returns true if INPUT fault occurred.
231      */
232     bool hasInputFault() const
233     {
234         return inputFault;
235     }
236 
237     /**
238      * @brief Returns true if MFRSPECIFIC occurred.
239      */
240     bool hasMFRFault() const
241     {
242         return mfrFault;
243     }
244 
245     /**
246      * @brief Returns true if VIN_UV_FAULT occurred.
247      */
248     bool hasVINUVFault() const
249     {
250         return vinUVFault;
251     }
252 
253     /**
254      * @brief Returns true if VOUT_OV_FAULT occurred.
255      */
256     bool hasVoutOVFault() const
257     {
258         return voutOVFault;
259     }
260 
261     /**
262      * @brief Returns true if IOUT_OC fault occurred (bit 4 STATUS_BYTE).
263      */
264     bool hasIoutOCFault() const
265     {
266         return ioutOCFault;
267     }
268 
269     /**
270      * @brief Returns true if VOUT_UV_FAULT occurred.
271      */
272     bool hasVoutUVFault() const
273     {
274         return voutUVFault;
275     }
276 
277     /**
278      *@brief Returns true if fan fault occurred.
279      */
280     bool hasFanFault() const
281     {
282         return fanFault;
283     }
284 
285     /**
286      * @brief Returns true if TEMPERATURE fault occurred.
287      */
288     bool hasTempFault() const
289     {
290         return tempFault;
291     }
292 
293     /**
294      * @brief Returns true if there is a PGood fault (PGOOD# inactive, or OFF
295      * bit on).
296      */
297     bool hasPgoodFault() const
298     {
299         return pgoodFault;
300     }
301 
302     /**
303      * @brief Returns the device path
304      *
305      * This can be used for error call outs.
306      * Example: /sys/bus/i2c/devices/3-0068
307      */
308     const std::string getDevicePath() const
309     {
310         return pmbusIntf->path();
311     }
312 
313     /**
314      * @brief Returns this power supplies inventory path.
315      *
316      * This can be used for error call outs.
317      * Example:
318      * /xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply1
319      */
320     const std::string& getInventoryPath() const
321     {
322         return inventoryPath;
323     }
324 
325     /**
326      * @brief Returns the firmware revision version read from the power supply
327      */
328     const std::string& getFWVersion() const
329     {
330         return fwVersion;
331     }
332 
333     /**
334      * @brief Returns the model name of the power supply
335      */
336     const std::string& getModelName() const
337     {
338         return modelName;
339     }
340 
341     /** @brief Returns true if the number of failed reads exceeds limit
342      * TODO: or CML bit on.
343      */
344     bool hasCommFault() const
345     {
346         return ((readFail >= LOG_LIMIT) || (cmlFault));
347     }
348 
349     /**
350      * @brief Reads the pmbus input voltage and returns that actual voltage
351      *        reading and the calculated input voltage based on thresholds.
352      * @param[out] actualInputVoltage - The actual voltage reading, in Volts.
353      * @param[out] inputVoltage - A rounded up/down value of the actual input
354      *             voltage based on thresholds, in Volts.
355      */
356     void getInputVoltage(double& actualInputVoltage, int& inputVoltage) const;
357 
358   private:
359     /** @brief systemd bus member */
360     sdbusplus::bus::bus& bus;
361 
362     /** @brief Will be updated to the latest/lastvalue read from STATUS_WORD.*/
363     uint64_t statusWord = 0;
364 
365     /** @brief Will be updated to the latest/lastvalue read from STATUS_INPUT.*/
366     uint64_t statusInput = 0;
367 
368     /** @brief Will be updated to the latest/lastvalue read from STATUS_MFR.*/
369     uint64_t statusMFR = 0;
370 
371     /** @brief Will be updated to the latest/last value read from STATUS_CML.*/
372     uint64_t statusCML = 0;
373 
374     /** @brief Will be updated to the latest/last value read from STATUS_VOUT.*/
375     uint64_t statusVout = 0;
376 
377     /** @brief Will be updated to the latest/last value read from STATUS_IOUT.*/
378     uint64_t statusIout = 0;
379 
380     /** @brief Will be updated to the latest/last value read from
381      * STATUS_FANS_1_2. */
382     uint64_t statusFans12 = 0;
383 
384     /** @brief Will be updated to the latest/last value read from
385      * STATUS_TEMPERATURE.*/
386     uint64_t statusTemperature = 0;
387 
388     /** @brief True if an error for a fault has already been logged. */
389     bool faultLogged = false;
390 
391     /** @brief True if bit 1 of STATUS_WORD low byte is on. */
392     bool cmlFault = false;
393 
394     /** @brief True if bit 5 of STATUS_WORD high byte is on. */
395     bool inputFault = false;
396 
397     /** @brief True if bit 4 of STATUS_WORD high byte is on. */
398     bool mfrFault = false;
399 
400     /** @brief True if bit 3 of STATUS_WORD low byte is on. */
401     bool vinUVFault = false;
402 
403     /** @brief True if bit 5 of STATUS_WORD low byte is on. */
404     bool voutOVFault = false;
405 
406     /** @brief True if bit 4 of STATUS_WORD low byte is on. */
407     bool ioutOCFault = false;
408 
409     /** @brief True if bit 7 of STATUS_WORD high byte is on and bit 5 (VOUT_OV)
410      * of low byte is off. */
411     bool voutUVFault = false;
412 
413     /** @brief True if FANS fault/warn bit on in STATUS_WORD. */
414     bool fanFault = false;
415 
416     /** @brief True if bit 2 of STATUS_WORD low byte is on. */
417     bool tempFault = false;
418 
419     /**
420      * @brief True if bit 11 or 6 of STATUS_WORD is on. PGOOD# is inactive, or
421      * the unit is off.
422      */
423     bool pgoodFault = false;
424 
425     /** @brief Count of the number of read failures. */
426     size_t readFail = 0;
427 
428     /**
429      * @brief D-Bus path to use for this power supply's inventory status.
430      **/
431     std::string inventoryPath;
432 
433     /**
434      * @brief The libgpiod object for monitoring PSU presence
435      */
436     std::unique_ptr<GPIOInterfaceBase> presenceGPIO = nullptr;
437 
438     /** @brief True if the power supply is present. */
439     bool present = false;
440 
441     /** @brief Power supply model name. */
442     std::string modelName;
443 
444     /** @brief D-Bus match variable used to subscribe to Present property
445      * changes.
446      **/
447     std::unique_ptr<sdbusplus::bus::match_t> presentMatch;
448 
449     /** @brief D-Bus match variable used to subscribe for Present property
450      * interface added.
451      */
452     std::unique_ptr<sdbusplus::bus::match_t> presentAddedMatch;
453 
454     /**
455      * @brief Pointer to the PMBus interface
456      *
457      * Used to read or write to/from PMBus power supply devices.
458      */
459     std::unique_ptr<phosphor::pmbus::PMBusBase> pmbusIntf = nullptr;
460 
461     /** @brief Stored copy of the firmware version/revision string */
462     std::string fwVersion;
463 
464     /**
465      * @brief The file system path used for binding the device driver.
466      */
467     const std::filesystem::path bindPath;
468 
469     /* @brief The string to pass in for binding the device driver. */
470     std::string bindDevice;
471 
472     /**
473      * @brief Binds or unbinds the power supply device driver
474      *
475      * Called when a presence change is detected to either bind the device
476      * driver for the power supply when it is installed, or unbind the device
477      * driver when the power supply is removed.
478      *
479      * Writes <device> to <path>/bind (or unbind)
480      *
481      * @param present - when true, will bind the device driver
482      *                  when false, will unbind the device driver
483      */
484     void bindOrUnbindDriver(bool present);
485 
486     /**
487      *  @brief Updates the presence status by querying D-Bus
488      *
489      * The D-Bus inventory properties for this power supply will be read to
490      * determine if the power supply is present or not and update this
491      * object's present member variable to reflect current status.
492      **/
493     void updatePresence();
494 
495     /**
496      * @brief Updates the power supply presence by reading the GPIO line.
497      */
498     void updatePresenceGPIO();
499 
500     /**
501      * @brief Callback for inventory property changes
502      *
503      * Process change of Present property for power supply.
504      *
505      * This is used if we are watching the D-Bus properties instead of reading
506      * the GPIO presence line ourselves.
507      *
508      * @param[in]  msg - Data associated with Present change signal
509      **/
510     void inventoryChanged(sdbusplus::message::message& msg);
511 
512     /**
513      * @brief Callback for inventory property added.
514      *
515      * Process add of the interface with the Present property for power supply.
516      *
517      * This is used if we are watching the D-Bus properties instead of reading
518      * the GPIO presence line ourselves.
519      *
520      * @param[in]  msg - Data associated with Present add signal
521      **/
522     void inventoryAdded(sdbusplus::message::message& msg);
523 };
524 
525 } // namespace phosphor::power::psu
526