xref: /openbmc/openpower-occ-control/powercap.hpp (revision 03a8fe364d403ec0fb743e190d2f7222de1f4de8)
1 #pragma once
2 
3 #include "config.h"
4 
5 #include "utils.hpp"
6 
7 #include <sdbusplus/bus.hpp>
8 #include <sdbusplus/bus/match.hpp>
9 #include <xyz/openbmc_project/Control/Power/CapLimits/server.hpp>
10 
11 #include <filesystem>
12 #include <regex>
13 
14 namespace open_power
15 {
16 namespace occ
17 {
18 class Status;
19 
20 namespace powercap
21 {
22 
23 namespace sdbusRule = sdbusplus::bus::match::rules;
24 namespace fs = std::filesystem;
25 
26 constexpr auto PCAPLIMITS_PATH =
27     "/xyz/openbmc_project/control/host0/power_cap_limits";
28 
29 namespace Base = sdbusplus::xyz::openbmc_project::Control::Power::server;
30 using CapLimitsInterface = sdbusplus::server::object_t<Base::CapLimits>;
31 
32 constexpr auto PCAPDATA_FILE_VERSION = 1;
33 struct PowerCapData
34 {
35     uint32_t version = PCAPDATA_FILE_VERSION;
36     bool initialized = false;
37     uint32_t softMin = 0x0000;
38     uint32_t hardMin = 0x0000;
39     uint32_t max = UINT_MAX;
40 };
41 
42 /** @class OccPersistCapData
43  *  @brief Provides persistent container to store data for OCC
44  *
45  * Data is stored in filesystem
46  */
47 class OccPersistCapData
48 {
49   public:
50     ~OccPersistCapData() = default;
51     OccPersistCapData(const OccPersistCapData&) = default;
52     OccPersistCapData& operator=(const OccPersistCapData&) = default;
53     OccPersistCapData(OccPersistCapData&&) = default;
54     OccPersistCapData& operator=(OccPersistCapData&&) = default;
55 
56     /** @brief Loads any saved power cap data */
OccPersistCapData()57     OccPersistCapData()
58     {
59         load();
60     }
61 
62     /** @brief Save Power Mode data to persistent file
63      *
64      *  @param[in] softMin - soft minimum power cap in Watts
65      *  @param[in] hardMin - hard minimum power cap in Watts
66      *  @param[in] max     - maximum power cap in Watts
67      */
updateCapLimits(const uint32_t softMin,const uint32_t hardMin,const uint32_t max)68     void updateCapLimits(const uint32_t softMin, const uint32_t hardMin,
69                          const uint32_t max)
70     {
71         capData.softMin = softMin;
72         capData.hardMin = hardMin;
73         capData.max = max;
74         capData.initialized = true;
75         save();
76     }
77 
78     /** @brief Return the power cap limits
79      *
80      *  @param[out] softMin - soft minimum power cap in Watts
81      *  @param[out] hardMin - hard minimum power cap in Watts
82      *  @param[out] max     - maximum power cap in Watts
83      */
getCapLimits(uint32_t & softMin,uint32_t & hardMin,uint32_t & max) const84     void getCapLimits(uint32_t& softMin, uint32_t& hardMin, uint32_t& max) const
85     {
86         // If not initialized yet, still return PowerCapData defaults
87         softMin = capData.softMin;
88         hardMin = capData.hardMin;
89         max = capData.max;
90     }
91 
92     /** @brief Return true if the power cap limits are available */
limitsAvailable()93     bool limitsAvailable()
94     {
95         return (capData.initialized);
96     }
97 
98     /** @brief Saves the Power Mode data in the filesystem. */
99     void save();
100 
101     /** @brief Trace the Power Mode and IPS parameters. */
102     void print();
103 
104   private:
105     /** @brief Power Mode data filename to store persistent data */
106     static constexpr auto powerCapFilename = "powerCapLimitData";
107 
108     /** @brief Power Mode data object to be persisted */
109     PowerCapData capData;
110 
111     /** @brief Loads the persisted power cap data from the filesystem. */
112     void load();
113 };
114 
115 /** @class PowerCap
116  *  @brief Monitors for changes to the power cap and notifies occ
117  *
118  *  The customer power cap is provided to the OCC by host TMGT when the occ
119  *  first goes active or is reset.  This code is responsible for sending
120  *  the power cap to the OCC if the cap is changed while the occ is active.
121  */
122 
123 class PowerCap : public CapLimitsInterface
124 {
125   public:
126     /** @brief PowerCap object to inform occ of changes to cap
127      *
128      * This object will monitor for changes to the power cap setting and
129      * power cap enable properties.  If a change is detected, and the occ
130      * is active, then this object will notify the OCC of the change.
131      *
132      * @param[in] occStatus - The occ status object
133      */
PowerCap(Status & occStatus)134     explicit PowerCap(Status& occStatus) :
135         CapLimitsInterface(utils::getBus(), PCAPLIMITS_PATH,
136                            CapLimitsInterface::action::defer_emit),
137         occStatus(occStatus),
138         pcapMatch(
139             utils::getBus(),
140             sdbusRule::member("PropertiesChanged") +
141                 sdbusRule::path(
142                     "/xyz/openbmc_project/control/host0/power_cap") +
143                 sdbusRule::argN(0, "xyz.openbmc_project.Control.Power.Cap") +
144                 sdbusRule::interface("org.freedesktop.DBus.Properties"),
145             std::bind(std::mem_fn(&PowerCap::pcapChanged), this,
146                       std::placeholders::_1))
147     {
148         //  Read the current limits from persistent data
149         uint32_t capSoftMin, capHardMin, capMax;
150         persistedData.getCapLimits(capSoftMin, capHardMin, capMax);
151         // Update limits on dbus
152         updateDbusPcapLimits(capSoftMin, capHardMin, capMax);
153         // CapLimit interface is now ready
154         this->emit_object_added();
155     };
156 
157     /** @brief Return the appropriate value to write to the OCC (output/DC
158      * power)
159      *
160      * @param[in]  pcap        - Current user power cap setting (input/AC power)
161      * @param[in]  pcapEnabled - Current power cap enable setting
162      *
163      * @return The value to write to the occ user pcap
164      */
165     uint32_t getOccInput(uint32_t pcap, bool pcapEnabled);
166 
167     /** @brief Read the power cap bounds from sysfs and update DBus */
168     void updatePcapBounds();
169 
170   private:
171     /** @brief Persisted power cap limits */
172     OccPersistCapData persistedData;
173 
174     /** @brief Callback for pcap setting changes
175      *
176      * Process change and inform OCC
177      *
178      * @param[in]  msg       - Data associated with pcap change signal
179      *
180      */
181     void pcapChanged(sdbusplus::message_t& msg);
182 
183     /** @brief Get the power cap property
184      *
185      * @return Power cap, 0 on failure to indicate no pcap
186      */
187     uint32_t getPcap();
188 
189     /** @brief Get the power cap enable property
190      *
191      * @return Whether power cap enabled, will return false on error
192      */
193     bool getPcapEnabled();
194 
195     /** @brief Write the output/DC power cap to the occ hwmon entry
196      *
197      * @param[in]  pcapValue - Power cap value to write to OCC
198      */
199     void writeOcc(uint32_t pcapValue);
200 
201     /** @brief Read the user power cap from sysfs
202      *
203      * @return User power cap value in Watts or 0 if disabled
204      */
205     uint32_t readUserCapHwmon();
206 
207     /**
208      * @brief Returns the filename to use for the user power cap
209      *
210      * The file is of the form "powerX_cap_user", where X is any
211      * number.
212      *
213      * @param[in] expr - Regular expression of file to find
214      *
215      * @return full path/filename, or empty path if not found.
216      */
217     fs::path getPcapFilename(const std::regex& expr);
218 
219     /* @brief OCC Status object */
220     Status& occStatus;
221 
222     /** @brief Used to subscribe to dbus pcap property changes **/
223     sdbusplus::bus::match_t pcapMatch;
224 
225     /** @brief Path to the sysfs files holding the cap properties **/
226     fs::path pcapBasePathname;
227 
228     /** @brief Update the power cap bounds on DBus
229      *
230      * @param[in]  softMin - soft minimum power cap in Watts
231      * @param[in]  hardMin - hard minimum power cap in Watts
232      * @param[in]  pcapMax - maximum power cap in Watts
233      */
234     void updateDbusPcapLimits(uint32_t softMin, uint32_t hardMin,
235                               uint32_t pcapMax);
236 };
237 
238 } // namespace powercap
239 
240 } // namespace occ
241 
242 } // namespace open_power
243