blob: 638d5feffa0460d37d8b6674fc0f70f34ce9fe25 [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>
Andrew Geissler32016d12017-06-20 15:46:52 -05004
5namespace open_power
6{
7namespace occ
8{
9namespace powercap
10{
11
Gunnar Mills94df8c92018-09-14 14:50:03 -050012constexpr auto PCAP_PATH = "/xyz/openbmc_project/control/host0/power_cap";
Andrew Geissler52cf26a2017-07-06 12:56:32 -050013constexpr auto PCAP_INTERFACE = "xyz.openbmc_project.Control.Power.Cap";
14
15constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
16constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
17constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
18
19constexpr auto POWER_CAP_PROP = "PowerCap";
20constexpr auto POWER_CAP_ENABLE_PROP = "PowerCapEnable";
21
Andrew Geissler32016d12017-06-20 15:46:52 -050022using namespace phosphor::logging;
23
Gunnar Mills94df8c92018-09-14 14:50:03 -050024std::string PowerCap::getService(std::string path, std::string interface)
Andrew Geissler52cf26a2017-07-06 12:56:32 -050025{
Gunnar Mills94df8c92018-09-14 14:50:03 -050026 auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
27 MAPPER_INTERFACE, "GetObject");
Andrew Geissler52cf26a2017-07-06 12:56:32 -050028
29 mapper.append(path, std::vector<std::string>({interface}));
30 auto mapperResponseMsg = bus.call(mapper);
31
32 if (mapperResponseMsg.is_method_error())
33 {
Gunnar Mills94df8c92018-09-14 14:50:03 -050034 log<level::ERR>("Error in mapper call", entry("PATH=%s", path.c_str()),
Andrew Geissler52cf26a2017-07-06 12:56:32 -050035 entry("INTERFACE=%s", interface.c_str()));
36 // TODO openbmc/openbmc#851 - Once available, throw returned error
37 throw std::runtime_error("Error in mapper call");
38 }
39
40 std::map<std::string, std::vector<std::string>> mapperResponse;
41 mapperResponseMsg.read(mapperResponse);
42 if (mapperResponse.empty())
43 {
44 log<level::ERR>("Error reading mapper response",
45 entry("PATH=%s", path.c_str()),
46 entry("INTERFACE=%s", interface.c_str()));
47 // TODO openbmc/openbmc#1712 - Handle empty mapper resp. consistently
48 throw std::runtime_error("Error reading mapper response");
49 }
50
51 return mapperResponse.begin()->first;
52}
53
Andrew Geissler4cea4d22017-07-10 15:13:33 -050054uint32_t PowerCap::getOccInput(uint32_t pcap, bool pcapEnabled)
55{
56 if (!pcapEnabled)
57 {
58 // Pcap disabled, return 0 to indicate disabled
59 return 0;
60 }
61
62 // If pcap is not disabled then just return the pcap with the derating
63 // factor applied.
Gunnar Mills94df8c92018-09-14 14:50:03 -050064 return ((static_cast<uint64_t>(pcap) * PS_DERATING_FACTOR) / 100);
Andrew Geissler4cea4d22017-07-10 15:13:33 -050065}
66
Andrew Geissler52cf26a2017-07-06 12:56:32 -050067uint32_t PowerCap::getPcap()
68{
Gunnar Mills94df8c92018-09-14 14:50:03 -050069 auto settingService = getService(PCAP_PATH, PCAP_INTERFACE);
Andrew Geissler52cf26a2017-07-06 12:56:32 -050070
Gunnar Mills94df8c92018-09-14 14:50:03 -050071 auto method =
72 this->bus.new_method_call(settingService.c_str(), PCAP_PATH,
73 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler52cf26a2017-07-06 12:56:32 -050074
75 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
76 auto reply = this->bus.call(method);
77
78 if (reply.is_method_error())
79 {
80 log<level::ERR>("Error in getPcap prop");
81 return 0;
82 }
83 sdbusplus::message::variant<uint32_t> pcap;
84 reply.read(pcap);
85
William A. Kennington III29a8ed12018-11-06 15:05:11 -080086 return sdbusplus::message::variant_ns::get<uint32_t>(pcap);
Andrew Geissler52cf26a2017-07-06 12:56:32 -050087}
88
89bool PowerCap::getPcapEnabled()
90{
Gunnar Mills94df8c92018-09-14 14:50:03 -050091 auto settingService = getService(PCAP_PATH, PCAP_INTERFACE);
Andrew Geissler52cf26a2017-07-06 12:56:32 -050092
Gunnar Mills94df8c92018-09-14 14:50:03 -050093 auto method =
94 this->bus.new_method_call(settingService.c_str(), PCAP_PATH,
95 "org.freedesktop.DBus.Properties", "Get");
Andrew Geissler52cf26a2017-07-06 12:56:32 -050096
97 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
98 auto reply = this->bus.call(method);
99
100 if (reply.is_method_error())
101 {
102 log<level::ERR>("Error in getPcapEnabled prop");
103 return 0;
104 }
105 sdbusplus::message::variant<bool> pcapEnabled;
106 reply.read(pcapEnabled);
107
William A. Kennington III29a8ed12018-11-06 15:05:11 -0800108 return sdbusplus::message::variant_ns::get<bool>(pcapEnabled);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500109}
Andrew Geissler32016d12017-06-20 15:46:52 -0500110
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500111void PowerCap::writeOcc(uint32_t pcapValue)
112{
113 // Create path out to master occ hwmon entry
114 std::unique_ptr<fs::path> fileName =
Gunnar Mills94df8c92018-09-14 14:50:03 -0500115 std::make_unique<fs::path>(OCC_HWMON_PATH);
Lei YU41470e52017-11-30 16:03:50 +0800116 *fileName /= occMasterName;
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500117 *fileName /= "/hwmon/";
118
119 // Need to get the hwmonXX directory name, there better only be 1 dir
120 assert(std::distance(fs::directory_iterator(*fileName),
121 fs::directory_iterator{}) == 1);
122 // Now set our path to this full path, including this hwmonXX directory
123 fileName = std::make_unique<fs::path>(*fs::directory_iterator(*fileName));
124 // Append on the hwmon string where we write the user power cap
125 *fileName /= "/caps1_user";
126
Gunnar Mills94df8c92018-09-14 14:50:03 -0500127 auto pcapString{std::to_string(pcapValue)};
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500128
129 log<level::INFO>("Writing pcap value to hwmon",
Gunnar Mills94df8c92018-09-14 14:50:03 -0500130 entry("PCAP_PATH=%s", fileName->c_str()),
131 entry("PCAP_VALUE=%s", pcapString.c_str()));
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500132 // Open the hwmon file and write the power cap
133 std::ofstream file(*fileName, std::ios::out);
134 file << pcapString;
135 file.close();
136 return;
137}
138
Andrew Geissler32016d12017-06-20 15:46:52 -0500139void PowerCap::pcapChanged(sdbusplus::message::message& msg)
140{
Andrew Geissler32016d12017-06-20 15:46:52 -0500141 if (!occStatus.occActive())
142 {
143 // Nothing to do
144 return;
145 }
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500146
147 uint32_t pcap = 0;
148 bool pcapEnabled = false;
149
150 std::string msgSensor;
151 std::map<std::string, sdbusplus::message::variant<uint32_t, bool>> msgData;
152 msg.read(msgSensor, msgData);
153
154 // Retrieve which property changed via the msg and read the other one
155 auto valPropMap = msgData.find(POWER_CAP_PROP);
156 if (valPropMap != msgData.end())
157 {
Gunnar Mills94df8c92018-09-14 14:50:03 -0500158 pcap =
159 sdbusplus::message::variant_ns::get<uint32_t>(valPropMap->second);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500160 pcapEnabled = getPcapEnabled();
161 }
162 else
163 {
164 valPropMap = msgData.find(POWER_CAP_ENABLE_PROP);
165 if (valPropMap != msgData.end())
166 {
Gunnar Mills94df8c92018-09-14 14:50:03 -0500167 pcapEnabled =
168 sdbusplus::message::variant_ns::get<bool>(valPropMap->second);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500169 pcap = getPcap();
170 }
171 else
172 {
173 log<level::INFO>("Unknown power cap property changed");
174 return;
175 }
176 }
177
Gunnar Mills94df8c92018-09-14 14:50:03 -0500178 log<level::INFO>("Power Cap Property Change", entry("PCAP=%u", pcap),
179 entry("PCAP_ENABLED=%u", pcapEnabled));
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500180
181 // Determine desired action to write to occ
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500182
Andrew Geissler4cea4d22017-07-10 15:13:33 -0500183 auto occInput = getOccInput(pcap, pcapEnabled);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500184
185 // Write action to occ
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500186 writeOcc(occInput);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500187
188 return;
Andrew Geissler32016d12017-06-20 15:46:52 -0500189}
190
Gunnar Mills94df8c92018-09-14 14:50:03 -0500191} // namespace powercap
Andrew Geissler32016d12017-06-20 15:46:52 -0500192
193} // namespace occ
194
Gunnar Mills94df8c92018-09-14 14:50:03 -0500195} // namespace open_power