blob: bc4d3cad02b811b1a8c8f4c4d84d3cd9273fa540 [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>
Andrew Geissler32016d12017-06-20 15:46:52 -05003
4namespace open_power
5{
6namespace occ
7{
8namespace powercap
9{
10
Gunnar Mills94df8c92018-09-14 14:50:03 -050011constexpr auto PCAP_PATH = "/xyz/openbmc_project/control/host0/power_cap";
Andrew Geissler52cf26a2017-07-06 12:56:32 -050012constexpr auto PCAP_INTERFACE = "xyz.openbmc_project.Control.Power.Cap";
13
14constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
15constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
16constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
17
18constexpr auto POWER_CAP_PROP = "PowerCap";
19constexpr auto POWER_CAP_ENABLE_PROP = "PowerCapEnable";
20
Andrew Geissler32016d12017-06-20 15:46:52 -050021using namespace phosphor::logging;
22
Gunnar Mills94df8c92018-09-14 14:50:03 -050023std::string PowerCap::getService(std::string path, std::string interface)
Andrew Geissler52cf26a2017-07-06 12:56:32 -050024{
Gunnar Mills94df8c92018-09-14 14:50:03 -050025 auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
26 MAPPER_INTERFACE, "GetObject");
Andrew Geissler52cf26a2017-07-06 12:56:32 -050027
28 mapper.append(path, std::vector<std::string>({interface}));
29 auto mapperResponseMsg = bus.call(mapper);
30
31 if (mapperResponseMsg.is_method_error())
32 {
Gunnar Mills94df8c92018-09-14 14:50:03 -050033 log<level::ERR>("Error in mapper call", entry("PATH=%s", path.c_str()),
Andrew Geissler52cf26a2017-07-06 12:56:32 -050034 entry("INTERFACE=%s", interface.c_str()));
35 // TODO openbmc/openbmc#851 - Once available, throw returned error
36 throw std::runtime_error("Error in mapper call");
37 }
38
39 std::map<std::string, std::vector<std::string>> mapperResponse;
40 mapperResponseMsg.read(mapperResponse);
41 if (mapperResponse.empty())
42 {
43 log<level::ERR>("Error reading mapper response",
44 entry("PATH=%s", path.c_str()),
45 entry("INTERFACE=%s", interface.c_str()));
46 // TODO openbmc/openbmc#1712 - Handle empty mapper resp. consistently
47 throw std::runtime_error("Error reading mapper response");
48 }
49
50 return mapperResponse.begin()->first;
51}
52
Andrew Geissler4cea4d22017-07-10 15:13:33 -050053uint32_t PowerCap::getOccInput(uint32_t pcap, bool pcapEnabled)
54{
55 if (!pcapEnabled)
56 {
57 // Pcap disabled, return 0 to indicate disabled
58 return 0;
59 }
60
61 // If pcap is not disabled then just return the pcap with the derating
62 // factor applied.
Gunnar Mills94df8c92018-09-14 14:50:03 -050063 return ((static_cast<uint64_t>(pcap) * PS_DERATING_FACTOR) / 100);
Andrew Geissler4cea4d22017-07-10 15:13:33 -050064}
65
Andrew Geissler52cf26a2017-07-06 12:56:32 -050066uint32_t PowerCap::getPcap()
67{
Gunnar Mills94df8c92018-09-14 14:50:03 -050068 auto settingService = getService(PCAP_PATH, PCAP_INTERFACE);
Andrew Geissler52cf26a2017-07-06 12:56:32 -050069
Gunnar Mills94df8c92018-09-14 14:50:03 -050070 auto method =
71 this->bus.new_method_call(settingService.c_str(), PCAP_PATH,
72 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler52cf26a2017-07-06 12:56:32 -050073
74 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
75 auto reply = this->bus.call(method);
76
77 if (reply.is_method_error())
78 {
79 log<level::ERR>("Error in getPcap prop");
80 return 0;
81 }
82 sdbusplus::message::variant<uint32_t> pcap;
83 reply.read(pcap);
84
85 return pcap.get<uint32_t>();
86}
87
88bool PowerCap::getPcapEnabled()
89{
Gunnar Mills94df8c92018-09-14 14:50:03 -050090 auto settingService = getService(PCAP_PATH, PCAP_INTERFACE);
Andrew Geissler52cf26a2017-07-06 12:56:32 -050091
Gunnar Mills94df8c92018-09-14 14:50:03 -050092 auto method =
93 this->bus.new_method_call(settingService.c_str(), PCAP_PATH,
94 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler52cf26a2017-07-06 12:56:32 -050095
96 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
97 auto reply = this->bus.call(method);
98
99 if (reply.is_method_error())
100 {
101 log<level::ERR>("Error in getPcapEnabled prop");
102 return 0;
103 }
104 sdbusplus::message::variant<bool> pcapEnabled;
105 reply.read(pcapEnabled);
106
107 return pcapEnabled.get<bool>();
108}
Andrew Geissler32016d12017-06-20 15:46:52 -0500109
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500110void PowerCap::writeOcc(uint32_t pcapValue)
111{
112 // Create path out to master occ hwmon entry
113 std::unique_ptr<fs::path> fileName =
Gunnar Mills94df8c92018-09-14 14:50:03 -0500114 std::make_unique<fs::path>(OCC_HWMON_PATH);
Lei YU41470e52017-11-30 16:03:50 +0800115 *fileName /= occMasterName;
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500116 *fileName /= "/hwmon/";
117
118 // Need to get the hwmonXX directory name, there better only be 1 dir
119 assert(std::distance(fs::directory_iterator(*fileName),
120 fs::directory_iterator{}) == 1);
121 // Now set our path to this full path, including this hwmonXX directory
122 fileName = std::make_unique<fs::path>(*fs::directory_iterator(*fileName));
123 // Append on the hwmon string where we write the user power cap
124 *fileName /= "/caps1_user";
125
Gunnar Mills94df8c92018-09-14 14:50:03 -0500126 auto pcapString{std::to_string(pcapValue)};
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500127
128 log<level::INFO>("Writing pcap value to hwmon",
Gunnar Mills94df8c92018-09-14 14:50:03 -0500129 entry("PCAP_PATH=%s", fileName->c_str()),
130 entry("PCAP_VALUE=%s", pcapString.c_str()));
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500131 // Open the hwmon file and write the power cap
132 std::ofstream file(*fileName, std::ios::out);
133 file << pcapString;
134 file.close();
135 return;
136}
137
Andrew Geissler32016d12017-06-20 15:46:52 -0500138void PowerCap::pcapChanged(sdbusplus::message::message& msg)
139{
Andrew Geissler32016d12017-06-20 15:46:52 -0500140 if (!occStatus.occActive())
141 {
142 // Nothing to do
143 return;
144 }
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500145
146 uint32_t pcap = 0;
147 bool pcapEnabled = false;
148
149 std::string msgSensor;
150 std::map<std::string, sdbusplus::message::variant<uint32_t, bool>> msgData;
151 msg.read(msgSensor, msgData);
152
153 // Retrieve which property changed via the msg and read the other one
154 auto valPropMap = msgData.find(POWER_CAP_PROP);
155 if (valPropMap != msgData.end())
156 {
Gunnar Mills94df8c92018-09-14 14:50:03 -0500157 pcap =
158 sdbusplus::message::variant_ns::get<uint32_t>(valPropMap->second);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500159 pcapEnabled = getPcapEnabled();
160 }
161 else
162 {
163 valPropMap = msgData.find(POWER_CAP_ENABLE_PROP);
164 if (valPropMap != msgData.end())
165 {
Gunnar Mills94df8c92018-09-14 14:50:03 -0500166 pcapEnabled =
167 sdbusplus::message::variant_ns::get<bool>(valPropMap->second);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500168 pcap = getPcap();
169 }
170 else
171 {
172 log<level::INFO>("Unknown power cap property changed");
173 return;
174 }
175 }
176
Gunnar Mills94df8c92018-09-14 14:50:03 -0500177 log<level::INFO>("Power Cap Property Change", entry("PCAP=%u", pcap),
178 entry("PCAP_ENABLED=%u", pcapEnabled));
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500179
180 // Determine desired action to write to occ
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500181
Andrew Geissler4cea4d22017-07-10 15:13:33 -0500182 auto occInput = getOccInput(pcap, pcapEnabled);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500183
184 // Write action to occ
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500185 writeOcc(occInput);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500186
187 return;
Andrew Geissler32016d12017-06-20 15:46:52 -0500188}
189
Gunnar Mills94df8c92018-09-14 14:50:03 -0500190} // namespace powercap
Andrew Geissler32016d12017-06-20 15:46:52 -0500191
192} // namespace occ
193
Gunnar Mills94df8c92018-09-14 14:50:03 -0500194} // namespace open_power