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      */
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},
98         presence{presence}, page{page}, isPsuRail{isPowerSupplyRail},
99         checkStatusVout{checkStatusVout},
100         compareVoltageToLimit{compareVoltageToLimit}, gpio{gpio}
101     {
102         // If checking STATUS_VOUT or output voltage, verify PAGE was specified
103         if ((checkStatusVout || compareVoltageToLimit) && !page)
104         {
105             throw std::invalid_argument{"PMBus PAGE is required"};
106         }
107     }
108 
109     /**
110      * Returns the unique name for the rail.
111      *
112      * @return rail name
113      */
114     const std::string& getName() const
115     {
116         return name;
117     }
118 
119     /**
120      * Returns the D-Bus inventory path of a system component which must be
121      * present in order for the rail to be present.
122      *
123      * @return inventory path for presence detection
124      */
125     const std::optional<std::string>& getPresence() const
126     {
127         return presence;
128     }
129 
130     /**
131      * Returns the PMBus PAGE number of the rail.
132      *
133      * @return PAGE number for rail
134      */
135     const std::optional<uint8_t>& getPage() const
136     {
137         return page;
138     }
139 
140     /**
141      * Returns whether the rail is produced by a power supply.
142      *
143      * @return true if rail is produced by a power supply, false otherwise
144      */
145     bool isPowerSupplyRail() const
146     {
147         return isPsuRail;
148     }
149 
150     /**
151      * Returns whether the value of the PMBus STATUS_VOUT command is checked
152      * when determining the pgood status of the rail.
153      *
154      * @return true if STATUS_VOUT is checked, false otherwise
155      */
156     bool getCheckStatusVout() const
157     {
158         return checkStatusVout;
159     }
160 
161     /**
162      * Returns whether the output voltage should be compared to the undervoltage
163      * fault limit when determining the pgood status of the rail.
164      *
165      * @return true if output voltage is compared to limit, false otherwise
166      */
167     bool getCompareVoltageToLimit() const
168     {
169         return compareVoltageToLimit;
170     }
171 
172     /**
173      * Returns the GPIO to read to determine the pgood status of the rail.
174      *
175      * @return GPIO
176      */
177     const std::optional<GPIO>& getGPIO() const
178     {
179         return gpio;
180     }
181 
182     /**
183      * Returns whether the rail is present.
184      *
185      * Returns true if no inventory path was specified for presence detection.
186      *
187      * @param services System services like hardware presence and the journal
188      * @return true if rail is present, false otherwise
189      */
190     bool isPresent(Services& services);
191 
192     /**
193      * Returns the value of the PMBus STATUS_WORD command for the rail.
194      *
195      * Reads the value from the specified device.  The returned value is in
196      * host-endian order.
197      *
198      * Throws an exception if the value could not be obtained.
199      *
200      * @param device Power sequencer device that enables and monitors the rail
201      * @return STATUS_WORD value
202      */
203     uint16_t getStatusWord(PowerSequencerDevice& device);
204 
205     /**
206      * Returns the value of the PMBus STATUS_VOUT command for the rail.
207      *
208      * Reads the value from the specified device.
209      *
210      * Throws an exception if the value could not be obtained.
211      *
212      * @param device Power sequencer device that enables and monitors the rail
213      * @return STATUS_VOUT value
214      */
215     uint8_t getStatusVout(PowerSequencerDevice& device);
216 
217     /**
218      * Returns the value of the PMBus READ_VOUT command for the rail.
219      *
220      * Reads the value from the specified device.  The returned value is in
221      * volts.
222      *
223      * Throws an exception if the value could not be obtained.
224      *
225      * @param device Power sequencer device that enables and monitors the rail
226      * @return READ_VOUT value in volts
227      */
228     double getReadVout(PowerSequencerDevice& device);
229 
230     /**
231      * Returns the value of the PMBus VOUT_UV_FAULT_LIMIT command for the rail.
232      *
233      * Reads the value from the specified device.  The returned value is in
234      * volts.
235      *
236      * Throws an exception if the value could not be obtained.
237      *
238      * @param device Power sequencer device that enables and monitors the rail
239      * @return VOUT_UV_FAULT_LIMIT value in volts
240      */
241     double getVoutUVFaultLimit(PowerSequencerDevice& device);
242 
243     /**
244      * Returns whether a pgood (power good) fault has occurred on the rail.
245      *
246      * Throws an exception if an error occurs while trying to obtain the rail
247      * status.
248      *
249      * @param device Power sequencer device that enables and monitors the rail
250      * @param services System services like hardware presence and the journal
251      * @param gpioValues GPIO values obtained from the device (if any)
252      * @param additionalData Additional data to include in an error log if this
253      *                       method returns true
254      * @return true if a pgood fault was found on the rail, false otherwise
255      */
256     bool hasPgoodFault(PowerSequencerDevice& device, Services& services,
257                        const std::vector<int>& gpioValues,
258                        std::map<std::string, std::string>& additionalData);
259 
260     /**
261      * Returns whether the PMBus STATUS_VOUT command indicates a pgood fault
262      * has occurred on the rail.
263      *
264      * Throws an exception if an error occurs while trying to obtain the rail
265      * status.
266      *
267      * @param device Power sequencer device that enables and monitors the rail
268      * @param services System services like hardware presence and the journal
269      * @param additionalData Additional data to include in an error log if this
270      *                       method returns true
271      * @return true if a pgood fault was found on the rail, false otherwise
272      */
273     bool hasPgoodFaultStatusVout(
274         PowerSequencerDevice& device, Services& services,
275         std::map<std::string, std::string>& additionalData);
276 
277     /**
278      * Returns whether a GPIO value indicates a pgood fault has occurred on the
279      * rail.
280      *
281      * Throws an exception if an error occurs while trying to obtain the rail
282      * status.
283      *
284      * @param device Power sequencer device that enables and monitors the rail
285      * @param services System services like hardware presence and the journal
286      * @param gpioValues GPIO values obtained from the device (if any)
287      * @param additionalData Additional data to include in an error log if this
288      *                       method returns true
289      * @return true if a pgood fault was found on the rail, false otherwise
290      */
291     bool hasPgoodFaultGPIO(PowerSequencerDevice& device, Services& services,
292                            const std::vector<int>& gpioValues,
293                            std::map<std::string, std::string>& additionalData);
294 
295     /**
296      * Returns whether the output voltage is below the undervoltage limit
297      * indicating a pgood fault has occurred on the rail.
298      *
299      * Throws an exception if an error occurs while trying to obtain the rail
300      * status.
301      *
302      * @param device Power sequencer device that enables and monitors the rail
303      * @param services System services like hardware presence and the journal
304      * @param additionalData Additional data to include in an error log if this
305      *                       method returns true
306      * @return true if a pgood fault was found on the rail, false otherwise
307      */
308     bool hasPgoodFaultOutputVoltage(
309         PowerSequencerDevice& device, Services& services,
310         std::map<std::string, std::string>& additionalData);
311 
312   private:
313     /**
314      * Verifies that a PMBus PAGE number is defined for the rail.
315      *
316      * Throws an exception if a PAGE number is not defined.
317      */
318     void verifyHasPage();
319 
320     /**
321      * Store pgood fault debug data in the specified additional data map.
322      *
323      * Stores data that is relevant regardless of which method was used to
324      * detect the pgood fault.
325      *
326      * @param device Power sequencer device that enables and monitors the rail
327      * @param services System services like hardware presence and the journal
328      * @param additionalData Additional data to include in an error log
329      */
330     void storePgoodFaultDebugData(
331         PowerSequencerDevice& device, Services& services,
332         std::map<std::string, std::string>& additionalData);
333 
334     /**
335      * Unique name for the rail.
336      */
337     std::string name{};
338 
339     /**
340      * D-Bus inventory path of a system component which must be present in order
341      * for the rail to be present.
342      *
343      * If not specified, the rail is assumed to always be present.
344      */
345     std::optional<std::string> presence{};
346 
347     /**
348      * PMBus PAGE number of the rail.
349      */
350     std::optional<uint8_t> page{};
351 
352     /**
353      * Specifies whether the rail is produced by a power supply.
354      */
355     bool isPsuRail{false};
356 
357     /**
358      * Specifies whether to check the value of the PMBus STATUS_VOUT command
359      * when determining the pgood status of the rail.
360      *
361      * If one of the error bits is set in STATUS_VOUT, the rail pgood will be
362      * considered false.
363      */
364     bool checkStatusVout{false};
365 
366     /**
367      * Specifies whether to compare the output voltage to the undervoltage fault
368      * limit when determining the pgood status of the rail.
369      *
370      * If the output voltage is below this limit, the rail pgood will be
371      * considered false.
372      *
373      * Uses the values of the PMBus READ_VOUT and VOUT_UV_FAULT_LIMIT commands.
374      */
375     bool compareVoltageToLimit{false};
376 
377     /**
378      * GPIO to read to determine the pgood status of the rail.
379      */
380     std::optional<GPIO> gpio{};
381 };
382 
383 } // namespace phosphor::power::sequencer
384