blob: a04584fdad5fad5d1c83ef3193b322e2bb2859ef [file] [log] [blame]
William A. Kennington III29a8ed12018-11-06 15:05:11 -08001#include <cassert>
Andrew Geissler32016d12017-06-20 15:46:52 -05002#include <phosphor-logging/log.hpp>
Gunnar Mills94df8c92018-09-14 14:50:03 -05003#include <powercap.hpp>
Matt Spinlereaaf3b22019-07-16 10:29:27 -05004#include <regex>
Andrew Geissler32016d12017-06-20 15:46:52 -05005
6namespace open_power
7{
8namespace occ
9{
10namespace powercap
11{
12
Gunnar Mills94df8c92018-09-14 14:50:03 -050013constexpr auto PCAP_PATH = "/xyz/openbmc_project/control/host0/power_cap";
Andrew Geissler52cf26a2017-07-06 12:56:32 -050014constexpr auto PCAP_INTERFACE = "xyz.openbmc_project.Control.Power.Cap";
15
16constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
17constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
18constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
19
20constexpr auto POWER_CAP_PROP = "PowerCap";
21constexpr auto POWER_CAP_ENABLE_PROP = "PowerCapEnable";
22
Andrew Geissler32016d12017-06-20 15:46:52 -050023using namespace phosphor::logging;
Matt Spinler00a64782019-07-24 14:29:24 -050024namespace fs = std::experimental::filesystem;
Andrew Geissler32016d12017-06-20 15:46:52 -050025
Gunnar Mills94df8c92018-09-14 14:50:03 -050026std::string PowerCap::getService(std::string path, std::string interface)
Andrew Geissler52cf26a2017-07-06 12:56:32 -050027{
Gunnar Mills94df8c92018-09-14 14:50:03 -050028 auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
29 MAPPER_INTERFACE, "GetObject");
Andrew Geissler52cf26a2017-07-06 12:56:32 -050030
31 mapper.append(path, std::vector<std::string>({interface}));
32 auto mapperResponseMsg = bus.call(mapper);
33
34 if (mapperResponseMsg.is_method_error())
35 {
Gunnar Mills94df8c92018-09-14 14:50:03 -050036 log<level::ERR>("Error in mapper call", entry("PATH=%s", path.c_str()),
Andrew Geissler52cf26a2017-07-06 12:56:32 -050037 entry("INTERFACE=%s", interface.c_str()));
38 // TODO openbmc/openbmc#851 - Once available, throw returned error
39 throw std::runtime_error("Error in mapper call");
40 }
41
42 std::map<std::string, std::vector<std::string>> mapperResponse;
43 mapperResponseMsg.read(mapperResponse);
44 if (mapperResponse.empty())
45 {
46 log<level::ERR>("Error reading mapper response",
47 entry("PATH=%s", path.c_str()),
48 entry("INTERFACE=%s", interface.c_str()));
49 // TODO openbmc/openbmc#1712 - Handle empty mapper resp. consistently
50 throw std::runtime_error("Error reading mapper response");
51 }
52
53 return mapperResponse.begin()->first;
54}
55
Andrew Geissler4cea4d22017-07-10 15:13:33 -050056uint32_t PowerCap::getOccInput(uint32_t pcap, bool pcapEnabled)
57{
58 if (!pcapEnabled)
59 {
60 // Pcap disabled, return 0 to indicate disabled
61 return 0;
62 }
63
64 // If pcap is not disabled then just return the pcap with the derating
65 // factor applied.
Gunnar Mills94df8c92018-09-14 14:50:03 -050066 return ((static_cast<uint64_t>(pcap) * PS_DERATING_FACTOR) / 100);
Andrew Geissler4cea4d22017-07-10 15:13:33 -050067}
68
Andrew Geissler52cf26a2017-07-06 12:56:32 -050069uint32_t PowerCap::getPcap()
70{
Gunnar Mills94df8c92018-09-14 14:50:03 -050071 auto settingService = getService(PCAP_PATH, PCAP_INTERFACE);
Andrew Geissler52cf26a2017-07-06 12:56:32 -050072
Gunnar Mills94df8c92018-09-14 14:50:03 -050073 auto method =
74 this->bus.new_method_call(settingService.c_str(), PCAP_PATH,
75 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler52cf26a2017-07-06 12:56:32 -050076
77 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
78 auto reply = this->bus.call(method);
79
80 if (reply.is_method_error())
81 {
82 log<level::ERR>("Error in getPcap prop");
83 return 0;
84 }
85 sdbusplus::message::variant<uint32_t> pcap;
86 reply.read(pcap);
87
William A. Kennington III29a8ed12018-11-06 15:05:11 -080088 return sdbusplus::message::variant_ns::get<uint32_t>(pcap);
Andrew Geissler52cf26a2017-07-06 12:56:32 -050089}
90
91bool PowerCap::getPcapEnabled()
92{
Gunnar Mills94df8c92018-09-14 14:50:03 -050093 auto settingService = getService(PCAP_PATH, PCAP_INTERFACE);
Andrew Geissler52cf26a2017-07-06 12:56:32 -050094
Gunnar Mills94df8c92018-09-14 14:50:03 -050095 auto method =
96 this->bus.new_method_call(settingService.c_str(), PCAP_PATH,
97 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler52cf26a2017-07-06 12:56:32 -050098
99 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
100 auto reply = this->bus.call(method);
101
102 if (reply.is_method_error())
103 {
104 log<level::ERR>("Error in getPcapEnabled prop");
105 return 0;
106 }
107 sdbusplus::message::variant<bool> pcapEnabled;
108 reply.read(pcapEnabled);
109
William A. Kennington III29a8ed12018-11-06 15:05:11 -0800110 return sdbusplus::message::variant_ns::get<bool>(pcapEnabled);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500111}
Andrew Geissler32016d12017-06-20 15:46:52 -0500112
Matt Spinlereaaf3b22019-07-16 10:29:27 -0500113std::string PowerCap::getPcapFilename(const fs::path& path)
114{
115 std::regex expr{"power\\d+_cap_user$"};
116 for (auto& file : fs::directory_iterator(path))
117 {
118 if (std::regex_search(file.path().string(), expr))
119 {
120 return file.path().filename();
121 }
122 }
123 return std::string{};
124}
125
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500126void PowerCap::writeOcc(uint32_t pcapValue)
127{
128 // Create path out to master occ hwmon entry
129 std::unique_ptr<fs::path> fileName =
Gunnar Mills94df8c92018-09-14 14:50:03 -0500130 std::make_unique<fs::path>(OCC_HWMON_PATH);
Lei YU41470e52017-11-30 16:03:50 +0800131 *fileName /= occMasterName;
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500132 *fileName /= "/hwmon/";
133
134 // Need to get the hwmonXX directory name, there better only be 1 dir
135 assert(std::distance(fs::directory_iterator(*fileName),
136 fs::directory_iterator{}) == 1);
137 // Now set our path to this full path, including this hwmonXX directory
138 fileName = std::make_unique<fs::path>(*fs::directory_iterator(*fileName));
139 // Append on the hwmon string where we write the user power cap
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500140
Matt Spinlereaaf3b22019-07-16 10:29:27 -0500141 auto baseName = getPcapFilename(*fileName);
142 if (baseName.empty())
143 {
144 log<level::ERR>("Could not find a power cap file to write to",
145 entry("PATH=%s", *fileName->c_str()));
146 return;
147 }
148 *fileName /= baseName;
149
150 uint64_t microWatts = pcapValue * 1000000ull;
151
152 auto pcapString{std::to_string(microWatts)};
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500153
154 log<level::INFO>("Writing pcap value to hwmon",
Gunnar Mills94df8c92018-09-14 14:50:03 -0500155 entry("PCAP_PATH=%s", fileName->c_str()),
156 entry("PCAP_VALUE=%s", pcapString.c_str()));
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500157 // Open the hwmon file and write the power cap
158 std::ofstream file(*fileName, std::ios::out);
159 file << pcapString;
160 file.close();
161 return;
162}
163
Andrew Geissler32016d12017-06-20 15:46:52 -0500164void PowerCap::pcapChanged(sdbusplus::message::message& msg)
165{
Andrew Geissler32016d12017-06-20 15:46:52 -0500166 if (!occStatus.occActive())
167 {
168 // Nothing to do
169 return;
170 }
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500171
172 uint32_t pcap = 0;
173 bool pcapEnabled = false;
174
175 std::string msgSensor;
176 std::map<std::string, sdbusplus::message::variant<uint32_t, bool>> msgData;
177 msg.read(msgSensor, msgData);
178
179 // Retrieve which property changed via the msg and read the other one
180 auto valPropMap = msgData.find(POWER_CAP_PROP);
181 if (valPropMap != msgData.end())
182 {
Gunnar Mills94df8c92018-09-14 14:50:03 -0500183 pcap =
184 sdbusplus::message::variant_ns::get<uint32_t>(valPropMap->second);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500185 pcapEnabled = getPcapEnabled();
186 }
187 else
188 {
189 valPropMap = msgData.find(POWER_CAP_ENABLE_PROP);
190 if (valPropMap != msgData.end())
191 {
Gunnar Mills94df8c92018-09-14 14:50:03 -0500192 pcapEnabled =
193 sdbusplus::message::variant_ns::get<bool>(valPropMap->second);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500194 pcap = getPcap();
195 }
196 else
197 {
198 log<level::INFO>("Unknown power cap property changed");
199 return;
200 }
201 }
202
Gunnar Mills94df8c92018-09-14 14:50:03 -0500203 log<level::INFO>("Power Cap Property Change", entry("PCAP=%u", pcap),
204 entry("PCAP_ENABLED=%u", pcapEnabled));
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500205
206 // Determine desired action to write to occ
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500207
Andrew Geissler4cea4d22017-07-10 15:13:33 -0500208 auto occInput = getOccInput(pcap, pcapEnabled);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500209
210 // Write action to occ
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500211 writeOcc(occInput);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500212
213 return;
Andrew Geissler32016d12017-06-20 15:46:52 -0500214}
215
Gunnar Mills94df8c92018-09-14 14:50:03 -0500216} // namespace powercap
Andrew Geissler32016d12017-06-20 15:46:52 -0500217
218} // namespace occ
219
Gunnar Mills94df8c92018-09-14 14:50:03 -0500220} // namespace open_power