blob: 26c1ee7163a15966347dd35ad64ad19688492370 [file] [log] [blame]
Andrew Geissler32016d12017-06-20 15:46:52 -05001#include <phosphor-logging/log.hpp>
Gunnar Mills94df8c92018-09-14 14:50:03 -05002#include <powercap.hpp>
George Liub5ca1012021-09-10 12:53:11 +08003
4#include <cassert>
Matt Spinlereaaf3b22019-07-16 10:29:27 -05005#include <regex>
Andrew Geissler32016d12017-06-20 15:46:52 -05006
7namespace open_power
8{
9namespace occ
10{
11namespace powercap
12{
13
Gunnar Mills94df8c92018-09-14 14:50:03 -050014constexpr auto PCAP_PATH = "/xyz/openbmc_project/control/host0/power_cap";
Andrew Geissler52cf26a2017-07-06 12:56:32 -050015constexpr auto PCAP_INTERFACE = "xyz.openbmc_project.Control.Power.Cap";
16
17constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
18constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
19constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
20
21constexpr auto POWER_CAP_PROP = "PowerCap";
22constexpr auto POWER_CAP_ENABLE_PROP = "PowerCapEnable";
23
Andrew Geissler32016d12017-06-20 15:46:52 -050024using namespace phosphor::logging;
George Liubcef3b42021-09-10 12:39:02 +080025namespace fs = std::filesystem;
Andrew Geissler32016d12017-06-20 15:46:52 -050026
Andrew Geissler4cea4d22017-07-10 15:13:33 -050027uint32_t PowerCap::getOccInput(uint32_t pcap, bool pcapEnabled)
28{
29 if (!pcapEnabled)
30 {
31 // Pcap disabled, return 0 to indicate disabled
32 return 0;
33 }
34
35 // If pcap is not disabled then just return the pcap with the derating
36 // factor applied.
Gunnar Mills94df8c92018-09-14 14:50:03 -050037 return ((static_cast<uint64_t>(pcap) * PS_DERATING_FACTOR) / 100);
Andrew Geissler4cea4d22017-07-10 15:13:33 -050038}
39
Andrew Geissler52cf26a2017-07-06 12:56:32 -050040uint32_t PowerCap::getPcap()
41{
George Liuf3b75142021-06-10 11:22:50 +080042 utils::PropertyValue pcap{};
43 try
Andrew Geissler52cf26a2017-07-06 12:56:32 -050044 {
George Liuf3b75142021-06-10 11:22:50 +080045 pcap = utils::getProperty(PCAP_PATH, PCAP_INTERFACE, POWER_CAP_PROP);
46
47 return std::get<uint32_t>(pcap);
48 }
Patrick Williams25613622021-09-02 09:29:54 -050049 catch (const sdbusplus::exception::exception& e)
George Liuf3b75142021-06-10 11:22:50 +080050 {
51 log<level::ERR>("Failed to get PowerCap property",
52 entry("ERROR=%s", e.what()),
53 entry("PATH=%s", PCAP_PATH));
54
Andrew Geissler52cf26a2017-07-06 12:56:32 -050055 return 0;
56 }
Andrew Geissler52cf26a2017-07-06 12:56:32 -050057}
58
59bool PowerCap::getPcapEnabled()
60{
George Liuf3b75142021-06-10 11:22:50 +080061 utils::PropertyValue pcapEnabled{};
62 try
Andrew Geissler52cf26a2017-07-06 12:56:32 -050063 {
George Liuf3b75142021-06-10 11:22:50 +080064 pcapEnabled = utils::getProperty(PCAP_PATH, PCAP_INTERFACE,
65 POWER_CAP_ENABLE_PROP);
Andrew Geissler52cf26a2017-07-06 12:56:32 -050066
George Liuf3b75142021-06-10 11:22:50 +080067 return std::get<bool>(pcapEnabled);
68 }
Patrick Williams25613622021-09-02 09:29:54 -050069 catch (const sdbusplus::exception::exception& e)
George Liuf3b75142021-06-10 11:22:50 +080070 {
71 log<level::ERR>("Failed to get PowerCapEnable property",
72 entry("ERROR=%s", e.what()),
73 entry("PATH=%s", PCAP_PATH));
74
75 return false;
76 }
Andrew Geissler52cf26a2017-07-06 12:56:32 -050077}
Andrew Geissler32016d12017-06-20 15:46:52 -050078
Matt Spinlereaaf3b22019-07-16 10:29:27 -050079std::string PowerCap::getPcapFilename(const fs::path& path)
80{
81 std::regex expr{"power\\d+_cap_user$"};
82 for (auto& file : fs::directory_iterator(path))
83 {
84 if (std::regex_search(file.path().string(), expr))
85 {
86 return file.path().filename();
87 }
88 }
89 return std::string{};
90}
91
Andrew Geissler6ac874e2017-07-10 15:54:58 -050092void PowerCap::writeOcc(uint32_t pcapValue)
93{
94 // Create path out to master occ hwmon entry
95 std::unique_ptr<fs::path> fileName =
Gunnar Mills94df8c92018-09-14 14:50:03 -050096 std::make_unique<fs::path>(OCC_HWMON_PATH);
Lei YU41470e52017-11-30 16:03:50 +080097 *fileName /= occMasterName;
Andrew Geissler6ac874e2017-07-10 15:54:58 -050098 *fileName /= "/hwmon/";
99
100 // Need to get the hwmonXX directory name, there better only be 1 dir
101 assert(std::distance(fs::directory_iterator(*fileName),
102 fs::directory_iterator{}) == 1);
103 // Now set our path to this full path, including this hwmonXX directory
104 fileName = std::make_unique<fs::path>(*fs::directory_iterator(*fileName));
105 // Append on the hwmon string where we write the user power cap
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500106
Matt Spinlereaaf3b22019-07-16 10:29:27 -0500107 auto baseName = getPcapFilename(*fileName);
108 if (baseName.empty())
109 {
110 log<level::ERR>("Could not find a power cap file to write to",
111 entry("PATH=%s", *fileName->c_str()));
112 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
Gunnar Mills94df8c92018-09-14 14:50:03 -0500167 log<level::INFO>("Power Cap Property Change", entry("PCAP=%u", pcap),
168 entry("PCAP_ENABLED=%u", pcapEnabled));
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500169
170 // Determine desired action to write to occ
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500171
Andrew Geissler4cea4d22017-07-10 15:13:33 -0500172 auto occInput = getOccInput(pcap, pcapEnabled);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500173
174 // Write action to occ
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500175 writeOcc(occInput);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500176
177 return;
Andrew Geissler32016d12017-06-20 15:46:52 -0500178}
179
Gunnar Mills94df8c92018-09-14 14:50:03 -0500180} // namespace powercap
Andrew Geissler32016d12017-06-20 15:46:52 -0500181
182} // namespace occ
183
Gunnar Mills94df8c92018-09-14 14:50:03 -0500184} // namespace open_power