blob: 2555d95aed94d9a14be02657683af9a55703fc66 [file] [log] [blame]
Chris Cainb6535e82022-01-21 08:24:13 -06001#include <fmt/core.h>
2
Andrew Geissler32016d12017-06-20 15:46:52 -05003#include <phosphor-logging/log.hpp>
Gunnar Mills94df8c92018-09-14 14:50:03 -05004#include <powercap.hpp>
George Liub5ca1012021-09-10 12:53:11 +08005
6#include <cassert>
Matt Spinlereaaf3b22019-07-16 10:29:27 -05007#include <regex>
Andrew Geissler32016d12017-06-20 15:46:52 -05008
9namespace open_power
10{
11namespace occ
12{
13namespace powercap
14{
15
Gunnar Mills94df8c92018-09-14 14:50:03 -050016constexpr auto PCAP_PATH = "/xyz/openbmc_project/control/host0/power_cap";
Andrew Geissler52cf26a2017-07-06 12:56:32 -050017constexpr auto PCAP_INTERFACE = "xyz.openbmc_project.Control.Power.Cap";
18
Andrew Geissler52cf26a2017-07-06 12:56:32 -050019constexpr auto POWER_CAP_PROP = "PowerCap";
20constexpr auto POWER_CAP_ENABLE_PROP = "PowerCapEnable";
21
Andrew Geissler32016d12017-06-20 15:46:52 -050022using namespace phosphor::logging;
George Liubcef3b42021-09-10 12:39:02 +080023namespace fs = std::filesystem;
Andrew Geissler32016d12017-06-20 15:46:52 -050024
Andrew Geissler4cea4d22017-07-10 15:13:33 -050025uint32_t PowerCap::getOccInput(uint32_t pcap, bool pcapEnabled)
26{
27 if (!pcapEnabled)
28 {
29 // Pcap disabled, return 0 to indicate disabled
30 return 0;
31 }
32
33 // If pcap is not disabled then just return the pcap with the derating
34 // factor applied.
Gunnar Mills94df8c92018-09-14 14:50:03 -050035 return ((static_cast<uint64_t>(pcap) * PS_DERATING_FACTOR) / 100);
Andrew Geissler4cea4d22017-07-10 15:13:33 -050036}
37
Andrew Geissler52cf26a2017-07-06 12:56:32 -050038uint32_t PowerCap::getPcap()
39{
George Liuf3b75142021-06-10 11:22:50 +080040 utils::PropertyValue pcap{};
41 try
Andrew Geissler52cf26a2017-07-06 12:56:32 -050042 {
George Liuf3b75142021-06-10 11:22:50 +080043 pcap = utils::getProperty(PCAP_PATH, PCAP_INTERFACE, POWER_CAP_PROP);
44
45 return std::get<uint32_t>(pcap);
46 }
Patrick Williams25613622021-09-02 09:29:54 -050047 catch (const sdbusplus::exception::exception& e)
George Liuf3b75142021-06-10 11:22:50 +080048 {
49 log<level::ERR>("Failed to get PowerCap property",
50 entry("ERROR=%s", e.what()),
51 entry("PATH=%s", PCAP_PATH));
52
Andrew Geissler52cf26a2017-07-06 12:56:32 -050053 return 0;
54 }
Andrew Geissler52cf26a2017-07-06 12:56:32 -050055}
56
57bool PowerCap::getPcapEnabled()
58{
George Liuf3b75142021-06-10 11:22:50 +080059 utils::PropertyValue pcapEnabled{};
60 try
Andrew Geissler52cf26a2017-07-06 12:56:32 -050061 {
George Liuf3b75142021-06-10 11:22:50 +080062 pcapEnabled = utils::getProperty(PCAP_PATH, PCAP_INTERFACE,
63 POWER_CAP_ENABLE_PROP);
Andrew Geissler52cf26a2017-07-06 12:56:32 -050064
George Liuf3b75142021-06-10 11:22:50 +080065 return std::get<bool>(pcapEnabled);
66 }
Patrick Williams25613622021-09-02 09:29:54 -050067 catch (const sdbusplus::exception::exception& e)
George Liuf3b75142021-06-10 11:22:50 +080068 {
69 log<level::ERR>("Failed to get PowerCapEnable property",
70 entry("ERROR=%s", e.what()),
71 entry("PATH=%s", PCAP_PATH));
72
73 return false;
74 }
Andrew Geissler52cf26a2017-07-06 12:56:32 -050075}
Andrew Geissler32016d12017-06-20 15:46:52 -050076
Matt Spinlereaaf3b22019-07-16 10:29:27 -050077std::string PowerCap::getPcapFilename(const fs::path& path)
78{
79 std::regex expr{"power\\d+_cap_user$"};
80 for (auto& file : fs::directory_iterator(path))
81 {
82 if (std::regex_search(file.path().string(), expr))
83 {
84 return file.path().filename();
85 }
86 }
87 return std::string{};
88}
89
Andrew Geissler6ac874e2017-07-10 15:54:58 -050090void PowerCap::writeOcc(uint32_t pcapValue)
91{
92 // Create path out to master occ hwmon entry
93 std::unique_ptr<fs::path> fileName =
Gunnar Mills94df8c92018-09-14 14:50:03 -050094 std::make_unique<fs::path>(OCC_HWMON_PATH);
Lei YU41470e52017-11-30 16:03:50 +080095 *fileName /= occMasterName;
Chris Cainb6535e82022-01-21 08:24:13 -060096 *fileName /= "hwmon";
Andrew Geissler6ac874e2017-07-10 15:54:58 -050097
98 // Need to get the hwmonXX directory name, there better only be 1 dir
99 assert(std::distance(fs::directory_iterator(*fileName),
100 fs::directory_iterator{}) == 1);
101 // Now set our path to this full path, including this hwmonXX directory
102 fileName = std::make_unique<fs::path>(*fs::directory_iterator(*fileName));
103 // Append on the hwmon string where we write the user power cap
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500104
Matt Spinlereaaf3b22019-07-16 10:29:27 -0500105 auto baseName = getPcapFilename(*fileName);
106 if (baseName.empty())
107 {
Chris Cainb6535e82022-01-21 08:24:13 -0600108 log<level::ERR>(
109 fmt::format("Could not find a power cap file to write to: {})",
110 fileName->c_str())
111 .c_str());
Matt Spinlereaaf3b22019-07-16 10:29:27 -0500112 return;
113 }
114 *fileName /= baseName;
115
116 uint64_t microWatts = pcapValue * 1000000ull;
117
118 auto pcapString{std::to_string(microWatts)};
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500119
120 log<level::INFO>("Writing pcap value to hwmon",
Gunnar Mills94df8c92018-09-14 14:50:03 -0500121 entry("PCAP_PATH=%s", fileName->c_str()),
122 entry("PCAP_VALUE=%s", pcapString.c_str()));
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500123 // Open the hwmon file and write the power cap
124 std::ofstream file(*fileName, std::ios::out);
125 file << pcapString;
126 file.close();
127 return;
128}
129
Andrew Geissler32016d12017-06-20 15:46:52 -0500130void PowerCap::pcapChanged(sdbusplus::message::message& msg)
131{
Andrew Geissler32016d12017-06-20 15:46:52 -0500132 if (!occStatus.occActive())
133 {
134 // Nothing to do
135 return;
136 }
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500137
138 uint32_t pcap = 0;
139 bool pcapEnabled = false;
140
141 std::string msgSensor;
Patrick Williamse0962702020-05-13 17:50:22 -0500142 std::map<std::string, std::variant<uint32_t, bool>> msgData;
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500143 msg.read(msgSensor, msgData);
144
145 // Retrieve which property changed via the msg and read the other one
146 auto valPropMap = msgData.find(POWER_CAP_PROP);
147 if (valPropMap != msgData.end())
148 {
Patrick Williams305ff8b2020-05-13 11:17:39 -0500149 pcap = std::get<uint32_t>(valPropMap->second);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500150 pcapEnabled = getPcapEnabled();
151 }
152 else
153 {
154 valPropMap = msgData.find(POWER_CAP_ENABLE_PROP);
155 if (valPropMap != msgData.end())
156 {
Patrick Williams305ff8b2020-05-13 11:17:39 -0500157 pcapEnabled = std::get<bool>(valPropMap->second);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500158 pcap = getPcap();
159 }
160 else
161 {
162 log<level::INFO>("Unknown power cap property changed");
163 return;
164 }
165 }
166
Chris Cainb6535e82022-01-21 08:24:13 -0600167 log<level::INFO>(
168 fmt::format("Power Cap Property Change (cap={}W (input), enabled={})",
169 pcap, pcapEnabled ? 'y' : 'n')
170 .c_str());
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500171
172 // Determine desired action to write to occ
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500173
Andrew Geissler4cea4d22017-07-10 15:13:33 -0500174 auto occInput = getOccInput(pcap, pcapEnabled);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500175
176 // Write action to occ
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500177 writeOcc(occInput);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500178
179 return;
Andrew Geissler32016d12017-06-20 15:46:52 -0500180}
181
Gunnar Mills94df8c92018-09-14 14:50:03 -0500182} // namespace powercap
Andrew Geissler32016d12017-06-20 15:46:52 -0500183
184} // namespace occ
185
Gunnar Mills94df8c92018-09-14 14:50:03 -0500186} // namespace open_power