1 #pragma once
2 
3 #include "average.hpp"
4 #include "maximum.hpp"
5 #include "pmbus.hpp"
6 #include "record_manager.hpp"
7 #include "types.hpp"
8 #include "util.hpp"
9 #include "utility.hpp"
10 
11 #include <gpiod.hpp>
12 #include <sdbusplus/bus/match.hpp>
13 #include <xyz/openbmc_project/Sensor/Value/server.hpp>
14 
15 #include <filesystem>
16 #include <stdexcept>
17 
18 namespace phosphor::power::psu
19 {
20 
21 #if IBM_VPD
22 // PMBus device driver "file name" to read for CCIN value.
23 constexpr auto CCIN = "ccin";
24 constexpr auto PART_NUMBER = "mfr_revision";
25 constexpr auto FRU_NUMBER = "mfr_model";
26 constexpr auto SERIAL_HEADER = "mfr_location";
27 constexpr auto SERIAL_NUMBER = "mfr_serial";
28 constexpr auto FW_VERSION = "fw_version";
29 
30 // The D-Bus property name to update with the CCIN value.
31 constexpr auto MODEL_PROP = "Model";
32 constexpr auto PN_PROP = "PartNumber";
33 constexpr auto SPARE_PN_PROP = "SparePartNumber";
34 constexpr auto SN_PROP = "SerialNumber";
35 constexpr auto VERSION_PROP = "Version";
36 
37 // ipzVPD Keyword sizes
38 static constexpr auto FL_KW_SIZE = 20;
39 static constexpr auto FN_KW_SIZE = 7;
40 static constexpr auto PN_KW_SIZE = 7;
41 // For IBM power supplies, the SN is 6-byte header + 6-byte serial.
42 static constexpr auto SN_KW_SIZE = 12;
43 static constexpr auto CC_KW_SIZE = 4;
44 #endif
45 
46 constexpr auto LOG_LIMIT = 3;
47 constexpr auto DEGLITCH_LIMIT = 3;
48 constexpr auto PGOOD_DEGLITCH_LIMIT = 5;
49 // Number of polls to remember that an AC fault occured. Should remain greater
50 // than PGOOD_DEGLITCH_LIMIT.
51 constexpr auto AC_FAULT_LIMIT = 6;
52 
53 constexpr auto IBMCFFPS_DD_NAME = "ibm-cffps";
54 
55 using SensorInterface = sdbusplus::xyz::openbmc_project::Sensor::server::Value;
56 using SensorObject = sdbusplus::server::object_t<SensorInterface>;
57 
58 /**
59  * @class PowerSupply
60  * Represents a PMBus power supply device.
61  */
62 class PowerSupply
63 {
64   public:
65     PowerSupply() = delete;
66     PowerSupply(const PowerSupply&) = delete;
67     PowerSupply(PowerSupply&&) = delete;
68     PowerSupply& operator=(const PowerSupply&) = delete;
69     PowerSupply& operator=(PowerSupply&&) = delete;
70     ~PowerSupply() = default;
71 
72     /**
73      * @param[in] invpath - String for inventory path to use
74      * @param[in] i2cbus - The bus number this power supply is on
75      * @param[in] i2caddr - The 16-bit I2C address of the power supply
76      * @param[in] driver - i2c driver name for power supply
77      * @param[in] gpioLineName - The gpio-line-name to read for presence. See
78      * https://github.com/openbmc/docs/blob/master/designs/device-tree-gpio-naming.md
79      * @param[in] callback - Get the power on status of the psu manager class
80      */
81     PowerSupply(sdbusplus::bus_t& bus, const std::string& invpath,
82                 std::uint8_t i2cbus, const std::uint16_t i2caddr,
83                 const std::string& driver, const std::string& gpioLineName,
84                 std::function<bool()>&& callback);
85 
86     phosphor::pmbus::PMBusBase& getPMBus()
87     {
88         return *pmbusIntf;
89     }
90 
91     GPIOInterfaceBase* getPresenceGPIO()
92     {
93         return presenceGPIO.get();
94     }
95 
96     std::string getPresenceGPIOName() const
97     {
98         if (presenceGPIO != nullptr)
99         {
100             return presenceGPIO->getName();
101         }
102         else
103         {
104             return std::string();
105         }
106     }
107 
108     /**
109      * Power supply specific function to analyze for faults/errors.
110      *
111      * Various PMBus status bits will be checked for fault conditions.
112      * If a certain fault bits are on, the appropriate error will be
113      * committed.
114      */
115     void analyze();
116 
117     /**
118      * Write PMBus ON_OFF_CONFIG
119      *
120      * This function will be called to cause the PMBus device driver to send the
121      * ON_OFF_CONFIG command. Takes one byte of data.
122      *
123      * @param[in] data - The ON_OFF_CONFIG data byte mask.
124      */
125     void onOffConfig(uint8_t data);
126 
127     /**
128      * Clears all the member variables that indicate if a fault bit was seen as
129      * on in the STATUS_WORD or STATUS_MFR_SPECIFIC response.
130      */
131     void clearFaultFlags()
132     {
133         inputFault = 0;
134         mfrFault = 0;
135         statusMFR = 0;
136         vinUVFault = 0;
137         cmlFault = 0;
138         voutOVFault = 0;
139         ioutOCFault = 0;
140         voutUVFault = 0;
141         fanFault = 0;
142         tempFault = 0;
143         pgoodFault = 0;
144         psKillFault = 0;
145         ps12VcsFault = 0;
146         psCS12VFault = 0;
147         faultLogged = false;
148     }
149 
150     /**
151      * @brief Function to specifically clear VIN_UV/OFF fault(s).
152      *
153      * The PMBus HWMON device driver has various alarm "files" to read out of
154      * sysfs. Reading those files will indicate if various alarms are active or
155      * not, and then specifically clear those faults that go with that alarm.
156      *
157      * The VIN_UV fault, indicated in STATUS_INPUT, goes with in1_lcrit_alarm.
158      * When a VIN_UV fault occurs, the "Unit Off For Insufficient Input Voltage"
159      * may also be active. Reading in1_lcrit_alarm should clear both fault bits,
160      * resulting in the corresponding fault bits in STATUS_WORD also clearing.
161      *
162      * See: https://www.kernel.org/doc/html/latest/hwmon/pmbus.html
163      */
164     void clearVinUVFault();
165 
166     /**
167      * Write PMBus CLEAR_FAULTS
168      *
169      * This function will be called in various situations in order to clear
170      * any fault status bits that may have been set, in order to start over
171      * with a clean state. Presence changes and power state changes will
172      * want to clear any faults logged.
173      */
174     void clearFaults();
175 
176     /**
177      * @brief Adds properties to the inventory.
178      *
179      * Reads the values from the device and writes them to the
180      * associated power supply D-Bus inventory object.
181      *
182      * This needs to be done on startup, and each time the presence
183      * state changes.
184      *
185      * Properties added:
186      * - Serial Number
187      * - Part Number
188      * - CCIN (Customer Card Identification Number) - added as the Model
189      * - Firmware version
190      */
191     void updateInventory();
192 
193     /**
194      * @brief Accessor function to indicate present status
195      */
196     bool isPresent() const
197     {
198         return present;
199     }
200 
201     /**
202      * @brief Returns the last read value from STATUS_WORD.
203      */
204     uint64_t getStatusWord() const
205     {
206         return statusWord;
207     }
208 
209     /**
210      * @brief Returns the last read value from STATUS_INPUT.
211      */
212     uint64_t getStatusInput() const
213     {
214         return statusInput;
215     }
216 
217     /**
218      * @brief Returns the last read value from STATUS_MFR.
219      */
220     uint64_t getMFRFault() const
221     {
222         return statusMFR;
223     }
224 
225     /**
226      * @brief Returns the last read value from STATUS_CML.
227      */
228     uint64_t getStatusCML() const
229     {
230         return statusCML;
231     }
232 
233     /**
234      * @brief Returns the last read value from STATUS_VOUT.
235      */
236     uint64_t getStatusVout() const
237     {
238         return statusVout;
239     }
240 
241     /**
242      * @brief Returns the last value read from STATUS_IOUT.
243      */
244     uint64_t getStatusIout() const
245     {
246         return statusIout;
247     }
248 
249     /**
250      * @brief Returns the last value read from STATUS_FANS_1_2.
251      */
252     uint64_t getStatusFans12() const
253     {
254         return statusFans12;
255     }
256 
257     /**
258      * @brief Returns the last value read from STATUS_TEMPERATURE.
259      */
260     uint64_t getStatusTemperature() const
261     {
262         return statusTemperature;
263     }
264 
265     /**
266      * @brief Returns true if a fault was found.
267      */
268     bool isFaulted() const
269     {
270         return (hasCommFault() || (vinUVFault >= DEGLITCH_LIMIT) ||
271                 (inputFault >= DEGLITCH_LIMIT) ||
272                 (voutOVFault >= DEGLITCH_LIMIT) ||
273                 (ioutOCFault >= DEGLITCH_LIMIT) ||
274                 (voutUVFault >= DEGLITCH_LIMIT) ||
275                 (fanFault >= DEGLITCH_LIMIT) || (tempFault >= DEGLITCH_LIMIT) ||
276                 (pgoodFault >= PGOOD_DEGLITCH_LIMIT) ||
277                 (mfrFault >= DEGLITCH_LIMIT));
278     }
279 
280     /**
281      * @brief Return whether a fault has been logged for this power supply
282      */
283     bool isFaultLogged() const
284     {
285         return faultLogged;
286     }
287 
288     /**
289      * @brief Called when a fault for this power supply has been logged.
290      */
291     void setFaultLogged()
292     {
293         faultLogged = true;
294     }
295 
296     /**
297      * @brief Returns true if INPUT fault occurred.
298      */
299     bool hasInputFault() const
300     {
301         return (inputFault >= DEGLITCH_LIMIT);
302     }
303 
304     /**
305      * @brief Returns true if MFRSPECIFIC occurred.
306      */
307     bool hasMFRFault() const
308     {
309         return (mfrFault >= DEGLITCH_LIMIT);
310     }
311 
312     /**
313      * @brief Returns true if VIN_UV_FAULT occurred.
314      */
315     bool hasVINUVFault() const
316     {
317         return (vinUVFault >= DEGLITCH_LIMIT);
318     }
319 
320     /**
321      * @brief Returns true if VOUT_OV_FAULT occurred.
322      */
323     bool hasVoutOVFault() const
324     {
325         return (voutOVFault >= DEGLITCH_LIMIT);
326     }
327 
328     /**
329      * @brief Returns true if IOUT_OC fault occurred (bit 4 STATUS_BYTE).
330      */
331     bool hasIoutOCFault() const
332     {
333         return (ioutOCFault >= DEGLITCH_LIMIT);
334     }
335 
336     /**
337      * @brief Returns true if VOUT_UV_FAULT occurred.
338      */
339     bool hasVoutUVFault() const
340     {
341         return (voutUVFault >= DEGLITCH_LIMIT);
342     }
343 
344     /**
345      *@brief Returns true if fan fault occurred.
346      */
347     bool hasFanFault() const
348     {
349         return (fanFault >= DEGLITCH_LIMIT);
350     }
351 
352     /**
353      * @brief Returns true if TEMPERATURE fault occurred.
354      */
355     bool hasTempFault() const
356     {
357         return (tempFault >= DEGLITCH_LIMIT);
358     }
359 
360     /**
361      * @brief Returns true if there is a PGood fault (PGOOD# inactive, or OFF
362      * bit on).
363      */
364     bool hasPgoodFault() const
365     {
366         return (pgoodFault >= PGOOD_DEGLITCH_LIMIT);
367     }
368 
369     /**
370      * @brief Return true if there is a PS_Kill fault.
371      */
372     bool hasPSKillFault() const
373     {
374         return (psKillFault >= DEGLITCH_LIMIT);
375     }
376 
377     /**
378      * @brief Returns true if there is a 12Vcs (standy power) fault.
379      */
380     bool hasPS12VcsFault() const
381     {
382         return (ps12VcsFault >= DEGLITCH_LIMIT);
383     }
384 
385     /**
386      * @brief Returns true if there is a 12V current-share fault.
387      */
388     bool hasPSCS12VFault() const
389     {
390         return (psCS12VFault >= DEGLITCH_LIMIT);
391     }
392 
393     /**
394      * @brief Returns true if an AC fault has occurred in the window of
395      * interest.
396      */
397     bool hasACFault() const
398     {
399         return acFault != 0;
400     }
401 
402     /**
403      * @brief Returns the device path
404      *
405      * This can be used for error call outs.
406      * Example: /sys/bus/i2c/devices/3-0068
407      */
408     const std::string getDevicePath() const
409     {
410         return pmbusIntf->path();
411     }
412 
413     /**
414      * @brief Returns this power supply's inventory path.
415      *
416      * This can be used for error call outs.
417      * Example:
418      * /xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply1
419      */
420     const std::string& getInventoryPath() const
421     {
422         return inventoryPath;
423     }
424 
425     /**
426      * @brief Returns the short name (last part of inventoryPath).
427      */
428     const std::string& getShortName() const
429     {
430         return shortName;
431     }
432 
433     /**
434      * @brief Returns the firmware revision version read from the power supply
435      */
436     const std::string& getFWVersion() const
437     {
438         return fwVersion;
439     }
440 
441     /**
442      * @brief Returns the model name of the power supply
443      */
444     const std::string& getModelName() const
445     {
446         return modelName;
447     }
448 
449     /**
450      * @brief Returns true if the number of failed reads exceeds limit
451      * TODO: or CML bit on.
452      */
453     bool hasCommFault() const
454     {
455         return ((readFail >= LOG_LIMIT) || (cmlFault >= DEGLITCH_LIMIT));
456     }
457 
458     /**
459      * @brief Reads the pmbus input voltage and returns that actual voltage
460      *        reading and the calculated input voltage based on thresholds.
461      * @param[out] actualInputVoltage - The actual voltage reading, in Volts.
462      * @param[out] inputVoltage - A rounded up/down value of the actual input
463      *             voltage based on thresholds, in Volts.
464      */
465     void getInputVoltage(double& actualInputVoltage, int& inputVoltage) const;
466 
467     /**
468      * @brief Check if the PS is considered to be available or not
469      *
470      * It is unavailable if any of:
471      * - not present
472      * - input fault active
473      * - Vin UV fault active
474      * - PS KILL fault active
475      * - Iout OC fault active
476      *
477      * Other faults will, through creating error logs with callouts, already
478      * be setting the Functional property to false.
479      *
480      * On changes, the Available property is updated in the inventory.
481      */
482     void checkAvailability();
483 
484     /**
485      * @brief Setup for power supply input history.
486      *
487      * This will setup the variables and interfaces needed to get the power
488      * supply input history data over to D-Bus. The only known support for this
489      * at this time is the INPUT_HISTORY command implemented by the IBM Common
490      * Form Factor Power Suppplies (ibm-cffps). The INPUT_HISTORY command for
491      * ibm-cffps is implemented via a manufacturing specific PMBus command.
492      */
493     void setupInputHistory();
494 
495     /**
496      * @brief Returns true if this power supply has input history (supported).
497      */
498     bool hasInputHistory() const
499     {
500         return inputHistorySupported;
501     }
502 
503     /**
504      * @brief Returns the number of input history records
505      *
506      * PowerSupply wrapper to getNumRecords() from RecordManager.
507      */
508     size_t getNumInputHistoryRecords() const
509     {
510         if (recordManager)
511         {
512             return recordManager->getNumRecords();
513         }
514         else
515         {
516             return 0;
517         }
518     }
519 
520     /**
521      * @brief Returns true when INPUT_HISTORY sync is required.
522      */
523     bool isSyncHistoryRequired() const
524     {
525         return syncHistoryRequired;
526     }
527 
528     /**
529      * @brief Clears the indicator that sync required for INPUT_HISTORY.
530      *
531      * Sets variable to false to indicate that the sync is no longer required.
532      * This can be used after the PSUManager has reacted to the need for the
533      * INPUT_HISTORY data to be synchronized.
534      */
535     void clearSyncHistoryRequired()
536     {
537         syncHistoryRequired = false;
538     }
539 
540     /**
541      * @brief Puts the input voltage rating on D-Bus.
542      *
543      * The rating is like 0, 110, 220.
544      */
545     void setInputVoltageRating();
546 
547   private:
548     /**
549      * @brief systemd bus member
550      */
551     sdbusplus::bus_t& bus;
552 
553     /**
554      * @brief Will be updated to the latest/lastvalue read from STATUS_WORD.
555      */
556     uint64_t statusWord = 0;
557 
558     /**
559      * @brief Will be set to the last read value of STATUS_WORD.
560      */
561     uint64_t statusWordOld = 0;
562 
563     /**
564      * @brief Will be updated to the latest/lastvalue read from STATUS_INPUT.
565      */
566     uint64_t statusInput = 0;
567 
568     /**
569      * @brief Will be updated to the latest/lastvalue read from STATUS_MFR.
570      */
571     uint64_t statusMFR = 0;
572 
573     /**
574      * @brief Will be updated to the latest/last value read from STATUS_CML.
575      */
576     uint64_t statusCML = 0;
577 
578     /**
579      * @brief Will be updated to the latest/last value read from STATUS_VOUT.
580      */
581     uint64_t statusVout = 0;
582 
583     /**
584      * @brief Will be updated to the latest/last value read from STATUS_IOUT.
585      */
586     uint64_t statusIout = 0;
587 
588     /**
589      * @brief Will be updated to the latest/last value read from
590      * STATUS_FANS_1_2.
591      */
592     uint64_t statusFans12 = 0;
593 
594     /**
595      * @brief Will be updated to the latest/last value read from
596      * STATUS_TEMPERATURE.
597      */
598     uint64_t statusTemperature = 0;
599 
600     /**
601      * @brief Will be updated with latest converted value read from READ_VIN
602      */
603     int inputVoltage = phosphor::pmbus::in_input::VIN_VOLTAGE_0;
604 
605     /**
606      * @brief Will be updated with the actual voltage last read from READ_VIN
607      */
608     double actualInputVoltage = 0;
609 
610     /**
611      * @brief True if an error for a fault has already been logged.
612      */
613     bool faultLogged = false;
614 
615     /**
616      * @brief Incremented if bit 1 of STATUS_WORD low byte is on.
617      *
618      * Considered faulted if reaches DEGLITCH_LIMIT.
619      */
620     size_t cmlFault = 0;
621 
622     /**
623      * @brief Incremented if bit 5 of STATUS_WORD high byte is on.
624      *
625      * Considered faulted if reaches DEGLITCH_LIMIT.
626      */
627     size_t inputFault = 0;
628 
629     /**
630      * @brief Incremented if bit 4 of STATUS_WORD high byte is on.
631      *
632      * Considered faulted if reaches DEGLITCH_LIMIT.
633      */
634     size_t mfrFault = 0;
635 
636     /**
637      * @brief Incremented if bit 3 of STATUS_WORD low byte is on.
638      *
639      * Considered faulted if reaches DEGLITCH_LIMIT.
640      */
641     size_t vinUVFault = 0;
642 
643     /**
644      * @brief Incremented if bit 5 of STATUS_WORD low byte is on.
645      *
646      * Considered faulted if reaches DEGLITCH_LIMIT.
647      */
648     size_t voutOVFault = 0;
649 
650     /**
651      * @brief Incremented if bit 4 of STATUS_WORD low byte is on.
652      *
653      * Considered faulted if reaches DEGLITCH_LIMIT.
654      */
655     size_t ioutOCFault = 0;
656 
657     /**
658      * @brief Incremented if bit 7 of STATUS_WORD high byte is on and bit 5
659      * (VOUT_OV) of low byte is off.
660      *
661      * Considered faulted if reaches DEGLITCH_LIMIT.
662      */
663     size_t voutUVFault = 0;
664 
665     /**
666      * @brief Incremented if FANS fault/warn bit on in STATUS_WORD.
667      *
668      * Considered faulted if reaches DEGLITCH_LIMIT.
669      */
670     size_t fanFault = 0;
671 
672     /**
673      * @brief Incremented if bit 2 of STATUS_WORD low byte is on.
674      *
675      * Considered faulted if reaches DEGLITCH_LIMIT.
676      */
677     size_t tempFault = 0;
678 
679     /**
680      * @brief Incremented if bit 11 or 6 of STATUS_WORD is on. PGOOD# is
681      * inactive, or the unit is off.
682      *
683      * Considered faulted if reaches DEGLITCH_LIMIT.
684      */
685     size_t pgoodFault = 0;
686 
687     /**
688      * @brief Power Supply Kill fault.
689      *
690      * Incremented based on bits in STATUS_MFR_SPECIFIC. IBM power supplies use
691      * bit 4 to indicate this fault. Considered faulted if it reaches
692      * DEGLITCH_LIMIT.
693      */
694     size_t psKillFault = 0;
695 
696     /**
697      * @brief Power Supply 12Vcs fault (standby power).
698      *
699      * Incremented based on bits in STATUS_MFR_SPECIFIC. IBM power supplies use
700      * bit 6 to indicate this fault. Considered faulted if it reaches
701      * DEGLITCH_LIMIT.
702      */
703     size_t ps12VcsFault = 0;
704 
705     /**
706      * @brief Power Supply Current-Share fault in 12V domain.
707      *
708      * Incremented based on bits in STATUS_MFR_SPECIFIC. IBM power supplies use
709      * bit 7 to indicate this fault. Considered faulted if it reaches
710      * DEGLITCH_LIMIT.
711      */
712     size_t psCS12VFault = 0;
713 
714     /**
715      * @brief Set to AC_FAULT_LIMIT when AC fault is detected, decremented when
716      * AC fault has cleared. Effectively forms a timer since last AC failure.
717      * Zero indicates being outside the window of concern.
718      */
719     size_t acFault = 0;
720 
721     /**
722      * @brief Count of the number of read failures.
723      */
724     size_t readFail = 0;
725 
726     /**
727      * @brief Examine STATUS_WORD for CML (communication, memory, logic fault).
728      */
729     void analyzeCMLFault();
730 
731     /**
732      * @brief Examine STATUS_WORD for INPUT bit on.
733      *
734      * "An input voltage, input current, or input power fault or warning has
735      * occurred."
736      */
737     void analyzeInputFault();
738 
739     /**
740      * @brief Examine STATUS_WORD for VOUT being set.
741      *
742      * If VOUT is on, "An output voltage fault or warning has occurred.", and
743      * VOUT_OV_FAULT is on, there is an output over-voltage fault.
744      */
745     void analyzeVoutOVFault();
746 
747     /**
748      * @brief Examine STATUS_WORD value read for IOUT_OC_FAULT.
749      *
750      * "An output overcurrent fault has occurred." If it is on, and fault not
751      * set, trace STATUS_WORD, STATUS_MFR_SPECIFIC, and STATUS_IOUT values.
752      */
753     void analyzeIoutOCFault();
754 
755     /**
756      * @brief Examines STATUS_WORD value read to see if there is a UV fault.
757      *
758      * Checks if the VOUT bit is on, indicating "An output voltage fault or
759      * warning has occurred", if it is on, but VOUT_OV_FAULT is off, it is
760      * determined to be an indication of an output under-voltage fault.
761      */
762     void analyzeVoutUVFault();
763 
764     /**
765      * @brief Examine STATUS_WORD for the fan fault/warning bit.
766      *
767      * If fanFault is not on, trace that the bit now came on, include
768      * STATUS_WORD, STATUS_MFR_SPECIFIC, and STATUS_FANS_1_2 values as well, to
769      * help with understanding what may have caused it to be set.
770      */
771     void analyzeFanFault();
772 
773     /**
774      * @brief Examine STATUS_WORD for temperature fault.
775      */
776     void analyzeTemperatureFault();
777 
778     /**
779      * @brief Examine STATUS_WORD for pgood or unit off faults.
780      */
781     void analyzePgoodFault();
782 
783     /**
784      * @brief Determine possible manufacturer-specific faults from bits in
785      * STATUS_MFR.
786      *
787      * The bits in the STATUS_MFR_SPECIFIC command response have "Manufacturer
788      * Defined" meanings. Determine which faults, if any, are present based on
789      * the power supply (device driver) type.
790      */
791     void determineMFRFault();
792 
793     /**
794      * @brief Examine STATUS_WORD value read for MFRSPECIFIC bit on.
795      *
796      * "A manufacturer specific fault or warning has occurred."
797      *
798      * If it is on, call the determineMFRFault() helper function to examine the
799      * value read from STATUS_MFR_SPECIFIC.
800      */
801     void analyzeMFRFault();
802 
803     /**
804      * @brief Analyzes the STATUS_WORD for a VIN_UV_FAULT indicator.
805      */
806     void analyzeVinUVFault();
807 
808     /**
809      * @brief D-Bus path to use for this power supply's inventory status.
810      **/
811     std::string inventoryPath;
812 
813     /**
814      * @brief Store the short name to avoid string processing.
815      *
816      * The short name will be something like powersupply1, the last part of the
817      * inventoryPath.
818      */
819     std::string shortName;
820 
821     /**
822      * @brief Given a full inventory path, returns the last node of the path as
823      * the "short name"
824      */
825     std::string findShortName(const std::string& invPath)
826     {
827         const auto lastSlashPos = invPath.find_last_of('/');
828 
829         if ((lastSlashPos == std::string::npos) ||
830             ((lastSlashPos + 1) == invPath.size()))
831         {
832             return invPath;
833         }
834         else
835         {
836             return invPath.substr(lastSlashPos + 1);
837         }
838     }
839 
840     /**
841      * @brief The libgpiod object for monitoring PSU presence
842      */
843     std::unique_ptr<GPIOInterfaceBase> presenceGPIO = nullptr;
844 
845     /**
846      * @brief True if the power supply is present.
847      */
848     bool present = false;
849 
850     /**
851      * @brief Power supply model name.
852      */
853     std::string modelName;
854 
855     /**
856      * @brief D-Bus match variable used to subscribe to Present property
857      * changes.
858      **/
859     std::unique_ptr<sdbusplus::bus::match_t> presentMatch;
860 
861     /**
862      * @brief D-Bus match variable used to subscribe for Present property
863      * interface added.
864      */
865     std::unique_ptr<sdbusplus::bus::match_t> presentAddedMatch;
866 
867     /**
868      * @brief Pointer to the PMBus interface
869      *
870      * Used to read or write to/from PMBus power supply devices.
871      */
872     std::unique_ptr<phosphor::pmbus::PMBusBase> pmbusIntf = nullptr;
873 
874     /**
875      * @brief Stored copy of the firmware version/revision string
876      */
877     std::string fwVersion;
878 
879     /**
880      * @brief The file system path used for binding the device driver.
881      */
882     const std::filesystem::path bindPath;
883 
884     /**
885      * @brief The string to pass in for binding the device driver.
886      */
887     std::string bindDevice;
888 
889     /**
890      * @brief The result of the most recent availability check
891      *
892      * Saved on the object so changes can be detected.
893      */
894     bool available = false;
895 
896     /**
897      * @brief Binds or unbinds the power supply device driver
898      *
899      * Called when a presence change is detected to either bind the device
900      * driver for the power supply when it is installed, or unbind the device
901      * driver when the power supply is removed.
902      *
903      * Writes <device> to <path>/bind (or unbind)
904      *
905      * @param present - when true, will bind the device driver
906      *                  when false, will unbind the device driver
907      */
908     void bindOrUnbindDriver(bool present);
909 
910     /**
911      *  @brief Updates the presence status by querying D-Bus
912      *
913      * The D-Bus inventory properties for this power supply will be read to
914      * determine if the power supply is present or not and update this
915      * object's present member variable to reflect current status.
916      **/
917     void updatePresence();
918 
919     /**
920      * @brief Updates the power supply presence by reading the GPIO line.
921      */
922     void updatePresenceGPIO();
923 
924     /**
925      * @brief Callback for inventory property changes
926      *
927      * Process change of Present property for power supply.
928      *
929      * This is used if we are watching the D-Bus properties instead of reading
930      * the GPIO presence line ourselves.
931      *
932      * @param[in]  msg - Data associated with Present change signal
933      **/
934     void inventoryChanged(sdbusplus::message_t& msg);
935 
936     /**
937      * @brief Callback for inventory property added.
938      *
939      * Process add of the interface with the Present property for power supply.
940      *
941      * This is used if we are watching the D-Bus properties instead of reading
942      * the GPIO presence line ourselves.
943      *
944      * @param[in]  msg - Data associated with Present add signal
945      **/
946     void inventoryAdded(sdbusplus::message_t& msg);
947 
948     /**
949      * @brief Reads the pmbus MFR_POUT_MAX value.
950      *
951      * "The MFR_POUT_MAX command sets or retrieves the maximum rated output
952      * power, in watts, that the unit is rated to supply."
953      *
954      * @return max_power_out value converted from string.
955      */
956     auto getMaxPowerOut() const;
957 
958     /**
959      * @brief Reads a VPD value from PMBus, correct size, and contents.
960      *
961      * If the VPD data read is not the passed in size, resize and fill with
962      * spaces. If the data contains a non-alphanumeric value, replace any of
963      * those values with spaces.
964      *
965      * @param[in] vpdName - The name of the sysfs "file" to read data from.
966      * @param[in] type - The HWMON file type to read from.
967      * @param[in] vpdSize - The expacted size of the data for this VPD/property
968      *
969      * @return A string containing the VPD data read, resized if necessary
970      */
971     auto readVPDValue(const std::string& vpdName,
972                       const phosphor::pmbus::Type& type,
973                       const std::size_t& vpdSize);
974 
975     /**
976      * @brief Reads the most recent input history record from the power supply
977      * and updates the average and maximum properties in D-Bus if there is a new
978      * reading available.
979      *
980      * This will still run every time analyze() is called so code can post new
981      * data as soon as possible and the timestamp will more accurately reflect
982      * the correct time.
983      *
984      * D-Bus is only updated if there is a change and the oldest record will be
985      * pruned if the property already contains the max number of records.
986      */
987     void updateHistory();
988 
989     /**
990      * @brief Get the power on status of the psu manager class.
991      *
992      * This is a callback method used to get the power on status of the psu
993      * manager class.
994      */
995     std::function<bool()> isPowerOn;
996 
997     /**
998      * @brief Set to true if INPUT_HISTORY command supported.
999      *
1000      * Not all power supplies will support the INPUT_HISTORY command. The IBM
1001      * Common Form Factor power supplies do support this command.
1002      */
1003     bool inputHistorySupported{false};
1004 
1005     /**
1006      * @brief Set to true when INPUT_HISTORY sync is required.
1007      *
1008      * A power supply will need to synchronize its INPUT_HISTORY data with the
1009      * other power supplies installed in the system when it goes from missing to
1010      * present.
1011      */
1012     bool syncHistoryRequired{false};
1013 
1014     /**
1015      * @brief Class that manages the input power history records.
1016      **/
1017     std::unique_ptr<history::RecordManager> recordManager;
1018 
1019     /**
1020      * @brief The D-Bus object for the average input power history
1021      **/
1022     std::unique_ptr<history::Average> average;
1023 
1024     /**
1025      * @brief The D-Bus object for the maximum input power history
1026      **/
1027     std::unique_ptr<history::Maximum> maximum;
1028 
1029     /**
1030      * @brief The base D-Bus object path to use for the average and maximum
1031      * objects.
1032      **/
1033     std::string historyObjectPath;
1034 
1035     /**
1036      * @brief The D-Bus object for the input voltage rating
1037      *
1038      * It is updated at startup and power on.  If a power supply is
1039      * added or removed after that, it does not need to be updated
1040      * again (though that could be done as a future improvement).
1041      */
1042     std::unique_ptr<SensorObject> inputVoltageRatingIface;
1043 
1044     /**
1045      * @brief The device driver name
1046      */
1047     std::string driverName;
1048 };
1049 
1050 } // namespace phosphor::power::psu
1051