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