blob: 0aca3e4764ca4463c2eeeb31c3e8e0f6f3f2a59a [file] [log] [blame]
Andrew Geissler32016d12017-06-20 15:46:52 -05001#include <powercap.hpp>
2#include <phosphor-logging/log.hpp>
3
4namespace open_power
5{
6namespace occ
7{
8namespace powercap
9{
10
Andrew Geissler52cf26a2017-07-06 12:56:32 -050011constexpr auto PCAP_PATH = "/xyz/openbmc_project/control/host0/power_cap";
12constexpr 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
Andrew Geissler52cf26a2017-07-06 12:56:32 -050023std::string PowerCap::getService(std::string path,
24 std::string interface)
25{
26 auto mapper = bus.new_method_call(MAPPER_BUSNAME,
27 MAPPER_PATH,
28 MAPPER_INTERFACE,
29 "GetObject");
30
31 mapper.append(path, std::vector<std::string>({interface}));
32 auto mapperResponseMsg = bus.call(mapper);
33
34 if (mapperResponseMsg.is_method_error())
35 {
36 log<level::ERR>("Error in mapper call",
37 entry("PATH=%s", path.c_str()),
38 entry("INTERFACE=%s", interface.c_str()));
39 // TODO openbmc/openbmc#851 - Once available, throw returned error
40 throw std::runtime_error("Error in mapper call");
41 }
42
43 std::map<std::string, std::vector<std::string>> mapperResponse;
44 mapperResponseMsg.read(mapperResponse);
45 if (mapperResponse.empty())
46 {
47 log<level::ERR>("Error reading mapper response",
48 entry("PATH=%s", path.c_str()),
49 entry("INTERFACE=%s", interface.c_str()));
50 // TODO openbmc/openbmc#1712 - Handle empty mapper resp. consistently
51 throw std::runtime_error("Error reading mapper response");
52 }
53
54 return mapperResponse.begin()->first;
55}
56
Andrew Geissler4cea4d22017-07-10 15:13:33 -050057uint32_t PowerCap::getOccInput(uint32_t pcap, bool pcapEnabled)
58{
59 if (!pcapEnabled)
60 {
61 // Pcap disabled, return 0 to indicate disabled
62 return 0;
63 }
64
65 // If pcap is not disabled then just return the pcap with the derating
66 // factor applied.
67 return( (static_cast<uint64_t>(pcap) * PS_DERATING_FACTOR) /100);
68}
69
Andrew Geissler52cf26a2017-07-06 12:56:32 -050070uint32_t PowerCap::getPcap()
71{
72 auto settingService = getService(PCAP_PATH,PCAP_INTERFACE);
73
74 auto method = this->bus.new_method_call(settingService.c_str(),
75 PCAP_PATH,
76 "org.freedesktop.DBus.Properties",
77 "Get");
78
79 method.append(PCAP_INTERFACE, POWER_CAP_PROP);
80 auto reply = this->bus.call(method);
81
82 if (reply.is_method_error())
83 {
84 log<level::ERR>("Error in getPcap prop");
85 return 0;
86 }
87 sdbusplus::message::variant<uint32_t> pcap;
88 reply.read(pcap);
89
90 return pcap.get<uint32_t>();
91}
92
93bool PowerCap::getPcapEnabled()
94{
95 auto settingService = getService(PCAP_PATH,PCAP_INTERFACE);
96
97 auto method = this->bus.new_method_call(settingService.c_str(),
98 PCAP_PATH,
99 "org.freedesktop.DBus.Properties",
100 "Get");
101
102 method.append(PCAP_INTERFACE, POWER_CAP_ENABLE_PROP);
103 auto reply = this->bus.call(method);
104
105 if (reply.is_method_error())
106 {
107 log<level::ERR>("Error in getPcapEnabled prop");
108 return 0;
109 }
110 sdbusplus::message::variant<bool> pcapEnabled;
111 reply.read(pcapEnabled);
112
113 return pcapEnabled.get<bool>();
114}
Andrew Geissler32016d12017-06-20 15:46:52 -0500115
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500116void PowerCap::writeOcc(uint32_t pcapValue)
117{
118 // Create path out to master occ hwmon entry
119 std::unique_ptr<fs::path> fileName =
120 std::make_unique<fs::path>(OCC_HWMON_PATH);
121 *fileName /= OCC_MASTER_NAME;
122 *fileName /= "/hwmon/";
123
124 // Need to get the hwmonXX directory name, there better only be 1 dir
125 assert(std::distance(fs::directory_iterator(*fileName),
126 fs::directory_iterator{}) == 1);
127 // Now set our path to this full path, including this hwmonXX directory
128 fileName = std::make_unique<fs::path>(*fs::directory_iterator(*fileName));
129 // Append on the hwmon string where we write the user power cap
130 *fileName /= "/caps1_user";
131
132 auto pcapString {std::to_string(pcapValue)};
133
134 log<level::INFO>("Writing pcap value to hwmon",
135 entry("PCAP_PATH=%s",*fileName),
136 entry("PCAP_VALUE=%s",pcapString.c_str()));
137 // Open the hwmon file and write the power cap
138 std::ofstream file(*fileName, std::ios::out);
139 file << pcapString;
140 file.close();
141 return;
142}
143
Andrew Geissler32016d12017-06-20 15:46:52 -0500144void PowerCap::pcapChanged(sdbusplus::message::message& msg)
145{
Andrew Geissler32016d12017-06-20 15:46:52 -0500146 if (!occStatus.occActive())
147 {
148 // Nothing to do
149 return;
150 }
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500151
152 uint32_t pcap = 0;
153 bool pcapEnabled = false;
154
155 std::string msgSensor;
156 std::map<std::string, sdbusplus::message::variant<uint32_t, bool>> msgData;
157 msg.read(msgSensor, msgData);
158
159 // Retrieve which property changed via the msg and read the other one
160 auto valPropMap = msgData.find(POWER_CAP_PROP);
161 if (valPropMap != msgData.end())
162 {
163 pcap = sdbusplus::message::variant_ns::get<uint32_t>(
164 valPropMap->second);
165 pcapEnabled = getPcapEnabled();
166 }
167 else
168 {
169 valPropMap = msgData.find(POWER_CAP_ENABLE_PROP);
170 if (valPropMap != msgData.end())
171 {
172 pcapEnabled = sdbusplus::message::variant_ns::get<bool>(
173 valPropMap->second);
174 pcap = getPcap();
175 }
176 else
177 {
178 log<level::INFO>("Unknown power cap property changed");
179 return;
180 }
181 }
182
183 log<level::INFO>("Power Cap Property Change",
184 entry("PCAP=%u",pcap),
185 entry("PCAP_ENABLED=%u",pcapEnabled));
186
187 // Determine desired action to write to occ
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500188
Andrew Geissler4cea4d22017-07-10 15:13:33 -0500189 auto occInput = getOccInput(pcap, pcapEnabled);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500190
191 // Write action to occ
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500192 writeOcc(occInput);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500193
194 return;
Andrew Geissler32016d12017-06-20 15:46:52 -0500195}
196
197} // namespace open_power
198
199} // namespace occ
200
201}// namespace powercap