blob: e2f08379de93441e8bcf9bbd8ba26fafd30aa3b4 [file] [log] [blame]
Chris Cain36f9cde2021-11-22 11:18:21 -06001#include "powermode.hpp"
2
Sheldon Baileyea2b22e2022-04-04 12:24:46 -05003#include <fcntl.h>
Chris Cain78e86012021-03-04 16:15:31 -06004#include <fmt/core.h>
Sheldon Baileyea2b22e2022-04-04 12:24:46 -05005#include <sys/ioctl.h>
Chris Cain78e86012021-03-04 16:15:31 -06006
Chris Cain36f9cde2021-11-22 11:18:21 -06007#include <com/ibm/Host/Target/server.hpp>
Sheldon Baileyea2b22e2022-04-04 12:24:46 -05008#include <org/open_power/OCC/Device/error.hpp>
Ben Tyner3576d652022-05-22 18:05:53 -05009#include <phosphor-logging/elog-errors.hpp>
Chris Cain78e86012021-03-04 16:15:31 -060010#include <phosphor-logging/log.hpp>
Sheldon Baileyea2b22e2022-04-04 12:24:46 -050011#include <xyz/openbmc_project/Common/error.hpp>
Chris Cain78e86012021-03-04 16:15:31 -060012#include <xyz/openbmc_project/Control/Power/Mode/server.hpp>
13
George Liub5ca1012021-09-10 12:53:11 +080014#include <cassert>
Chris Cain36f9cde2021-11-22 11:18:21 -060015#include <fstream>
George Liub5ca1012021-09-10 12:53:11 +080016#include <regex>
17
Chris Cain78e86012021-03-04 16:15:31 -060018namespace open_power
19{
20namespace occ
21{
22namespace powermode
23{
24
25using namespace phosphor::logging;
Chris Cain1be43372021-12-09 19:29:37 -060026using namespace std::literals::string_literals;
Sheldon Baileyea2b22e2022-04-04 12:24:46 -050027using namespace sdbusplus::org::open_power::OCC::Device::Error;
Chris Cain1be43372021-12-09 19:29:37 -060028
Chris Cain78e86012021-03-04 16:15:31 -060029using Mode = sdbusplus::xyz::openbmc_project::Control::Power::server::Mode;
30
Ben Tyner3576d652022-05-22 18:05:53 -050031using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
32using Reason = xyz::openbmc_project::Common::NotAllowed::REASON;
33
Chris Cain6fa848a2022-01-24 14:54:38 -060034// Set the Master OCC
Chris Cain1be43372021-12-09 19:29:37 -060035void PowerMode::setMasterOcc(const std::string& masterOccPath)
Chris Cain6fa848a2022-01-24 14:54:38 -060036{
Chris Cain1be43372021-12-09 19:29:37 -060037 if (masterOccSet)
38 {
39 if (masterOccPath != path)
40 {
41 log<level::ERR>(
42 fmt::format(
43 "PowerMode::setMasterOcc: Master changed (was OCC{}, {})",
44 occInstance, masterOccPath)
45 .c_str());
46 if (occCmd)
47 {
48 occCmd.reset();
49 }
50 }
51 }
52 path = masterOccPath;
Chris Cain6fa848a2022-01-24 14:54:38 -060053 occInstance = path.back() - '0';
54 log<level::DEBUG>(fmt::format("PowerMode::setMasterOcc(OCC{}, {})",
55 occInstance, path.c_str())
56 .c_str());
Chris Cain1be43372021-12-09 19:29:37 -060057 if (!occCmd)
58 {
59 occCmd = std::make_unique<open_power::occ::OccCommand>(occInstance,
60 path.c_str());
61 }
Chris Cain6fa848a2022-01-24 14:54:38 -060062 masterOccSet = true;
63};
64
Chris Cain36f9cde2021-11-22 11:18:21 -060065// Called when DBus power mode gets changed
Chris Cain78e86012021-03-04 16:15:31 -060066void PowerMode::modeChanged(sdbusplus::message::message& msg)
67{
Chris Cain78e86012021-03-04 16:15:31 -060068 std::map<std::string, std::variant<std::string>> properties{};
69 std::string interface;
70 std::string propVal;
71 msg.read(interface, properties);
72 const auto modeEntry = properties.find(POWER_MODE_PROP);
73 if (modeEntry != properties.end())
74 {
75 auto modeEntryValue = modeEntry->second;
76 propVal = std::get<std::string>(modeEntryValue);
Chris Cain6fa848a2022-01-24 14:54:38 -060077 SysPwrMode newMode = convertStringToMode(propVal);
Ben Tyner3576d652022-05-22 18:05:53 -050078
79 // If mode set was requested via direct dbus property change then we
80 // need to see if mode set is locked and ignore the request. We should
81 // not get to this path since the property change method should also be
82 // checking the mode lock status.
83 if (persistedData.getModeLock())
84 {
85 // Fix up the mode property since we are going to ignore this
86 // set mode request.
87 log<level::ERR>(
88 "PowerMode::modeChanged: mode property changed while locked");
89 SysPwrMode currentMode;
90 uint16_t oemModeData;
91 getMode(currentMode, oemModeData);
92 updateDbusMode(currentMode);
93 return;
94 }
95
Chris Cain36f9cde2021-11-22 11:18:21 -060096 if (newMode != SysPwrMode::NO_CHANGE)
Chris Cain78e86012021-03-04 16:15:31 -060097 {
Chris Cain1be43372021-12-09 19:29:37 -060098 // Update persisted data with new mode
99 persistedData.updateMode(newMode, 0);
Chris Cain36f9cde2021-11-22 11:18:21 -0600100
Chris Cain78e86012021-03-04 16:15:31 -0600101 log<level::INFO>(
Chris Cain1be43372021-12-09 19:29:37 -0600102 fmt::format("DBus Power Mode Changed: {}", propVal).c_str());
Chris Cain78e86012021-03-04 16:15:31 -0600103
Chris Cain36f9cde2021-11-22 11:18:21 -0600104 // Send mode change to OCC
105 sendModeChange();
106 }
107 }
108}
109
Ben Tyner3576d652022-05-22 18:05:53 -0500110// Set the state of power mode lock. Writing persistent data via dbus method.
111bool PowerMode::powerModeLock()
112{
113 log<level::INFO>("PowerMode::powerModeLock: locking mode change");
114 persistedData.updateModeLock(true); // write persistent data
115 return true;
116}
117
118// Get the state of power mode. Reading persistent data via dbus method.
119bool PowerMode::powerModeLockStatus()
120{
121 bool status = persistedData.getModeLock(); // read persistent data
122 log<level::INFO>(fmt::format("PowerMode::powerModeLockStatus: {}",
123 status ? "locked" : "unlocked")
124 .c_str());
125 return status;
126}
127
Chris Cain36f9cde2021-11-22 11:18:21 -0600128// Called from OCC PassThrough interface (via CE login / BMC command line)
Chris Cain1be43372021-12-09 19:29:37 -0600129bool PowerMode::setMode(const SysPwrMode newMode, const uint16_t oemModeData)
Chris Cain36f9cde2021-11-22 11:18:21 -0600130{
Ben Tyner3576d652022-05-22 18:05:53 -0500131 if (persistedData.getModeLock())
132 {
133 log<level::INFO>("PowerMode::setMode: mode change blocked");
134 return false;
135 }
136
Chris Cain36f9cde2021-11-22 11:18:21 -0600137 if (updateDbusMode(newMode) == false)
138 {
139 // Unsupported mode
140 return false;
141 }
142
Chris Cain1be43372021-12-09 19:29:37 -0600143 // Save mode
144 persistedData.updateMode(newMode, oemModeData);
Chris Cain36f9cde2021-11-22 11:18:21 -0600145
Chris Cain1be43372021-12-09 19:29:37 -0600146 // Send mode change to OCC
147 if (sendModeChange() != CmdStatus::SUCCESS)
148 {
149 // Mode change failed
150 return false;
Chris Cain78e86012021-03-04 16:15:31 -0600151 }
152
Chris Cain36f9cde2021-11-22 11:18:21 -0600153 return true;
Chris Cain78e86012021-03-04 16:15:31 -0600154}
155
156// Convert PowerMode string to OCC SysPwrMode
Chris Cain36f9cde2021-11-22 11:18:21 -0600157// Returns NO_CHANGE if OEM or unsupported mode
Chris Cain78e86012021-03-04 16:15:31 -0600158SysPwrMode convertStringToMode(const std::string& i_modeString)
159{
160 SysPwrMode pmode = SysPwrMode::NO_CHANGE;
161
162 Mode::PowerMode mode = Mode::convertPowerModeFromString(i_modeString);
163 if (mode == Mode::PowerMode::MaximumPerformance)
164 {
165 pmode = SysPwrMode::MAX_PERF;
166 }
167 else if (mode == Mode::PowerMode::PowerSaving)
168 {
169 pmode = SysPwrMode::POWER_SAVING;
170 }
171 else if (mode == Mode::PowerMode::Static)
172 {
Chris Cain36f9cde2021-11-22 11:18:21 -0600173 pmode = SysPwrMode::STATIC;
Chris Cain78e86012021-03-04 16:15:31 -0600174 }
175 else
176 {
Chris Cain36f9cde2021-11-22 11:18:21 -0600177 if (mode != Mode::PowerMode::OEM)
178 {
179 log<level::ERR>(
180 fmt::format(
181 "convertStringToMode: Invalid Power Mode specified: {}",
182 i_modeString)
183 .c_str());
184 }
Chris Cain78e86012021-03-04 16:15:31 -0600185 }
186
187 return pmode;
188}
189
Chris Cain36f9cde2021-11-22 11:18:21 -0600190// Check if Hypervisor target is PowerVM
191bool isPowerVM()
Chris Cain1d51da22021-09-21 14:13:41 -0500192{
Chris Cain36f9cde2021-11-22 11:18:21 -0600193 namespace Hyper = sdbusplus::com::ibm::Host::server;
194 constexpr auto HYPE_PATH = "/com/ibm/host0/hypervisor";
195 constexpr auto HYPE_INTERFACE = "com.ibm.Host.Target";
196 constexpr auto HYPE_PROP = "Target";
197
198 bool powerVmTarget = false;
199
200 // This will throw exception on failure
201 auto& bus = utils::getBus();
202 auto service = utils::getService(HYPE_PATH, HYPE_INTERFACE);
203 auto method = bus.new_method_call(service.c_str(), HYPE_PATH,
204 "org.freedesktop.DBus.Properties", "Get");
205 method.append(HYPE_INTERFACE, HYPE_PROP);
206 auto reply = bus.call(method);
207
208 std::variant<std::string> hyperEntryValue;
209 reply.read(hyperEntryValue);
210 auto propVal = std::get<std::string>(hyperEntryValue);
211 if (Hyper::Target::convertHypervisorFromString(propVal) ==
212 Hyper::Target::Hypervisor::PowerVM)
213 {
214 powerVmTarget = true;
215 }
216
217 log<level::DEBUG>(
218 fmt::format("isPowerVM returning {}", powerVmTarget).c_str());
219
220 return powerVmTarget;
221}
222
Chris Cain1be43372021-12-09 19:29:37 -0600223// Initialize persistent data and return true if successful
224bool PowerMode::initPersistentData()
Chris Cain36f9cde2021-11-22 11:18:21 -0600225{
Chris Cain1be43372021-12-09 19:29:37 -0600226 if (!persistedData.modeAvailable())
Chris Cain36f9cde2021-11-22 11:18:21 -0600227 {
Chris Cain1be43372021-12-09 19:29:37 -0600228 // Read the default mode
229 SysPwrMode currentMode;
230 if (!getDefaultMode(currentMode))
231 {
232 // Unable to read defaults
233 return false;
234 }
235 log<level::INFO>(
236 fmt::format("PowerMode::initPersistentData: Using default mode: {}",
237 currentMode)
Chris Cain36f9cde2021-11-22 11:18:21 -0600238 .c_str());
Chris Cain1be43372021-12-09 19:29:37 -0600239
240 // Save default mode as current mode
241 persistedData.updateMode(currentMode, 0);
242
243 // Write default mode to DBus
244 updateDbusMode(currentMode);
Chris Cain36f9cde2021-11-22 11:18:21 -0600245 }
246
Chris Cain1be43372021-12-09 19:29:37 -0600247 if (!persistedData.ipsAvailable())
248 {
Chris Caincde7bea2022-01-28 15:54:24 -0600249 // Read the default IPS parameters, write persistent file and update
250 // DBus
251 return useDefaultIPSParms();
Chris Cain1be43372021-12-09 19:29:37 -0600252 }
253 return true;
254}
255
256// Get the requested power mode and return true if successful
257bool PowerMode::getMode(SysPwrMode& currentMode, uint16_t& oemModeData)
258{
259 currentMode = SysPwrMode::NO_CHANGE;
260 oemModeData = 0;
261
262 if (!persistedData.getMode(currentMode, oemModeData))
263 {
264 // Persistent data not initialized, read defaults and update DBus
265 if (!initPersistentData())
266 {
267 // Unable to read defaults from entity manager yet
268 return false;
269 }
270 return persistedData.getMode(currentMode, oemModeData);
271 }
272
273 return true;
Chris Cain36f9cde2021-11-22 11:18:21 -0600274}
275
276// Set the power mode on DBus
277bool PowerMode::updateDbusMode(const SysPwrMode newMode)
278{
Chris Cain36f9cde2021-11-22 11:18:21 -0600279 if (!VALID_POWER_MODE_SETTING(newMode) &&
280 !VALID_OEM_POWER_MODE_SETTING(newMode))
281 {
282 log<level::ERR>(
283 fmt::format(
284 "PowerMode::updateDbusMode - Requested power mode not supported: {}",
285 newMode)
286 .c_str());
287 return false;
288 }
289
Chris Cain1be43372021-12-09 19:29:37 -0600290 // Convert mode for DBus
291 ModeInterface::PowerMode dBusMode;
Chris Cain36f9cde2021-11-22 11:18:21 -0600292 switch (newMode)
293 {
294 case SysPwrMode::STATIC:
Chris Cain1be43372021-12-09 19:29:37 -0600295 dBusMode = Mode::PowerMode::Static;
Chris Cain36f9cde2021-11-22 11:18:21 -0600296 break;
297 case SysPwrMode::POWER_SAVING:
Chris Cain1be43372021-12-09 19:29:37 -0600298 dBusMode = Mode::PowerMode::PowerSaving;
Chris Cain36f9cde2021-11-22 11:18:21 -0600299 break;
300 case SysPwrMode::MAX_PERF:
Chris Cain1be43372021-12-09 19:29:37 -0600301 dBusMode = Mode::PowerMode::MaximumPerformance;
Chris Cain36f9cde2021-11-22 11:18:21 -0600302 break;
303 default:
Chris Cain1be43372021-12-09 19:29:37 -0600304 dBusMode = Mode::PowerMode::OEM;
Chris Cain36f9cde2021-11-22 11:18:21 -0600305 }
306
Chris Cain1be43372021-12-09 19:29:37 -0600307 // true = skip update signal
308 ModeInterface::setPropertyByName(POWER_MODE_PROP, dBusMode, true);
Chris Cain36f9cde2021-11-22 11:18:21 -0600309
310 return true;
311}
312
313// Send mode change request to the master OCC
314CmdStatus PowerMode::sendModeChange()
315{
Chris Cain6fa848a2022-01-24 14:54:38 -0600316 CmdStatus status;
Chris Cain36f9cde2021-11-22 11:18:21 -0600317
Chris Cain6fa848a2022-01-24 14:54:38 -0600318 if (!masterActive || !masterOccSet)
Chris Cain36f9cde2021-11-22 11:18:21 -0600319 {
320 // Nothing to do
Chris Cain6fa848a2022-01-24 14:54:38 -0600321 log<level::DEBUG>("PowerMode::sendModeChange: OCC master not active");
Chris Cain36f9cde2021-11-22 11:18:21 -0600322 return CmdStatus::SUCCESS;
323 }
324
325 if (!isPowerVM())
326 {
327 // Mode change is only supported on PowerVM systems
328 log<level::DEBUG>(
329 "PowerMode::sendModeChange: MODE CHANGE does not get sent on non-PowerVM systems");
330 return CmdStatus::SUCCESS;
331 }
332
Chris Cain1be43372021-12-09 19:29:37 -0600333 SysPwrMode newMode;
334 uint16_t oemModeData = 0;
335 getMode(newMode, oemModeData);
Chris Cain36f9cde2021-11-22 11:18:21 -0600336
337 if (VALID_POWER_MODE_SETTING(newMode) ||
338 VALID_OEM_POWER_MODE_SETTING(newMode))
339 {
340 std::vector<std::uint8_t> cmd, rsp;
341 cmd.reserve(9);
342 cmd.push_back(uint8_t(CmdType::SET_MODE_AND_STATE));
343 cmd.push_back(0x00); // Data Length (2 bytes)
344 cmd.push_back(0x06);
345 cmd.push_back(0x30); // Data (Version)
346 cmd.push_back(uint8_t(OccState::NO_CHANGE));
347 cmd.push_back(uint8_t(newMode));
Chris Cain1be43372021-12-09 19:29:37 -0600348 cmd.push_back(oemModeData >> 8); // Mode Data (Freq Point)
349 cmd.push_back(oemModeData & 0xFF); //
350 cmd.push_back(0x00); // reserved
Chris Cain36f9cde2021-11-22 11:18:21 -0600351 log<level::INFO>(
352 fmt::format(
353 "PowerMode::sendModeChange: SET_MODE({},{}) command to OCC{} ({} bytes)",
Chris Cain1be43372021-12-09 19:29:37 -0600354 newMode, oemModeData, occInstance, cmd.size())
Chris Cain36f9cde2021-11-22 11:18:21 -0600355 .c_str());
Chris Cain6fa848a2022-01-24 14:54:38 -0600356 status = occCmd->send(cmd, rsp);
Chris Cain36f9cde2021-11-22 11:18:21 -0600357 if (status == CmdStatus::SUCCESS)
358 {
359 if (rsp.size() == 5)
360 {
361 if (RspStatus::SUCCESS != RspStatus(rsp[2]))
362 {
363 log<level::ERR>(
364 fmt::format(
365 "PowerMode::sendModeChange: SET MODE failed with status 0x{:02X}",
366 rsp[2])
367 .c_str());
368 dump_hex(rsp);
369 status = CmdStatus::FAILURE;
370 }
371 }
372 else
373 {
374 log<level::ERR>(
375 "PowerMode::sendModeChange: INVALID SET MODE response");
376 dump_hex(rsp);
377 status = CmdStatus::FAILURE;
378 }
379 }
380 else
381 {
Chris Cainc567dc82022-04-01 15:09:17 -0500382 log<level::ERR>(
383 fmt::format(
384 "PowerMode::sendModeChange: SET_MODE FAILED with status={}",
385 status)
386 .c_str());
Chris Cain36f9cde2021-11-22 11:18:21 -0600387 }
388 }
389 else
390 {
391 log<level::ERR>(
392 fmt::format(
393 "PowerMode::sendModeChange: Unable to set power mode to {}",
394 newMode)
395 .c_str());
396 status = CmdStatus::FAILURE;
397 }
398
399 return status;
400}
401
402void PowerMode::ipsChanged(sdbusplus::message::message& msg)
403{
Chris Cain1d51da22021-09-21 14:13:41 -0500404 bool parmsChanged = false;
405 std::string interface;
406 std::map<std::string, std::variant<bool, uint8_t, uint64_t>>
407 ipsProperties{};
408 msg.read(interface, ipsProperties);
409
Chris Cain1be43372021-12-09 19:29:37 -0600410 // Read persisted values
411 bool ipsEnabled;
412 uint8_t enterUtil, exitUtil;
413 uint16_t enterTime, exitTime;
414 getIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime);
415
416 // Check for any changed data
Chris Cain1d51da22021-09-21 14:13:41 -0500417 auto ipsEntry = ipsProperties.find(IPS_ENABLED_PROP);
418 if (ipsEntry != ipsProperties.end())
419 {
Chris Cain1be43372021-12-09 19:29:37 -0600420 ipsEnabled = std::get<bool>(ipsEntry->second);
Chris Cain1d51da22021-09-21 14:13:41 -0500421 log<level::INFO>(
422 fmt::format("Idle Power Saver change: Enabled={}", ipsEnabled)
423 .c_str());
424 parmsChanged = true;
425 }
426 ipsEntry = ipsProperties.find(IPS_ENTER_UTIL);
427 if (ipsEntry != ipsProperties.end())
428 {
Chris Cain1be43372021-12-09 19:29:37 -0600429 enterUtil = std::get<uint8_t>(ipsEntry->second);
Chris Cain1d51da22021-09-21 14:13:41 -0500430 log<level::INFO>(
431 fmt::format("Idle Power Saver change: Enter Util={}%", enterUtil)
432 .c_str());
433 parmsChanged = true;
434 }
435 ipsEntry = ipsProperties.find(IPS_ENTER_TIME);
436 if (ipsEntry != ipsProperties.end())
437 {
438 std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second));
Chris Cain1be43372021-12-09 19:29:37 -0600439 enterTime =
Chris Cain1d51da22021-09-21 14:13:41 -0500440 std::chrono::duration_cast<std::chrono::seconds>(ms).count();
441 log<level::INFO>(
442 fmt::format("Idle Power Saver change: Enter Time={}sec", enterTime)
443 .c_str());
444 parmsChanged = true;
445 }
446 ipsEntry = ipsProperties.find(IPS_EXIT_UTIL);
447 if (ipsEntry != ipsProperties.end())
448 {
Chris Cain1be43372021-12-09 19:29:37 -0600449 exitUtil = std::get<uint8_t>(ipsEntry->second);
Chris Cain1d51da22021-09-21 14:13:41 -0500450 log<level::INFO>(
451 fmt::format("Idle Power Saver change: Exit Util={}%", exitUtil)
452 .c_str());
453 parmsChanged = true;
454 }
455 ipsEntry = ipsProperties.find(IPS_EXIT_TIME);
456 if (ipsEntry != ipsProperties.end())
457 {
458 std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second));
Chris Cain1be43372021-12-09 19:29:37 -0600459 exitTime = std::chrono::duration_cast<std::chrono::seconds>(ms).count();
Chris Cain1d51da22021-09-21 14:13:41 -0500460 log<level::INFO>(
461 fmt::format("Idle Power Saver change: Exit Time={}sec", exitTime)
462 .c_str());
463 parmsChanged = true;
464 }
465
466 if (parmsChanged)
467 {
Chris Caincde7bea2022-01-28 15:54:24 -0600468 if (exitUtil == 0)
469 {
470 // Setting the exitUtil to 0 will force restoring the default IPS
471 // parmeters (0 is not valid exit utilization)
472 log<level::INFO>(
473 "Idle Power Saver Exit Utilization is 0%. Restoring default parameters");
474 // Read the default IPS parameters, write persistent file and update
475 // DBus
476 useDefaultIPSParms();
477 }
478 else
479 {
480 // Update persistant data with new DBus values
481 persistedData.updateIPS(ipsEnabled, enterUtil, enterTime, exitUtil,
482 exitTime);
483 }
Chris Cain1be43372021-12-09 19:29:37 -0600484
485 // Trigger IPS data to get sent to the OCC
Chris Cain36f9cde2021-11-22 11:18:21 -0600486 sendIpsData();
Chris Cain1d51da22021-09-21 14:13:41 -0500487 }
488
489 return;
490}
491
Chris Cain1be43372021-12-09 19:29:37 -0600492/** @brief Get the Idle Power Saver properties from persisted data
493 * @return true if IPS parameters were read
Chris Cain36f9cde2021-11-22 11:18:21 -0600494 */
Chris Cain1be43372021-12-09 19:29:37 -0600495bool PowerMode::getIPSParms(bool& ipsEnabled, uint8_t& enterUtil,
496 uint16_t& enterTime, uint8_t& exitUtil,
497 uint16_t& exitTime)
Chris Cain36f9cde2021-11-22 11:18:21 -0600498{
Chris Cain36f9cde2021-11-22 11:18:21 -0600499 // Defaults:
Chris Cain1be43372021-12-09 19:29:37 -0600500 ipsEnabled = true; // Enabled
501 enterUtil = 8; // Enter Utilization (8%)
502 enterTime = 240; // Enter Delay Time (240s)
503 exitUtil = 12; // Exit Utilization (12%)
504 exitTime = 10; // Exit Delay Time (10s)
Chris Cain36f9cde2021-11-22 11:18:21 -0600505
Chris Cain1be43372021-12-09 19:29:37 -0600506 if (!persistedData.getIPS(ipsEnabled, enterUtil, enterTime, exitUtil,
507 exitTime))
508 {
509 // Persistent data not initialized, read defaults and update DBus
510 if (!initPersistentData())
511 {
512 // Unable to read defaults from entity manager yet
513 return false;
514 }
Chris Cain36f9cde2021-11-22 11:18:21 -0600515
Chris Cain1be43372021-12-09 19:29:37 -0600516 persistedData.getIPS(ipsEnabled, enterUtil, enterTime, exitUtil,
517 exitTime);
Chris Cain36f9cde2021-11-22 11:18:21 -0600518 }
519
520 if (enterUtil > exitUtil)
521 {
522 log<level::ERR>(
523 fmt::format(
524 "ERROR: Idle Power Saver Enter Utilization ({}%) is > Exit Utilization ({}%) - using Exit for both",
525 enterUtil, exitUtil)
526 .c_str());
527 enterUtil = exitUtil;
528 }
529
Chris Cain1be43372021-12-09 19:29:37 -0600530 return true;
531}
532
533// Set the Idle Power Saver data on DBus
534bool PowerMode::updateDbusIPS(const bool enabled, const uint8_t enterUtil,
535 const uint16_t enterTime, const uint8_t exitUtil,
536 const uint16_t exitTime)
537{
538 // true = skip update signal
539 IpsInterface::setPropertyByName(IPS_ENABLED_PROP, enabled, true);
540 IpsInterface::setPropertyByName(IPS_ENTER_UTIL, enterUtil, true);
541 // Convert time from seconds to ms
542 uint64_t msTime = enterTime * 1000;
543 IpsInterface::setPropertyByName(IPS_ENTER_TIME, msTime, true);
544 IpsInterface::setPropertyByName(IPS_EXIT_UTIL, exitUtil, true);
545 msTime = exitTime * 1000;
546 IpsInterface::setPropertyByName(IPS_EXIT_TIME, msTime, true);
547
548 return true;
Chris Cain36f9cde2021-11-22 11:18:21 -0600549}
550
551// Send Idle Power Saver config data to the master OCC
552CmdStatus PowerMode::sendIpsData()
553{
Chris Cain6fa848a2022-01-24 14:54:38 -0600554 if (!masterActive || !masterOccSet)
Chris Cain36f9cde2021-11-22 11:18:21 -0600555 {
556 // Nothing to do
557 return CmdStatus::SUCCESS;
558 }
559
560 if (!isPowerVM())
561 {
562 // Idle Power Saver data is only supported on PowerVM systems
563 log<level::DEBUG>(
564 "PowerMode::sendIpsData: SET_CFG_DATA[IPS] does not get sent on non-PowerVM systems");
565 return CmdStatus::SUCCESS;
566 }
567
Chris Cain1be43372021-12-09 19:29:37 -0600568 bool ipsEnabled;
Chris Cain36f9cde2021-11-22 11:18:21 -0600569 uint8_t enterUtil, exitUtil;
570 uint16_t enterTime, exitTime;
Chris Cain1be43372021-12-09 19:29:37 -0600571 getIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime);
Chris Cain36f9cde2021-11-22 11:18:21 -0600572
573 log<level::INFO>(
574 fmt::format(
575 "Idle Power Saver Parameters: enabled:{}, enter:{}%/{}s, exit:{}%/{}s",
576 ipsEnabled, enterUtil, enterTime, exitUtil, exitTime)
577 .c_str());
578
579 std::vector<std::uint8_t> cmd, rsp;
580 cmd.reserve(12);
581 cmd.push_back(uint8_t(CmdType::SET_CONFIG_DATA));
582 cmd.push_back(0x00); // Data Length (2 bytes)
583 cmd.push_back(0x09); //
584 cmd.push_back(0x11); // Config Format: IPS Settings
585 cmd.push_back(0x00); // Version
586 cmd.push_back(ipsEnabled ? 1 : 0); // IPS Enable
587 cmd.push_back(enterTime >> 8); // Enter Delay Time
588 cmd.push_back(enterTime & 0xFF); //
589 cmd.push_back(enterUtil); // Enter Utilization
590 cmd.push_back(exitTime >> 8); // Exit Delay Time
591 cmd.push_back(exitTime & 0xFF); //
592 cmd.push_back(exitUtil); // Exit Utilization
593 log<level::INFO>(fmt::format("PowerMode::sendIpsData: SET_CFG_DATA[IPS] "
594 "command to OCC{} ({} bytes)",
595 occInstance, cmd.size())
596 .c_str());
Chris Cain1be43372021-12-09 19:29:37 -0600597 CmdStatus status = occCmd->send(cmd, rsp);
Chris Cain36f9cde2021-11-22 11:18:21 -0600598 if (status == CmdStatus::SUCCESS)
599 {
600 if (rsp.size() == 5)
601 {
602 if (RspStatus::SUCCESS != RspStatus(rsp[2]))
603 {
604 log<level::ERR>(
605 fmt::format(
606 "PowerMode::sendIpsData: SET_CFG_DATA[IPS] failed with status 0x{:02X}",
607 rsp[2])
608 .c_str());
609 dump_hex(rsp);
610 status = CmdStatus::FAILURE;
611 }
612 }
613 else
614 {
615 log<level::ERR>(
616 "PowerMode::sendIpsData: INVALID SET_CFG_DATA[IPS] response");
617 dump_hex(rsp);
618 status = CmdStatus::FAILURE;
619 }
620 }
621 else
622 {
Chris Cainc567dc82022-04-01 15:09:17 -0500623 log<level::ERR>(
624 fmt::format(
625 "PowerMode::sendIpsData: SET_CFG_DATA[IPS] with status={}",
626 status)
627 .c_str());
Chris Cain36f9cde2021-11-22 11:18:21 -0600628 }
629
630 return status;
631}
632
Chris Caincde7bea2022-01-28 15:54:24 -0600633// Print the current values
Chris Cain1be43372021-12-09 19:29:37 -0600634void OccPersistData::print()
Chris Cain36f9cde2021-11-22 11:18:21 -0600635{
Chris Cain1be43372021-12-09 19:29:37 -0600636 if (modeData.modeInitialized)
637 {
638 log<level::INFO>(
639 fmt::format(
Ben Tyner3576d652022-05-22 18:05:53 -0500640 "OccPersistData: Mode: 0x{:02X}, OEM Mode Data: {} (0x{:04X} Locked{})",
641 modeData.mode, modeData.oemModeData, modeData.oemModeData,
642 modeData.modeLocked)
Chris Cain1be43372021-12-09 19:29:37 -0600643 .c_str());
644 }
645 if (modeData.ipsInitialized)
646 {
647 log<level::INFO>(
648 fmt::format(
649 "OccPersistData: IPS enabled:{}, enter:{}%/{}s, exit:{}%/{}s",
650 modeData.ipsEnabled, modeData.ipsEnterUtil,
651 modeData.ipsEnterTime, modeData.ipsExitUtil,
652 modeData.ipsExitTime)
653 .c_str());
654 }
Chris Cain36f9cde2021-11-22 11:18:21 -0600655}
656
657// Saves the OEM mode data in the filesystem using cereal.
658void OccPersistData::save()
659{
660 std::filesystem::path opath =
Chris Cain1be43372021-12-09 19:29:37 -0600661 std::filesystem::path{OCC_CONTROL_PERSIST_PATH} / powerModeFilename;
Chris Cain36f9cde2021-11-22 11:18:21 -0600662
663 if (!std::filesystem::exists(opath.parent_path()))
664 {
665 std::filesystem::create_directory(opath.parent_path());
666 }
667
668 log<level::DEBUG>(
Chris Cain1be43372021-12-09 19:29:37 -0600669 fmt::format(
670 "OccPersistData::save: Writing Power Mode persisted data to {}",
671 opath.c_str())
Chris Cain36f9cde2021-11-22 11:18:21 -0600672 .c_str());
Chris Caincde7bea2022-01-28 15:54:24 -0600673 // print();
Chris Cain36f9cde2021-11-22 11:18:21 -0600674
675 std::ofstream stream{opath.c_str()};
676 cereal::JSONOutputArchive oarchive{stream};
677
Chris Cain1be43372021-12-09 19:29:37 -0600678 oarchive(modeData);
Chris Cain36f9cde2021-11-22 11:18:21 -0600679}
680
681// Loads the OEM mode data in the filesystem using cereal.
682void OccPersistData::load()
683{
684
685 std::filesystem::path ipath =
Chris Cain1be43372021-12-09 19:29:37 -0600686 std::filesystem::path{OCC_CONTROL_PERSIST_PATH} / powerModeFilename;
Chris Cain36f9cde2021-11-22 11:18:21 -0600687
688 if (!std::filesystem::exists(ipath))
689 {
Chris Cain1be43372021-12-09 19:29:37 -0600690 modeData.modeInitialized = false;
691 modeData.ipsInitialized = false;
Chris Cain36f9cde2021-11-22 11:18:21 -0600692 return;
693 }
694
695 log<level::DEBUG>(
Chris Cain1be43372021-12-09 19:29:37 -0600696 fmt::format(
697 "OccPersistData::load: Reading Power Mode persisted data from {}",
698 ipath.c_str())
Chris Cain36f9cde2021-11-22 11:18:21 -0600699 .c_str());
700 try
701 {
702 std::ifstream stream{ipath.c_str()};
703 cereal::JSONInputArchive iarchive(stream);
Chris Cain1be43372021-12-09 19:29:37 -0600704 iarchive(modeData);
Chris Cain36f9cde2021-11-22 11:18:21 -0600705 }
706 catch (const std::exception& e)
707 {
708 auto error = errno;
709 log<level::ERR>(
710 fmt::format("OccPersistData::load: failed to read {}, errno={}",
711 ipath.c_str(), error)
712 .c_str());
Chris Cain1be43372021-12-09 19:29:37 -0600713 modeData.modeInitialized = false;
714 modeData.ipsInitialized = false;
Chris Cain36f9cde2021-11-22 11:18:21 -0600715 }
716
Chris Caincde7bea2022-01-28 15:54:24 -0600717 // print();
Chris Cain36f9cde2021-11-22 11:18:21 -0600718}
719
Chris Cain1be43372021-12-09 19:29:37 -0600720// Called when PowerModeProperties defaults are available on DBus
721void PowerMode::defaultsReady(sdbusplus::message::message& msg)
Chris Cain36f9cde2021-11-22 11:18:21 -0600722{
Chris Cain1be43372021-12-09 19:29:37 -0600723 std::map<std::string, std::variant<std::string>> properties{};
724 std::string interface;
725 msg.read(interface, properties);
Chris Cain36f9cde2021-11-22 11:18:21 -0600726
Chris Cain1be43372021-12-09 19:29:37 -0600727 // If persistent data exists, then don't need to read defaults
728 if ((!persistedData.modeAvailable()) || (!persistedData.ipsAvailable()))
Chris Cain36f9cde2021-11-22 11:18:21 -0600729 {
Chris Cain1be43372021-12-09 19:29:37 -0600730 log<level::INFO>(
731 fmt::format(
732 "Default PowerModeProperties are now available (persistent modeAvail={}, ipsAvail={})",
733 persistedData.modeAvailable() ? 'y' : 'n',
734 persistedData.modeAvailable() ? 'y' : 'n')
735 .c_str());
736
737 // Read default power mode defaults and update DBus
738 initPersistentData();
739 }
740}
741
742// Get the default power mode from DBus and return true if success
743bool PowerMode::getDefaultMode(SysPwrMode& defaultMode)
744{
745 try
746 {
747 auto& bus = utils::getBus();
748 std::string path = "/";
749 std::string service =
750 utils::getServiceUsingSubTree(PMODE_DEFAULT_INTERFACE, path);
751 auto method =
752 bus.new_method_call(service.c_str(), path.c_str(),
753 "org.freedesktop.DBus.Properties", "Get");
754 method.append(PMODE_DEFAULT_INTERFACE, "PowerMode");
755 auto reply = bus.call(method);
756
757 std::variant<std::string> stateEntryValue;
758 reply.read(stateEntryValue);
759 auto propVal = std::get<std::string>(stateEntryValue);
760
761 const std::string fullModeString =
762 PMODE_INTERFACE + ".PowerMode."s + propVal;
763 defaultMode = powermode::convertStringToMode(fullModeString);
764 if (!VALID_POWER_MODE_SETTING(defaultMode))
765 {
766 log<level::ERR>(
767 fmt::format(
768 "PowerMode::getDefaultMode: Invalid default power mode found: {}",
769 defaultMode)
770 .c_str());
771 // If default was read but not valid, use Max Performance
772 defaultMode = SysPwrMode::MAX_PERF;
773 return true;
774 }
775 }
776 catch (const sdbusplus::exception::exception& e)
777 {
778 log<level::ERR>(
779 fmt::format("Unable to read Default Power Mode: {}", e.what())
780 .c_str());
781 return false;
Chris Cain36f9cde2021-11-22 11:18:21 -0600782 }
783
Chris Cain1be43372021-12-09 19:29:37 -0600784 return true;
785}
Chris Cain36f9cde2021-11-22 11:18:21 -0600786
Chris Cain1be43372021-12-09 19:29:37 -0600787/* Get the default Idle Power Saver properties and return true if successful */
788bool PowerMode::getDefaultIPSParms(bool& ipsEnabled, uint8_t& enterUtil,
789 uint16_t& enterTime, uint8_t& exitUtil,
790 uint16_t& exitTime)
791{
792 // Defaults:
793 ipsEnabled = true; // Enabled
794 enterUtil = 8; // Enter Utilization (8%)
795 enterTime = 240; // Enter Delay Time (240s)
796 exitUtil = 12; // Exit Utilization (12%)
797 exitTime = 10; // Exit Delay Time (10s)
798
799 std::map<std::string, std::variant<bool, uint8_t, uint16_t, uint64_t>>
800 ipsProperties{};
801
802 // Get all IPS properties from DBus
803 try
804 {
805 auto& bus = utils::getBus();
806 std::string path = "/";
807 std::string service =
808 utils::getServiceUsingSubTree(PMODE_DEFAULT_INTERFACE, path);
809 auto method =
810 bus.new_method_call(service.c_str(), path.c_str(),
811 "org.freedesktop.DBus.Properties", "GetAll");
812 method.append(PMODE_DEFAULT_INTERFACE);
813 auto reply = bus.call(method);
814 reply.read(ipsProperties);
815 }
816 catch (const sdbusplus::exception::exception& e)
817 {
818 log<level::ERR>(
819 fmt::format(
820 "Unable to read Default Idle Power Saver parameters so it will be disabled: {}",
821 e.what())
822 .c_str());
823 return false;
824 }
825
826 auto ipsEntry = ipsProperties.find("IdlePowerSaverEnabled");
827 if (ipsEntry != ipsProperties.end())
828 {
829 ipsEnabled = std::get<bool>(ipsEntry->second);
830 }
831 else
832 {
833 log<level::ERR>(
834 "PowerMode::getDefaultIPSParms could not find property: IdlePowerSaverEnabled");
835 }
836
837 ipsEntry = ipsProperties.find("EnterUtilizationPercent");
838 if (ipsEntry != ipsProperties.end())
839 {
840 enterUtil = std::get<uint64_t>(ipsEntry->second);
841 }
842 else
843 {
844 log<level::ERR>(
845 "PowerMode::getDefaultIPSParms could not find property: EnterUtilizationPercent");
846 }
847
848 ipsEntry = ipsProperties.find("EnterUtilizationDwellTime");
849 if (ipsEntry != ipsProperties.end())
850 {
851 enterTime = std::get<uint64_t>(ipsEntry->second);
852 }
853 else
854 {
855 log<level::ERR>(
856 "PowerMode::getDefaultIPSParms could not find property: EnterUtilizationDwellTime");
857 }
858
859 ipsEntry = ipsProperties.find("ExitUtilizationPercent");
860 if (ipsEntry != ipsProperties.end())
861 {
862 exitUtil = std::get<uint64_t>(ipsEntry->second);
863 }
864 else
865 {
866 log<level::ERR>(
867 "PowerMode::getDefaultIPSParms could not find property: ExitUtilizationPercent");
868 }
869
870 ipsEntry = ipsProperties.find("ExitUtilizationDwellTime");
871 if (ipsEntry != ipsProperties.end())
872 {
873 exitTime = std::get<uint64_t>(ipsEntry->second);
874 }
875 else
876 {
877 log<level::ERR>(
878 "PowerMode::getDefaultIPSParms could not find property: ExitUtilizationDwellTime");
879 }
880
881 if (enterUtil > exitUtil)
882 {
883 log<level::ERR>(
884 fmt::format(
885 "ERROR: Default Idle Power Saver Enter Utilization ({}%) is > Exit Utilization ({}%) - using Exit for both",
886 enterUtil, exitUtil)
887 .c_str());
888 enterUtil = exitUtil;
889 }
890
891 return true;
Chris Cain36f9cde2021-11-22 11:18:21 -0600892}
893
Chris Caincde7bea2022-01-28 15:54:24 -0600894/* Read default IPS parameters, save them to the persistent file and update
895 DBus. Return true if successful */
896bool PowerMode::useDefaultIPSParms()
897{
898 // Read the default IPS parameters
899 bool ipsEnabled;
900 uint8_t enterUtil, exitUtil;
901 uint16_t enterTime, exitTime;
902 if (!getDefaultIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil,
903 exitTime))
904 {
905 // Unable to read defaults
906 return false;
907 }
908 log<level::INFO>(
909 fmt::format(
910 "PowerMode::useDefaultIPSParms: Using default IPS parms: Enabled: {}, EnterUtil: {}%, EnterTime: {}s, ExitUtil: {}%, ExitTime: {}s",
911 ipsEnabled, enterUtil, enterTime, exitUtil, exitTime)
912 .c_str());
913
914 // Save IPS parms to the persistent file
915 persistedData.updateIPS(ipsEnabled, enterUtil, enterTime, exitUtil,
916 exitTime);
917
918 // Write IPS parms to DBus
919 return updateDbusIPS(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime);
920}
921
Sheldon Baileyea2b22e2022-04-04 12:24:46 -0500922#ifdef POWER10
923
924// Starts to watch for IPS active state changes.
925bool PowerMode::openIpsFile()
926{
927 bool rc = true;
928 fd = open(ipsStatusFile.c_str(), O_RDONLY | O_NONBLOCK);
929 const int open_errno = errno;
930 if (fd < 0)
931 {
932 log<level::ERR>(fmt::format("openIpsFile Error({})={} : File={}",
933 open_errno, strerror(open_errno),
934 ipsStatusFile.c_str())
935 .c_str());
936
937 close(fd);
938
939 using namespace sdbusplus::org::open_power::OCC::Device::Error;
940 report<OpenFailure>(
941 phosphor::logging::org::open_power::OCC::Device::OpenFailure::
942 CALLOUT_ERRNO(open_errno),
943 phosphor::logging::org::open_power::OCC::Device::OpenFailure::
944 CALLOUT_DEVICE_PATH(ipsStatusFile.c_str()));
945
946 // We are no longer watching the error
947 active(false);
948
949 watching = false;
950 rc = false;
951 // NOTE: this will leave the system not reporting IPS active state to
952 // Fan Controls, Until an APP reload, or IPL and we will attempt again.
953 }
954 return rc;
955}
956
957// Starts to watch for IPS active state changes.
958void PowerMode::addIpsWatch(bool poll)
959{
960 // open file and register callback on file if we are not currently watching,
961 // and if poll=true, and if we are the master.
962 if ((!watching) && poll)
963 {
964 // Open the file
965 if (openIpsFile())
966 {
967 // register the callback handler which sets 'watching'
968 registerIpsStatusCallBack();
969 }
970 }
971}
972
973// Stops watching for IPS active state changes.
974void PowerMode::removeIpsWatch()
975{
976 // NOTE: we want to remove event, close file, and IPS active false no
977 // matter what the 'watching' flags is set to.
978
979 // We are no longer watching the error
980 active(false);
981
982 watching = false;
983
984 // Close file
985 close(fd);
986
987 // clears sourcePtr in the event source.
988 eventSource.reset();
989}
990
991// Attaches the FD to event loop and registers the callback handler
992void PowerMode::registerIpsStatusCallBack()
993{
994 decltype(eventSource.get()) sourcePtr = nullptr;
995
996 auto r = sd_event_add_io(event.get(), &sourcePtr, fd, EPOLLPRI | EPOLLERR,
997 ipsStatusCallBack, this);
998 if (r < 0)
999 {
1000 log<level::ERR>(fmt::format("sd_event_add_io: Error({})={} : File={}",
1001 r, strerror(-r), ipsStatusFile.c_str())
1002 .c_str());
1003
1004 using InternalFailure =
1005 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
1006 report<InternalFailure>();
1007
1008 removeIpsWatch();
1009 // NOTE: this will leave the system not reporting IPS active state to
1010 // Fan Controls, Until an APP reload, or IPL and we will attempt again.
1011 }
1012 else
1013 {
1014 // puts sourcePtr in the event source.
1015 eventSource.reset(sourcePtr);
1016 // Set we are watching the error
1017 watching = true;
1018 }
1019}
1020
1021// Static function to redirect to non static analyze event function to be
1022// able to read file and push onto dBus.
1023int PowerMode::ipsStatusCallBack(sd_event_source* /*es*/, int /*fd*/,
1024 uint32_t /*revents*/, void* userData)
1025{
1026 auto pmode = static_cast<PowerMode*>(userData);
1027 pmode->analyzeIpsEvent();
1028 return 0;
1029}
1030
1031// Function to Read SysFs file change on IPS state and push on dBus.
1032void PowerMode::analyzeIpsEvent()
1033{
1034 // Need to seek to START, else the poll returns immediately telling
1035 // there is data to be read. if not done this floods the system.
1036 auto r = lseek(fd, 0, SEEK_SET);
1037 const int open_errno = errno;
1038 if (r < 0)
1039 {
1040 // NOTE: upon file access error we can not just re-open file, we have to
1041 // remove and add to watch.
1042 removeIpsWatch();
1043 addIpsWatch(true);
1044 }
1045
1046 // if we are 'watching' that is the file seek, or the re-open passed.. we
1047 // can read the data
1048 if (watching)
1049 {
1050 // This file gets created when polling OCCs. A value or length of 0 is
1051 // deemed success. That means we would disable IPS active on dbus.
1052 char data;
1053 bool ipsState = false;
1054 const auto len = read(fd, &data, sizeof(data));
1055 const int readErrno = errno;
1056 if (len <= 0)
1057 {
1058 removeIpsWatch();
1059
1060 log<level::ERR>(
1061 fmt::format("IPS state Read Error({})={} : File={} : len={}",
1062 readErrno, strerror(readErrno),
1063 ipsStatusFile.c_str(), len)
1064 .c_str());
1065
1066 report<ReadFailure>(
1067 phosphor::logging::org::open_power::OCC::Device::ReadFailure::
1068 CALLOUT_ERRNO(readErrno),
1069 phosphor::logging::org::open_power::OCC::Device::ReadFailure::
1070 CALLOUT_DEVICE_PATH(ipsStatusFile.c_str()));
1071
1072 // NOTE: this will leave the system not reporting IPS active state
1073 // to Fan Controls, Until an APP reload, or IPL and we will attempt
1074 // again.
1075 }
1076 else
1077 {
1078 // Data returned in ASCII.
1079 // convert to integer. atoi()
1080 // from OCC_P10_FW_Interfaces spec
1081 // Bit 6: IPS active 1 indicates enabled.
1082 // Bit 7: IPS enabled. 1 indicates enabled.
1083 // mask off bit 6 --> & 0x02
1084 // Shift left one bit and store as bool. >> 1
1085 ipsState = static_cast<bool>(((atoi(&data)) & 0x2) >> 1);
1086 }
1087
1088 // This will only set IPS active dbus if different than current.
1089 active(ipsState);
1090 }
1091 else
1092 {
1093 removeIpsWatch();
1094
1095 // If the Retry did not get to "watching = true" we already have an
1096 // error log, just post trace.
1097 log<level::ERR>(fmt::format("Retry on File seek Error({})={} : File={}",
1098 open_errno, strerror(open_errno),
1099 ipsStatusFile.c_str())
1100 .c_str());
1101
1102 // NOTE: this will leave the system not reporting IPS active state to
1103 // Fan Controls, Until an APP reload, or IPL and we will attempt again.
1104 }
1105
1106 return;
1107}
Ben Tyner3576d652022-05-22 18:05:53 -05001108
1109// overrides read/write to powerMode dbus property.
1110Mode::PowerMode PowerMode::powerMode(Mode::PowerMode value)
1111{
1112 if (persistedData.getModeLock())
1113 {
1114 log<level::INFO>("PowerMode::powerMode: mode property change blocked");
1115 elog<NotAllowed>(xyz::openbmc_project::Common::NotAllowed::REASON(
1116 "mode change not allowed due to lock"));
1117 return value;
1118 }
1119 else
1120 {
1121 return Mode::powerMode(value);
1122 }
1123}
Sheldon Baileyea2b22e2022-04-04 12:24:46 -05001124#endif
1125
Sheldon Bailey31a2f132022-05-20 11:31:52 -05001126/* Set dbus property to SAFE mode(true) or clear(false) only if different */
1127void PowerMode::updateDbusSafeMode(const bool safeModeReq)
1128{
1129 log<level::DEBUG>(
1130 fmt::format("PowerMode:updateDbusSafeMode: Update dbus state ({})",
1131 safeModeReq)
1132 .c_str());
1133
1134 // Note; this function checks and only updates if different.
1135 Mode::safeMode(safeModeReq);
1136}
1137
Chris Cain78e86012021-03-04 16:15:31 -06001138} // namespace powermode
1139
1140} // namespace occ
1141
1142} // namespace open_power