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