blob: ffa65ddde49fed23b9eba808dadc17205d579c09 [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
19constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
20constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
21constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
22
23constexpr auto POWER_CAP_PROP = "PowerCap";
24constexpr auto POWER_CAP_ENABLE_PROP = "PowerCapEnable";
25
Andrew Geissler32016d12017-06-20 15:46:52 -050026using namespace phosphor::logging;
George Liubcef3b42021-09-10 12:39:02 +080027namespace fs = std::filesystem;
Andrew Geissler32016d12017-06-20 15:46:52 -050028
Andrew Geissler4cea4d22017-07-10 15:13:33 -050029uint32_t PowerCap::getOccInput(uint32_t pcap, bool pcapEnabled)
30{
31 if (!pcapEnabled)
32 {
33 // Pcap disabled, return 0 to indicate disabled
34 return 0;
35 }
36
37 // If pcap is not disabled then just return the pcap with the derating
38 // factor applied.
Gunnar Mills94df8c92018-09-14 14:50:03 -050039 return ((static_cast<uint64_t>(pcap) * PS_DERATING_FACTOR) / 100);
Andrew Geissler4cea4d22017-07-10 15:13:33 -050040}
41
Andrew Geissler52cf26a2017-07-06 12:56:32 -050042uint32_t PowerCap::getPcap()
43{
George Liuf3b75142021-06-10 11:22:50 +080044 utils::PropertyValue pcap{};
45 try
Andrew Geissler52cf26a2017-07-06 12:56:32 -050046 {
George Liuf3b75142021-06-10 11:22:50 +080047 pcap = utils::getProperty(PCAP_PATH, PCAP_INTERFACE, POWER_CAP_PROP);
48
49 return std::get<uint32_t>(pcap);
50 }
Patrick Williams25613622021-09-02 09:29:54 -050051 catch (const sdbusplus::exception::exception& e)
George Liuf3b75142021-06-10 11:22:50 +080052 {
53 log<level::ERR>("Failed to get PowerCap property",
54 entry("ERROR=%s", e.what()),
55 entry("PATH=%s", PCAP_PATH));
56
Andrew Geissler52cf26a2017-07-06 12:56:32 -050057 return 0;
58 }
Andrew Geissler52cf26a2017-07-06 12:56:32 -050059}
60
61bool PowerCap::getPcapEnabled()
62{
George Liuf3b75142021-06-10 11:22:50 +080063 utils::PropertyValue pcapEnabled{};
64 try
Andrew Geissler52cf26a2017-07-06 12:56:32 -050065 {
George Liuf3b75142021-06-10 11:22:50 +080066 pcapEnabled = utils::getProperty(PCAP_PATH, PCAP_INTERFACE,
67 POWER_CAP_ENABLE_PROP);
Andrew Geissler52cf26a2017-07-06 12:56:32 -050068
George Liuf3b75142021-06-10 11:22:50 +080069 return std::get<bool>(pcapEnabled);
70 }
Patrick Williams25613622021-09-02 09:29:54 -050071 catch (const sdbusplus::exception::exception& e)
George Liuf3b75142021-06-10 11:22:50 +080072 {
73 log<level::ERR>("Failed to get PowerCapEnable property",
74 entry("ERROR=%s", e.what()),
75 entry("PATH=%s", PCAP_PATH));
76
77 return false;
78 }
Andrew Geissler52cf26a2017-07-06 12:56:32 -050079}
Andrew Geissler32016d12017-06-20 15:46:52 -050080
Matt Spinlereaaf3b22019-07-16 10:29:27 -050081std::string PowerCap::getPcapFilename(const fs::path& path)
82{
83 std::regex expr{"power\\d+_cap_user$"};
84 for (auto& file : fs::directory_iterator(path))
85 {
86 if (std::regex_search(file.path().string(), expr))
87 {
88 return file.path().filename();
89 }
90 }
91 return std::string{};
92}
93
Andrew Geissler6ac874e2017-07-10 15:54:58 -050094void PowerCap::writeOcc(uint32_t pcapValue)
95{
96 // Create path out to master occ hwmon entry
97 std::unique_ptr<fs::path> fileName =
Gunnar Mills94df8c92018-09-14 14:50:03 -050098 std::make_unique<fs::path>(OCC_HWMON_PATH);
Lei YU41470e52017-11-30 16:03:50 +080099 *fileName /= occMasterName;
Chris Cainb6535e82022-01-21 08:24:13 -0600100 *fileName /= "hwmon";
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500101
102 // Need to get the hwmonXX directory name, there better only be 1 dir
103 assert(std::distance(fs::directory_iterator(*fileName),
104 fs::directory_iterator{}) == 1);
105 // Now set our path to this full path, including this hwmonXX directory
106 fileName = std::make_unique<fs::path>(*fs::directory_iterator(*fileName));
107 // Append on the hwmon string where we write the user power cap
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500108
Matt Spinlereaaf3b22019-07-16 10:29:27 -0500109 auto baseName = getPcapFilename(*fileName);
110 if (baseName.empty())
111 {
Chris Cainb6535e82022-01-21 08:24:13 -0600112 log<level::ERR>(
113 fmt::format("Could not find a power cap file to write to: {})",
114 fileName->c_str())
115 .c_str());
Matt Spinlereaaf3b22019-07-16 10:29:27 -0500116 return;
117 }
118 *fileName /= baseName;
119
120 uint64_t microWatts = pcapValue * 1000000ull;
121
122 auto pcapString{std::to_string(microWatts)};
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500123
124 log<level::INFO>("Writing pcap value to hwmon",
Gunnar Mills94df8c92018-09-14 14:50:03 -0500125 entry("PCAP_PATH=%s", fileName->c_str()),
126 entry("PCAP_VALUE=%s", pcapString.c_str()));
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500127 // Open the hwmon file and write the power cap
128 std::ofstream file(*fileName, std::ios::out);
129 file << pcapString;
130 file.close();
131 return;
132}
133
Andrew Geissler32016d12017-06-20 15:46:52 -0500134void PowerCap::pcapChanged(sdbusplus::message::message& msg)
135{
Andrew Geissler32016d12017-06-20 15:46:52 -0500136 if (!occStatus.occActive())
137 {
138 // Nothing to do
139 return;
140 }
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500141
142 uint32_t pcap = 0;
143 bool pcapEnabled = false;
144
145 std::string msgSensor;
Patrick Williamse0962702020-05-13 17:50:22 -0500146 std::map<std::string, std::variant<uint32_t, bool>> msgData;
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500147 msg.read(msgSensor, msgData);
148
149 // Retrieve which property changed via the msg and read the other one
150 auto valPropMap = msgData.find(POWER_CAP_PROP);
151 if (valPropMap != msgData.end())
152 {
Patrick Williams305ff8b2020-05-13 11:17:39 -0500153 pcap = std::get<uint32_t>(valPropMap->second);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500154 pcapEnabled = getPcapEnabled();
155 }
156 else
157 {
158 valPropMap = msgData.find(POWER_CAP_ENABLE_PROP);
159 if (valPropMap != msgData.end())
160 {
Patrick Williams305ff8b2020-05-13 11:17:39 -0500161 pcapEnabled = std::get<bool>(valPropMap->second);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500162 pcap = getPcap();
163 }
164 else
165 {
166 log<level::INFO>("Unknown power cap property changed");
167 return;
168 }
169 }
170
Chris Cainb6535e82022-01-21 08:24:13 -0600171 log<level::INFO>(
172 fmt::format("Power Cap Property Change (cap={}W (input), enabled={})",
173 pcap, pcapEnabled ? 'y' : 'n')
174 .c_str());
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500175
176 // Determine desired action to write to occ
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500177
Andrew Geissler4cea4d22017-07-10 15:13:33 -0500178 auto occInput = getOccInput(pcap, pcapEnabled);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500179
180 // Write action to occ
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500181 writeOcc(occInput);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500182
183 return;
Andrew Geissler32016d12017-06-20 15:46:52 -0500184}
185
Gunnar Mills94df8c92018-09-14 14:50:03 -0500186} // namespace powercap
Andrew Geissler32016d12017-06-20 15:46:52 -0500187
188} // namespace occ
189
Gunnar Mills94df8c92018-09-14 14:50:03 -0500190} // namespace open_power