1 /**
2  * Copyright © 2024 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include "services.hpp"
19 
20 #include <cstdint>
21 #include <map>
22 #include <optional>
23 #include <stdexcept>
24 #include <string>
25 #include <vector>
26 
27 namespace phosphor::power::sequencer
28 {
29 
30 // Forward declarations to avoid circular dependencies
31 class PowerSequencerDevice;
32 
33 /**
34  * @struct GPIO
35  *
36  * General Purpose Input/Output (GPIO) that can be read to obtain the pgood
37  * status of a voltage rail.
38  */
39 struct GPIO
40 {
41     /**
42      * The libgpiod line offset of the GPIO.
43      */
44     unsigned int line{0};
45 
46     /**
47      * Specifies whether the GPIO is active low.
48      *
49      * If true, the GPIO value 0 indicates a true pgood status. If false, the
50      * GPIO value 1 indicates a true pgood status.
51      */
52     bool activeLow{false};
53 };
54 
55 /**
56  * @class Rail
57  *
58  * A voltage rail that is enabled or monitored by the power sequencer device.
59  */
60 class Rail
61 {
62   public:
63     // Specify which compiler-generated methods we want
64     Rail() = delete;
65     Rail(const Rail&) = delete;
66     Rail(Rail&&) = delete;
67     Rail& operator=(const Rail&) = delete;
68     Rail& operator=(Rail&&) = delete;
69     ~Rail() = default;
70 
71     /**
72      * Constructor.
73      *
74      * Throws an exception if any of the input parameters are invalid.
75      *
76      * @param name Unique name for the rail
77      * @param presence Optional D-Bus inventory path of a system component which
78      *                 must be present in order for the rail to be present
79      * @param page Optional PMBus PAGE number of the rail.  Required if
80      *             checkStatusVout or compareVoltageToLimit is true.
81      * @param isPowerSupplyRail Specifies whether the rail is produced by a
82      *                          power supply
83      * @param checkStatusVout Specifies whether to check the value of the PMBus
84      *                        STATUS_VOUT command when determining the pgood
85      *                        status of the rail
86      * @param compareVoltageToLimit Specifies whether to compare the output
87      *                              voltage to the undervoltage fault limit when
88      *                              determining the pgood status of the rail
89      * @param gpio Optional GPIO to read to determine the pgood status of the
90      *             rail
91      */
Rail(const std::string & name,const std::optional<std::string> & presence,const std::optional<uint8_t> & page,bool isPowerSupplyRail,bool checkStatusVout,bool compareVoltageToLimit,const std::optional<GPIO> & gpio)92     explicit Rail(const std::string& name,
93                   const std::optional<std::string>& presence,
94                   const std::optional<uint8_t>& page, bool isPowerSupplyRail,
95                   bool checkStatusVout, bool compareVoltageToLimit,
96                   const std::optional<GPIO>& gpio) :
97         name{name}, presence{presence}, page{page},
98         isPsuRail{isPowerSupplyRail}, checkStatusVout{checkStatusVout},
99         compareVoltageToLimit{compareVoltageToLimit}, gpio{gpio}
100     {
101         // If checking STATUS_VOUT or output voltage, verify PAGE was specified
102         if ((checkStatusVout || compareVoltageToLimit) && !page)
103         {
104             throw std::invalid_argument{"PMBus PAGE is required"};
105         }
106     }
107 
108     /**
109      * Returns the unique name for the rail.
110      *
111      * @return rail name
112      */
getName() const113     const std::string& getName() const
114     {
115         return name;
116     }
117 
118     /**
119      * Returns the D-Bus inventory path of a system component which must be
120      * present in order for the rail to be present.
121      *
122      * @return inventory path for presence detection
123      */
getPresence() const124     const std::optional<std::string>& getPresence() const
125     {
126         return presence;
127     }
128 
129     /**
130      * Returns the PMBus PAGE number of the rail.
131      *
132      * @return PAGE number for rail
133      */
getPage() const134     const std::optional<uint8_t>& getPage() const
135     {
136         return page;
137     }
138 
139     /**
140      * Returns whether the rail is produced by a power supply.
141      *
142      * @return true if rail is produced by a power supply, false otherwise
143      */
isPowerSupplyRail() const144     bool isPowerSupplyRail() const
145     {
146         return isPsuRail;
147     }
148 
149     /**
150      * Returns whether the value of the PMBus STATUS_VOUT command is checked
151      * when determining the pgood status of the rail.
152      *
153      * @return true if STATUS_VOUT is checked, false otherwise
154      */
getCheckStatusVout() const155     bool getCheckStatusVout() const
156     {
157         return checkStatusVout;
158     }
159 
160     /**
161      * Returns whether the output voltage should be compared to the undervoltage
162      * fault limit when determining the pgood status of the rail.
163      *
164      * @return true if output voltage is compared to limit, false otherwise
165      */
getCompareVoltageToLimit() const166     bool getCompareVoltageToLimit() const
167     {
168         return compareVoltageToLimit;
169     }
170 
171     /**
172      * Returns the GPIO to read to determine the pgood status of the rail.
173      *
174      * @return GPIO
175      */
getGPIO() const176     const std::optional<GPIO>& getGPIO() const
177     {
178         return gpio;
179     }
180 
181     /**
182      * Returns whether the rail is present.
183      *
184      * Returns true if no inventory path was specified for presence detection.
185      *
186      * @param services System services like hardware presence and the journal
187      * @return true if rail is present, false otherwise
188      */
189     bool isPresent(Services& services);
190 
191     /**
192      * Returns the value of the PMBus STATUS_WORD command for the rail.
193      *
194      * Reads the value from the specified device.  The returned value is in
195      * host-endian order.
196      *
197      * Throws an exception if the value could not be obtained.
198      *
199      * @param device Power sequencer device that enables and monitors the rail
200      * @return STATUS_WORD value
201      */
202     uint16_t getStatusWord(PowerSequencerDevice& device);
203 
204     /**
205      * Returns the value of the PMBus STATUS_VOUT command for the rail.
206      *
207      * Reads the value from the specified device.
208      *
209      * Throws an exception if the value could not be obtained.
210      *
211      * @param device Power sequencer device that enables and monitors the rail
212      * @return STATUS_VOUT value
213      */
214     uint8_t getStatusVout(PowerSequencerDevice& device);
215 
216     /**
217      * Returns the value of the PMBus READ_VOUT command for the rail.
218      *
219      * Reads the value from the specified device.  The returned value is in
220      * volts.
221      *
222      * Throws an exception if the value could not be obtained.
223      *
224      * @param device Power sequencer device that enables and monitors the rail
225      * @return READ_VOUT value in volts
226      */
227     double getReadVout(PowerSequencerDevice& device);
228 
229     /**
230      * Returns the value of the PMBus VOUT_UV_FAULT_LIMIT command for the rail.
231      *
232      * Reads the value from the specified device.  The returned value is in
233      * volts.
234      *
235      * Throws an exception if the value could not be obtained.
236      *
237      * @param device Power sequencer device that enables and monitors the rail
238      * @return VOUT_UV_FAULT_LIMIT value in volts
239      */
240     double getVoutUVFaultLimit(PowerSequencerDevice& device);
241 
242     /**
243      * Returns whether a pgood (power good) fault has occurred on the rail.
244      *
245      * Throws an exception if an error occurs while trying to obtain the rail
246      * status.
247      *
248      * @param device Power sequencer device that enables and monitors the rail
249      * @param services System services like hardware presence and the journal
250      * @param gpioValues GPIO values obtained from the device (if any)
251      * @param additionalData Additional data to include in an error log if this
252      *                       method returns true
253      * @return true if a pgood fault was found on the rail, false otherwise
254      */
255     bool hasPgoodFault(PowerSequencerDevice& device, Services& services,
256                        const std::vector<int>& gpioValues,
257                        std::map<std::string, std::string>& additionalData);
258 
259     /**
260      * Returns whether the PMBus STATUS_VOUT command indicates a pgood fault
261      * has occurred on the rail.
262      *
263      * Throws an exception if an error occurs while trying to obtain the rail
264      * status.
265      *
266      * @param device Power sequencer device that enables and monitors the rail
267      * @param services System services like hardware presence and the journal
268      * @param additionalData Additional data to include in an error log if this
269      *                       method returns true
270      * @return true if a pgood fault was found on the rail, false otherwise
271      */
272     bool hasPgoodFaultStatusVout(
273         PowerSequencerDevice& device, Services& services,
274         std::map<std::string, std::string>& additionalData);
275 
276     /**
277      * Returns whether a GPIO value indicates a pgood fault has occurred on the
278      * rail.
279      *
280      * Throws an exception if an error occurs while trying to obtain the rail
281      * status.
282      *
283      * @param device Power sequencer device that enables and monitors the rail
284      * @param services System services like hardware presence and the journal
285      * @param gpioValues GPIO values obtained from the device (if any)
286      * @param additionalData Additional data to include in an error log if this
287      *                       method returns true
288      * @return true if a pgood fault was found on the rail, false otherwise
289      */
290     bool hasPgoodFaultGPIO(PowerSequencerDevice& device, Services& services,
291                            const std::vector<int>& gpioValues,
292                            std::map<std::string, std::string>& additionalData);
293 
294     /**
295      * Returns whether the output voltage is below the undervoltage limit
296      * indicating a pgood fault has occurred on the rail.
297      *
298      * Throws an exception if an error occurs while trying to obtain the rail
299      * status.
300      *
301      * @param device Power sequencer device that enables and monitors the rail
302      * @param services System services like hardware presence and the journal
303      * @param additionalData Additional data to include in an error log if this
304      *                       method returns true
305      * @return true if a pgood fault was found on the rail, false otherwise
306      */
307     bool hasPgoodFaultOutputVoltage(
308         PowerSequencerDevice& device, Services& services,
309         std::map<std::string, std::string>& additionalData);
310 
311   private:
312     /**
313      * Verifies that a PMBus PAGE number is defined for the rail.
314      *
315      * Throws an exception if a PAGE number is not defined.
316      */
317     void verifyHasPage();
318 
319     /**
320      * Store pgood fault debug data in the specified additional data map.
321      *
322      * Stores data that is relevant regardless of which method was used to
323      * detect the pgood fault.
324      *
325      * @param device Power sequencer device that enables and monitors the rail
326      * @param services System services like hardware presence and the journal
327      * @param additionalData Additional data to include in an error log
328      */
329     void storePgoodFaultDebugData(
330         PowerSequencerDevice& device, Services& services,
331         std::map<std::string, std::string>& additionalData);
332 
333     /**
334      * Unique name for the rail.
335      */
336     std::string name{};
337 
338     /**
339      * D-Bus inventory path of a system component which must be present in order
340      * for the rail to be present.
341      *
342      * If not specified, the rail is assumed to always be present.
343      */
344     std::optional<std::string> presence{};
345 
346     /**
347      * PMBus PAGE number of the rail.
348      */
349     std::optional<uint8_t> page{};
350 
351     /**
352      * Specifies whether the rail is produced by a power supply.
353      */
354     bool isPsuRail{false};
355 
356     /**
357      * Specifies whether to check the value of the PMBus STATUS_VOUT command
358      * when determining the pgood status of the rail.
359      *
360      * If one of the error bits is set in STATUS_VOUT, the rail pgood will be
361      * considered false.
362      */
363     bool checkStatusVout{false};
364 
365     /**
366      * Specifies whether to compare the output voltage to the undervoltage fault
367      * limit when determining the pgood status of the rail.
368      *
369      * If the output voltage is below this limit, the rail pgood will be
370      * considered false.
371      *
372      * Uses the values of the PMBus READ_VOUT and VOUT_UV_FAULT_LIMIT commands.
373      */
374     bool compareVoltageToLimit{false};
375 
376     /**
377      * GPIO to read to determine the pgood status of the rail.
378      */
379     std::optional<GPIO> gpio{};
380 };
381 
382 } // namespace phosphor::power::sequencer
383