blob: 39c7416ece842938efc4496b099406660e56343d [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
Andrew Geissler4cea4d22017-07-10 15:13:33 -050026uint32_t PowerCap::getOccInput(uint32_t pcap, bool pcapEnabled)
27{
28 if (!pcapEnabled)
29 {
30 // Pcap disabled, return 0 to indicate disabled
31 return 0;
32 }
33
34 // If pcap is not disabled then just return the pcap with the derating
35 // factor applied.
Gunnar Mills94df8c92018-09-14 14:50:03 -050036 return ((static_cast<uint64_t>(pcap) * PS_DERATING_FACTOR) / 100);
Andrew Geissler4cea4d22017-07-10 15:13:33 -050037}
38
Andrew Geissler52cf26a2017-07-06 12:56:32 -050039uint32_t PowerCap::getPcap()
40{
George Liuf3b75142021-06-10 11:22:50 +080041 utils::PropertyValue pcap{};
42 try
Andrew Geissler52cf26a2017-07-06 12:56:32 -050043 {
George Liuf3b75142021-06-10 11:22:50 +080044 pcap = utils::getProperty(PCAP_PATH, PCAP_INTERFACE, POWER_CAP_PROP);
45
46 return std::get<uint32_t>(pcap);
47 }
48 catch (const sdbusplus::exception::SdBusError& e)
49 {
50 log<level::ERR>("Failed to get PowerCap property",
51 entry("ERROR=%s", e.what()),
52 entry("PATH=%s", PCAP_PATH));
53
Andrew Geissler52cf26a2017-07-06 12:56:32 -050054 return 0;
55 }
Andrew Geissler52cf26a2017-07-06 12:56:32 -050056}
57
58bool PowerCap::getPcapEnabled()
59{
George Liuf3b75142021-06-10 11:22:50 +080060 utils::PropertyValue pcapEnabled{};
61 try
Andrew Geissler52cf26a2017-07-06 12:56:32 -050062 {
George Liuf3b75142021-06-10 11:22:50 +080063 pcapEnabled = utils::getProperty(PCAP_PATH, PCAP_INTERFACE,
64 POWER_CAP_ENABLE_PROP);
Andrew Geissler52cf26a2017-07-06 12:56:32 -050065
George Liuf3b75142021-06-10 11:22:50 +080066 return std::get<bool>(pcapEnabled);
67 }
68 catch (const sdbusplus::exception::SdBusError& e)
69 {
70 log<level::ERR>("Failed to get PowerCapEnable property",
71 entry("ERROR=%s", e.what()),
72 entry("PATH=%s", PCAP_PATH));
73
74 return false;
75 }
Andrew Geissler52cf26a2017-07-06 12:56:32 -050076}
Andrew Geissler32016d12017-06-20 15:46:52 -050077
Matt Spinlereaaf3b22019-07-16 10:29:27 -050078std::string PowerCap::getPcapFilename(const fs::path& path)
79{
80 std::regex expr{"power\\d+_cap_user$"};
81 for (auto& file : fs::directory_iterator(path))
82 {
83 if (std::regex_search(file.path().string(), expr))
84 {
85 return file.path().filename();
86 }
87 }
88 return std::string{};
89}
90
Andrew Geissler6ac874e2017-07-10 15:54:58 -050091void PowerCap::writeOcc(uint32_t pcapValue)
92{
93 // Create path out to master occ hwmon entry
94 std::unique_ptr<fs::path> fileName =
Gunnar Mills94df8c92018-09-14 14:50:03 -050095 std::make_unique<fs::path>(OCC_HWMON_PATH);
Lei YU41470e52017-11-30 16:03:50 +080096 *fileName /= occMasterName;
Andrew Geissler6ac874e2017-07-10 15:54:58 -050097 *fileName /= "/hwmon/";
98
99 // Need to get the hwmonXX directory name, there better only be 1 dir
100 assert(std::distance(fs::directory_iterator(*fileName),
101 fs::directory_iterator{}) == 1);
102 // Now set our path to this full path, including this hwmonXX directory
103 fileName = std::make_unique<fs::path>(*fs::directory_iterator(*fileName));
104 // Append on the hwmon string where we write the user power cap
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500105
Matt Spinlereaaf3b22019-07-16 10:29:27 -0500106 auto baseName = getPcapFilename(*fileName);
107 if (baseName.empty())
108 {
109 log<level::ERR>("Could not find a power cap file to write to",
110 entry("PATH=%s", *fileName->c_str()));
111 return;
112 }
113 *fileName /= baseName;
114
115 uint64_t microWatts = pcapValue * 1000000ull;
116
117 auto pcapString{std::to_string(microWatts)};
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500118
119 log<level::INFO>("Writing pcap value to hwmon",
Gunnar Mills94df8c92018-09-14 14:50:03 -0500120 entry("PCAP_PATH=%s", fileName->c_str()),
121 entry("PCAP_VALUE=%s", pcapString.c_str()));
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500122 // Open the hwmon file and write the power cap
123 std::ofstream file(*fileName, std::ios::out);
124 file << pcapString;
125 file.close();
126 return;
127}
128
Andrew Geissler32016d12017-06-20 15:46:52 -0500129void PowerCap::pcapChanged(sdbusplus::message::message& msg)
130{
Andrew Geissler32016d12017-06-20 15:46:52 -0500131 if (!occStatus.occActive())
132 {
133 // Nothing to do
134 return;
135 }
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500136
137 uint32_t pcap = 0;
138 bool pcapEnabled = false;
139
140 std::string msgSensor;
Patrick Williamse0962702020-05-13 17:50:22 -0500141 std::map<std::string, std::variant<uint32_t, bool>> msgData;
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500142 msg.read(msgSensor, msgData);
143
144 // Retrieve which property changed via the msg and read the other one
145 auto valPropMap = msgData.find(POWER_CAP_PROP);
146 if (valPropMap != msgData.end())
147 {
Patrick Williams305ff8b2020-05-13 11:17:39 -0500148 pcap = std::get<uint32_t>(valPropMap->second);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500149 pcapEnabled = getPcapEnabled();
150 }
151 else
152 {
153 valPropMap = msgData.find(POWER_CAP_ENABLE_PROP);
154 if (valPropMap != msgData.end())
155 {
Patrick Williams305ff8b2020-05-13 11:17:39 -0500156 pcapEnabled = std::get<bool>(valPropMap->second);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500157 pcap = getPcap();
158 }
159 else
160 {
161 log<level::INFO>("Unknown power cap property changed");
162 return;
163 }
164 }
165
Gunnar Mills94df8c92018-09-14 14:50:03 -0500166 log<level::INFO>("Power Cap Property Change", entry("PCAP=%u", pcap),
167 entry("PCAP_ENABLED=%u", pcapEnabled));
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500168
169 // Determine desired action to write to occ
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500170
Andrew Geissler4cea4d22017-07-10 15:13:33 -0500171 auto occInput = getOccInput(pcap, pcapEnabled);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500172
173 // Write action to occ
Andrew Geissler6ac874e2017-07-10 15:54:58 -0500174 writeOcc(occInput);
Andrew Geissler52cf26a2017-07-06 12:56:32 -0500175
176 return;
Andrew Geissler32016d12017-06-20 15:46:52 -0500177}
178
Gunnar Mills94df8c92018-09-14 14:50:03 -0500179} // namespace powercap
Andrew Geissler32016d12017-06-20 15:46:52 -0500180
181} // namespace occ
182
Gunnar Mills94df8c92018-09-14 14:50:03 -0500183} // namespace open_power