blob: e367afc119e3a0da71fc34feec51a5d49732ef30 [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 Cain52cce032023-02-09 15:38:31 -06007#ifdef POWERVM_CHECK
Chris Cain36f9cde2021-11-22 11:18:21 -06008#include <com/ibm/Host/Target/server.hpp>
Chris Cain52cce032023-02-09 15:38:31 -06009#endif
Sheldon Baileyea2b22e2022-04-04 12:24:46 -050010#include <org/open_power/OCC/Device/error.hpp>
Ben Tyner3576d652022-05-22 18:05:53 -050011#include <phosphor-logging/elog-errors.hpp>
Chris Cain78e86012021-03-04 16:15:31 -060012#include <phosphor-logging/log.hpp>
Sheldon Baileyea2b22e2022-04-04 12:24:46 -050013#include <xyz/openbmc_project/Common/error.hpp>
Chris Cain78e86012021-03-04 16:15:31 -060014#include <xyz/openbmc_project/Control/Power/Mode/server.hpp>
15
George Liub5ca1012021-09-10 12:53:11 +080016#include <cassert>
Chris Cain36f9cde2021-11-22 11:18:21 -060017#include <fstream>
George Liub5ca1012021-09-10 12:53:11 +080018#include <regex>
19
Chris Cain78e86012021-03-04 16:15:31 -060020namespace open_power
21{
22namespace occ
23{
24namespace powermode
25{
26
27using namespace phosphor::logging;
Chris Cain1be43372021-12-09 19:29:37 -060028using namespace std::literals::string_literals;
Sheldon Baileyea2b22e2022-04-04 12:24:46 -050029using namespace sdbusplus::org::open_power::OCC::Device::Error;
Chris Cain1be43372021-12-09 19:29:37 -060030
Chris Cain78e86012021-03-04 16:15:31 -060031using Mode = sdbusplus::xyz::openbmc_project::Control::Power::server::Mode;
32
Ben Tyner3576d652022-05-22 18:05:53 -050033using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
34using Reason = xyz::openbmc_project::Common::NotAllowed::REASON;
35
Chris Cain6fa848a2022-01-24 14:54:38 -060036// Set the Master OCC
Chris Cain1be43372021-12-09 19:29:37 -060037void PowerMode::setMasterOcc(const std::string& masterOccPath)
Chris Cain6fa848a2022-01-24 14:54:38 -060038{
Chris Cain1be43372021-12-09 19:29:37 -060039 if (masterOccSet)
40 {
41 if (masterOccPath != path)
42 {
43 log<level::ERR>(
44 fmt::format(
45 "PowerMode::setMasterOcc: Master changed (was OCC{}, {})",
46 occInstance, masterOccPath)
47 .c_str());
48 if (occCmd)
49 {
50 occCmd.reset();
51 }
52 }
53 }
54 path = masterOccPath;
Chris Cain6fa848a2022-01-24 14:54:38 -060055 occInstance = path.back() - '0';
56 log<level::DEBUG>(fmt::format("PowerMode::setMasterOcc(OCC{}, {})",
57 occInstance, path.c_str())
58 .c_str());
Chris Cain1be43372021-12-09 19:29:37 -060059 if (!occCmd)
60 {
61 occCmd = std::make_unique<open_power::occ::OccCommand>(occInstance,
62 path.c_str());
63 }
Chris Cain6fa848a2022-01-24 14:54:38 -060064 masterOccSet = true;
65};
66
Chris Cain36f9cde2021-11-22 11:18:21 -060067// Called when DBus power mode gets changed
Patrick Williamsaf408082022-07-22 19:26:54 -050068void PowerMode::modeChanged(sdbusplus::message_t& msg)
Chris Cain78e86012021-03-04 16:15:31 -060069{
Chris Cain78e86012021-03-04 16:15:31 -060070 std::map<std::string, std::variant<std::string>> properties{};
71 std::string interface;
72 std::string propVal;
73 msg.read(interface, properties);
74 const auto modeEntry = properties.find(POWER_MODE_PROP);
75 if (modeEntry != properties.end())
76 {
77 auto modeEntryValue = modeEntry->second;
78 propVal = std::get<std::string>(modeEntryValue);
Chris Cain6fa848a2022-01-24 14:54:38 -060079 SysPwrMode newMode = convertStringToMode(propVal);
Ben Tyner3576d652022-05-22 18:05:53 -050080
81 // If mode set was requested via direct dbus property change then we
82 // need to see if mode set is locked and ignore the request. We should
83 // not get to this path since the property change method should also be
84 // checking the mode lock status.
85 if (persistedData.getModeLock())
86 {
87 // Fix up the mode property since we are going to ignore this
88 // set mode request.
89 log<level::ERR>(
90 "PowerMode::modeChanged: mode property changed while locked");
91 SysPwrMode currentMode;
92 uint16_t oemModeData;
93 getMode(currentMode, oemModeData);
94 updateDbusMode(currentMode);
95 return;
96 }
97
Chris Cain36f9cde2021-11-22 11:18:21 -060098 if (newMode != SysPwrMode::NO_CHANGE)
Chris Cain78e86012021-03-04 16:15:31 -060099 {
Chris Cain1be43372021-12-09 19:29:37 -0600100 // Update persisted data with new mode
101 persistedData.updateMode(newMode, 0);
Chris Cain36f9cde2021-11-22 11:18:21 -0600102
Chris Cain78e86012021-03-04 16:15:31 -0600103 log<level::INFO>(
Chris Cain1be43372021-12-09 19:29:37 -0600104 fmt::format("DBus Power Mode Changed: {}", propVal).c_str());
Chris Cain78e86012021-03-04 16:15:31 -0600105
Chris Cain36f9cde2021-11-22 11:18:21 -0600106 // Send mode change to OCC
107 sendModeChange();
108 }
109 }
110}
111
Ben Tyner3576d652022-05-22 18:05:53 -0500112// Set the state of power mode lock. Writing persistent data via dbus method.
113bool PowerMode::powerModeLock()
114{
115 log<level::INFO>("PowerMode::powerModeLock: locking mode change");
116 persistedData.updateModeLock(true); // write persistent data
117 return true;
118}
119
120// Get the state of power mode. Reading persistent data via dbus method.
121bool PowerMode::powerModeLockStatus()
122{
123 bool status = persistedData.getModeLock(); // read persistent data
124 log<level::INFO>(fmt::format("PowerMode::powerModeLockStatus: {}",
125 status ? "locked" : "unlocked")
126 .c_str());
127 return status;
128}
129
Chris Cain36f9cde2021-11-22 11:18:21 -0600130// Called from OCC PassThrough interface (via CE login / BMC command line)
Chris Cain1be43372021-12-09 19:29:37 -0600131bool PowerMode::setMode(const SysPwrMode newMode, const uint16_t oemModeData)
Chris Cain36f9cde2021-11-22 11:18:21 -0600132{
Ben Tyner3576d652022-05-22 18:05:53 -0500133 if (persistedData.getModeLock())
134 {
135 log<level::INFO>("PowerMode::setMode: mode change blocked");
136 return false;
137 }
138
Chris Cain36f9cde2021-11-22 11:18:21 -0600139 if (updateDbusMode(newMode) == false)
140 {
141 // Unsupported mode
142 return false;
143 }
144
Chris Cain1be43372021-12-09 19:29:37 -0600145 // Save mode
146 persistedData.updateMode(newMode, oemModeData);
Chris Cain36f9cde2021-11-22 11:18:21 -0600147
Chris Cain1be43372021-12-09 19:29:37 -0600148 // Send mode change to OCC
149 if (sendModeChange() != CmdStatus::SUCCESS)
150 {
151 // Mode change failed
152 return false;
Chris Cain78e86012021-03-04 16:15:31 -0600153 }
154
Chris Cain36f9cde2021-11-22 11:18:21 -0600155 return true;
Chris Cain78e86012021-03-04 16:15:31 -0600156}
157
158// Convert PowerMode string to OCC SysPwrMode
Chris Cain36f9cde2021-11-22 11:18:21 -0600159// Returns NO_CHANGE if OEM or unsupported mode
Chris Cain78e86012021-03-04 16:15:31 -0600160SysPwrMode convertStringToMode(const std::string& i_modeString)
161{
162 SysPwrMode pmode = SysPwrMode::NO_CHANGE;
163
164 Mode::PowerMode mode = Mode::convertPowerModeFromString(i_modeString);
165 if (mode == Mode::PowerMode::MaximumPerformance)
166 {
167 pmode = SysPwrMode::MAX_PERF;
168 }
169 else if (mode == Mode::PowerMode::PowerSaving)
170 {
171 pmode = SysPwrMode::POWER_SAVING;
172 }
173 else if (mode == Mode::PowerMode::Static)
174 {
Chris Cain36f9cde2021-11-22 11:18:21 -0600175 pmode = SysPwrMode::STATIC;
Chris Cain78e86012021-03-04 16:15:31 -0600176 }
177 else
178 {
Chris Cain36f9cde2021-11-22 11:18:21 -0600179 if (mode != Mode::PowerMode::OEM)
180 {
181 log<level::ERR>(
182 fmt::format(
183 "convertStringToMode: Invalid Power Mode specified: {}",
184 i_modeString)
185 .c_str());
186 }
Chris Cain78e86012021-03-04 16:15:31 -0600187 }
188
189 return pmode;
190}
191
Chris Cain36f9cde2021-11-22 11:18:21 -0600192// Check if Hypervisor target is PowerVM
193bool isPowerVM()
Chris Cain1d51da22021-09-21 14:13:41 -0500194{
Chris Cain52cce032023-02-09 15:38:31 -0600195 bool powerVmTarget = true;
196#ifdef POWERVM_CHECK
Chris Cain36f9cde2021-11-22 11:18:21 -0600197 namespace Hyper = sdbusplus::com::ibm::Host::server;
198 constexpr auto HYPE_PATH = "/com/ibm/host0/hypervisor";
199 constexpr auto HYPE_INTERFACE = "com.ibm.Host.Target";
200 constexpr auto HYPE_PROP = "Target";
201
Chris Cain36f9cde2021-11-22 11:18:21 -0600202 // This will throw exception on failure
203 auto& bus = utils::getBus();
204 auto service = utils::getService(HYPE_PATH, HYPE_INTERFACE);
205 auto method = bus.new_method_call(service.c_str(), HYPE_PATH,
206 "org.freedesktop.DBus.Properties", "Get");
207 method.append(HYPE_INTERFACE, HYPE_PROP);
208 auto reply = bus.call(method);
209
210 std::variant<std::string> hyperEntryValue;
211 reply.read(hyperEntryValue);
212 auto propVal = std::get<std::string>(hyperEntryValue);
213 if (Hyper::Target::convertHypervisorFromString(propVal) ==
214 Hyper::Target::Hypervisor::PowerVM)
215 {
216 powerVmTarget = true;
217 }
218
219 log<level::DEBUG>(
220 fmt::format("isPowerVM returning {}", powerVmTarget).c_str());
Chris Cain52cce032023-02-09 15:38:31 -0600221#endif
Chris Cain36f9cde2021-11-22 11:18:21 -0600222
223 return powerVmTarget;
224}
225
Chris Cain1be43372021-12-09 19:29:37 -0600226// Initialize persistent data and return true if successful
227bool PowerMode::initPersistentData()
Chris Cain36f9cde2021-11-22 11:18:21 -0600228{
Chris Cain1be43372021-12-09 19:29:37 -0600229 if (!persistedData.modeAvailable())
Chris Cain36f9cde2021-11-22 11:18:21 -0600230 {
Chris Cain1be43372021-12-09 19:29:37 -0600231 // Read the default mode
232 SysPwrMode currentMode;
233 if (!getDefaultMode(currentMode))
234 {
235 // Unable to read defaults
236 return false;
237 }
238 log<level::INFO>(
239 fmt::format("PowerMode::initPersistentData: Using default mode: {}",
240 currentMode)
Chris Cain36f9cde2021-11-22 11:18:21 -0600241 .c_str());
Chris Cain1be43372021-12-09 19:29:37 -0600242
243 // Save default mode as current mode
244 persistedData.updateMode(currentMode, 0);
245
246 // Write default mode to DBus
247 updateDbusMode(currentMode);
Chris Cain36f9cde2021-11-22 11:18:21 -0600248 }
249
Chris Cain1be43372021-12-09 19:29:37 -0600250 if (!persistedData.ipsAvailable())
251 {
Chris Caincde7bea2022-01-28 15:54:24 -0600252 // Read the default IPS parameters, write persistent file and update
253 // DBus
254 return useDefaultIPSParms();
Chris Cain1be43372021-12-09 19:29:37 -0600255 }
256 return true;
257}
258
259// Get the requested power mode and return true if successful
260bool PowerMode::getMode(SysPwrMode& currentMode, uint16_t& oemModeData)
261{
262 currentMode = SysPwrMode::NO_CHANGE;
263 oemModeData = 0;
264
265 if (!persistedData.getMode(currentMode, oemModeData))
266 {
267 // Persistent data not initialized, read defaults and update DBus
268 if (!initPersistentData())
269 {
270 // Unable to read defaults from entity manager yet
271 return false;
272 }
273 return persistedData.getMode(currentMode, oemModeData);
274 }
275
276 return true;
Chris Cain36f9cde2021-11-22 11:18:21 -0600277}
278
279// Set the power mode on DBus
280bool PowerMode::updateDbusMode(const SysPwrMode newMode)
281{
Chris Cain36f9cde2021-11-22 11:18:21 -0600282 if (!VALID_POWER_MODE_SETTING(newMode) &&
283 !VALID_OEM_POWER_MODE_SETTING(newMode))
284 {
285 log<level::ERR>(
286 fmt::format(
287 "PowerMode::updateDbusMode - Requested power mode not supported: {}",
288 newMode)
289 .c_str());
290 return false;
291 }
292
Chris Cain1be43372021-12-09 19:29:37 -0600293 // Convert mode for DBus
294 ModeInterface::PowerMode dBusMode;
Chris Cain36f9cde2021-11-22 11:18:21 -0600295 switch (newMode)
296 {
297 case SysPwrMode::STATIC:
Chris Cain1be43372021-12-09 19:29:37 -0600298 dBusMode = Mode::PowerMode::Static;
Chris Cain36f9cde2021-11-22 11:18:21 -0600299 break;
300 case SysPwrMode::POWER_SAVING:
Chris Cain1be43372021-12-09 19:29:37 -0600301 dBusMode = Mode::PowerMode::PowerSaving;
Chris Cain36f9cde2021-11-22 11:18:21 -0600302 break;
303 case SysPwrMode::MAX_PERF:
Chris Cain1be43372021-12-09 19:29:37 -0600304 dBusMode = Mode::PowerMode::MaximumPerformance;
Chris Cain36f9cde2021-11-22 11:18:21 -0600305 break;
306 default:
Chris Cain1be43372021-12-09 19:29:37 -0600307 dBusMode = Mode::PowerMode::OEM;
Chris Cain36f9cde2021-11-22 11:18:21 -0600308 }
309
Chris Cain1be43372021-12-09 19:29:37 -0600310 // true = skip update signal
311 ModeInterface::setPropertyByName(POWER_MODE_PROP, dBusMode, true);
Chris Cain36f9cde2021-11-22 11:18:21 -0600312
313 return true;
314}
315
316// Send mode change request to the master OCC
317CmdStatus PowerMode::sendModeChange()
318{
Chris Cain6fa848a2022-01-24 14:54:38 -0600319 CmdStatus status;
Chris Cain36f9cde2021-11-22 11:18:21 -0600320
Chris Cain6fa848a2022-01-24 14:54:38 -0600321 if (!masterActive || !masterOccSet)
Chris Cain36f9cde2021-11-22 11:18:21 -0600322 {
323 // Nothing to do
Chris Cain6fa848a2022-01-24 14:54:38 -0600324 log<level::DEBUG>("PowerMode::sendModeChange: OCC master not active");
Chris Cain36f9cde2021-11-22 11:18:21 -0600325 return CmdStatus::SUCCESS;
326 }
327
328 if (!isPowerVM())
329 {
330 // Mode change is only supported on PowerVM systems
331 log<level::DEBUG>(
332 "PowerMode::sendModeChange: MODE CHANGE does not get sent on non-PowerVM systems");
333 return CmdStatus::SUCCESS;
334 }
335
Chris Cain1be43372021-12-09 19:29:37 -0600336 SysPwrMode newMode;
337 uint16_t oemModeData = 0;
338 getMode(newMode, oemModeData);
Chris Cain36f9cde2021-11-22 11:18:21 -0600339
340 if (VALID_POWER_MODE_SETTING(newMode) ||
341 VALID_OEM_POWER_MODE_SETTING(newMode))
342 {
343 std::vector<std::uint8_t> cmd, rsp;
344 cmd.reserve(9);
345 cmd.push_back(uint8_t(CmdType::SET_MODE_AND_STATE));
346 cmd.push_back(0x00); // Data Length (2 bytes)
347 cmd.push_back(0x06);
348 cmd.push_back(0x30); // Data (Version)
349 cmd.push_back(uint8_t(OccState::NO_CHANGE));
350 cmd.push_back(uint8_t(newMode));
Chris Cain1be43372021-12-09 19:29:37 -0600351 cmd.push_back(oemModeData >> 8); // Mode Data (Freq Point)
352 cmd.push_back(oemModeData & 0xFF); //
353 cmd.push_back(0x00); // reserved
Chris Cain36f9cde2021-11-22 11:18:21 -0600354 log<level::INFO>(
355 fmt::format(
356 "PowerMode::sendModeChange: SET_MODE({},{}) command to OCC{} ({} bytes)",
Chris Cain1be43372021-12-09 19:29:37 -0600357 newMode, oemModeData, occInstance, cmd.size())
Chris Cain36f9cde2021-11-22 11:18:21 -0600358 .c_str());
Chris Cain6fa848a2022-01-24 14:54:38 -0600359 status = occCmd->send(cmd, rsp);
Chris Cain36f9cde2021-11-22 11:18:21 -0600360 if (status == CmdStatus::SUCCESS)
361 {
362 if (rsp.size() == 5)
363 {
364 if (RspStatus::SUCCESS != RspStatus(rsp[2]))
365 {
366 log<level::ERR>(
367 fmt::format(
368 "PowerMode::sendModeChange: SET MODE failed with status 0x{:02X}",
369 rsp[2])
370 .c_str());
371 dump_hex(rsp);
372 status = CmdStatus::FAILURE;
373 }
374 }
375 else
376 {
377 log<level::ERR>(
378 "PowerMode::sendModeChange: INVALID SET MODE response");
379 dump_hex(rsp);
380 status = CmdStatus::FAILURE;
381 }
382 }
383 else
384 {
Chris Cainc567dc82022-04-01 15:09:17 -0500385 log<level::ERR>(
386 fmt::format(
387 "PowerMode::sendModeChange: SET_MODE FAILED with status={}",
388 status)
389 .c_str());
Chris Cain36f9cde2021-11-22 11:18:21 -0600390 }
391 }
392 else
393 {
394 log<level::ERR>(
395 fmt::format(
396 "PowerMode::sendModeChange: Unable to set power mode to {}",
397 newMode)
398 .c_str());
399 status = CmdStatus::FAILURE;
400 }
401
402 return status;
403}
404
Patrick Williamsaf408082022-07-22 19:26:54 -0500405void PowerMode::ipsChanged(sdbusplus::message_t& msg)
Chris Cain36f9cde2021-11-22 11:18:21 -0600406{
Chris Cain1d51da22021-09-21 14:13:41 -0500407 bool parmsChanged = false;
408 std::string interface;
409 std::map<std::string, std::variant<bool, uint8_t, uint64_t>>
410 ipsProperties{};
411 msg.read(interface, ipsProperties);
412
Chris Cain1be43372021-12-09 19:29:37 -0600413 // Read persisted values
414 bool ipsEnabled;
415 uint8_t enterUtil, exitUtil;
416 uint16_t enterTime, exitTime;
417 getIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime);
418
419 // Check for any changed data
Chris Cain1d51da22021-09-21 14:13:41 -0500420 auto ipsEntry = ipsProperties.find(IPS_ENABLED_PROP);
421 if (ipsEntry != ipsProperties.end())
422 {
Chris Cain1be43372021-12-09 19:29:37 -0600423 ipsEnabled = std::get<bool>(ipsEntry->second);
Chris Cain1d51da22021-09-21 14:13:41 -0500424 log<level::INFO>(
425 fmt::format("Idle Power Saver change: Enabled={}", ipsEnabled)
426 .c_str());
427 parmsChanged = true;
428 }
429 ipsEntry = ipsProperties.find(IPS_ENTER_UTIL);
430 if (ipsEntry != ipsProperties.end())
431 {
Chris Cain1be43372021-12-09 19:29:37 -0600432 enterUtil = std::get<uint8_t>(ipsEntry->second);
Chris Cain1d51da22021-09-21 14:13:41 -0500433 log<level::INFO>(
434 fmt::format("Idle Power Saver change: Enter Util={}%", enterUtil)
435 .c_str());
436 parmsChanged = true;
437 }
438 ipsEntry = ipsProperties.find(IPS_ENTER_TIME);
439 if (ipsEntry != ipsProperties.end())
440 {
441 std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second));
Chris Cain1be43372021-12-09 19:29:37 -0600442 enterTime =
Chris Cain1d51da22021-09-21 14:13:41 -0500443 std::chrono::duration_cast<std::chrono::seconds>(ms).count();
444 log<level::INFO>(
445 fmt::format("Idle Power Saver change: Enter Time={}sec", enterTime)
446 .c_str());
447 parmsChanged = true;
448 }
449 ipsEntry = ipsProperties.find(IPS_EXIT_UTIL);
450 if (ipsEntry != ipsProperties.end())
451 {
Chris Cain1be43372021-12-09 19:29:37 -0600452 exitUtil = std::get<uint8_t>(ipsEntry->second);
Chris Cain1d51da22021-09-21 14:13:41 -0500453 log<level::INFO>(
454 fmt::format("Idle Power Saver change: Exit Util={}%", exitUtil)
455 .c_str());
456 parmsChanged = true;
457 }
458 ipsEntry = ipsProperties.find(IPS_EXIT_TIME);
459 if (ipsEntry != ipsProperties.end())
460 {
461 std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second));
Chris Cain1be43372021-12-09 19:29:37 -0600462 exitTime = std::chrono::duration_cast<std::chrono::seconds>(ms).count();
Chris Cain1d51da22021-09-21 14:13:41 -0500463 log<level::INFO>(
464 fmt::format("Idle Power Saver change: Exit Time={}sec", exitTime)
465 .c_str());
466 parmsChanged = true;
467 }
468
469 if (parmsChanged)
470 {
Chris Caincde7bea2022-01-28 15:54:24 -0600471 if (exitUtil == 0)
472 {
473 // Setting the exitUtil to 0 will force restoring the default IPS
474 // parmeters (0 is not valid exit utilization)
475 log<level::INFO>(
476 "Idle Power Saver Exit Utilization is 0%. Restoring default parameters");
477 // Read the default IPS parameters, write persistent file and update
478 // DBus
479 useDefaultIPSParms();
480 }
481 else
482 {
483 // Update persistant data with new DBus values
484 persistedData.updateIPS(ipsEnabled, enterUtil, enterTime, exitUtil,
485 exitTime);
486 }
Chris Cain1be43372021-12-09 19:29:37 -0600487
488 // Trigger IPS data to get sent to the OCC
Chris Cain36f9cde2021-11-22 11:18:21 -0600489 sendIpsData();
Chris Cain1d51da22021-09-21 14:13:41 -0500490 }
491
492 return;
493}
494
Chris Cain1be43372021-12-09 19:29:37 -0600495/** @brief Get the Idle Power Saver properties from persisted data
496 * @return true if IPS parameters were read
Chris Cain36f9cde2021-11-22 11:18:21 -0600497 */
Chris Cain1be43372021-12-09 19:29:37 -0600498bool PowerMode::getIPSParms(bool& ipsEnabled, uint8_t& enterUtil,
499 uint16_t& enterTime, uint8_t& exitUtil,
500 uint16_t& exitTime)
Chris Cain36f9cde2021-11-22 11:18:21 -0600501{
Chris Cain36f9cde2021-11-22 11:18:21 -0600502 // Defaults:
Chris Cain1be43372021-12-09 19:29:37 -0600503 ipsEnabled = true; // Enabled
504 enterUtil = 8; // Enter Utilization (8%)
505 enterTime = 240; // Enter Delay Time (240s)
506 exitUtil = 12; // Exit Utilization (12%)
507 exitTime = 10; // Exit Delay Time (10s)
Chris Cain36f9cde2021-11-22 11:18:21 -0600508
Chris Cain1be43372021-12-09 19:29:37 -0600509 if (!persistedData.getIPS(ipsEnabled, enterUtil, enterTime, exitUtil,
510 exitTime))
511 {
512 // Persistent data not initialized, read defaults and update DBus
513 if (!initPersistentData())
514 {
515 // Unable to read defaults from entity manager yet
516 return false;
517 }
Chris Cain36f9cde2021-11-22 11:18:21 -0600518
Chris Cain1be43372021-12-09 19:29:37 -0600519 persistedData.getIPS(ipsEnabled, enterUtil, enterTime, exitUtil,
520 exitTime);
Chris Cain36f9cde2021-11-22 11:18:21 -0600521 }
522
523 if (enterUtil > exitUtil)
524 {
525 log<level::ERR>(
526 fmt::format(
527 "ERROR: Idle Power Saver Enter Utilization ({}%) is > Exit Utilization ({}%) - using Exit for both",
528 enterUtil, exitUtil)
529 .c_str());
530 enterUtil = exitUtil;
531 }
532
Chris Cain1be43372021-12-09 19:29:37 -0600533 return true;
534}
535
536// Set the Idle Power Saver data on DBus
537bool PowerMode::updateDbusIPS(const bool enabled, const uint8_t enterUtil,
538 const uint16_t enterTime, const uint8_t exitUtil,
539 const uint16_t exitTime)
540{
541 // true = skip update signal
542 IpsInterface::setPropertyByName(IPS_ENABLED_PROP, enabled, true);
543 IpsInterface::setPropertyByName(IPS_ENTER_UTIL, enterUtil, true);
544 // Convert time from seconds to ms
545 uint64_t msTime = enterTime * 1000;
546 IpsInterface::setPropertyByName(IPS_ENTER_TIME, msTime, true);
547 IpsInterface::setPropertyByName(IPS_EXIT_UTIL, exitUtil, true);
548 msTime = exitTime * 1000;
549 IpsInterface::setPropertyByName(IPS_EXIT_TIME, msTime, true);
550
551 return true;
Chris Cain36f9cde2021-11-22 11:18:21 -0600552}
553
554// Send Idle Power Saver config data to the master OCC
555CmdStatus PowerMode::sendIpsData()
556{
Chris Cain6fa848a2022-01-24 14:54:38 -0600557 if (!masterActive || !masterOccSet)
Chris Cain36f9cde2021-11-22 11:18:21 -0600558 {
559 // Nothing to do
560 return CmdStatus::SUCCESS;
561 }
562
563 if (!isPowerVM())
564 {
565 // Idle Power Saver data is only supported on PowerVM systems
566 log<level::DEBUG>(
567 "PowerMode::sendIpsData: SET_CFG_DATA[IPS] does not get sent on non-PowerVM systems");
568 return CmdStatus::SUCCESS;
569 }
570
Chris Cain1be43372021-12-09 19:29:37 -0600571 bool ipsEnabled;
Chris Cain36f9cde2021-11-22 11:18:21 -0600572 uint8_t enterUtil, exitUtil;
573 uint16_t enterTime, exitTime;
Chris Cain1be43372021-12-09 19:29:37 -0600574 getIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime);
Chris Cain36f9cde2021-11-22 11:18:21 -0600575
576 log<level::INFO>(
577 fmt::format(
578 "Idle Power Saver Parameters: enabled:{}, enter:{}%/{}s, exit:{}%/{}s",
579 ipsEnabled, enterUtil, enterTime, exitUtil, exitTime)
580 .c_str());
581
582 std::vector<std::uint8_t> cmd, rsp;
583 cmd.reserve(12);
584 cmd.push_back(uint8_t(CmdType::SET_CONFIG_DATA));
585 cmd.push_back(0x00); // Data Length (2 bytes)
586 cmd.push_back(0x09); //
587 cmd.push_back(0x11); // Config Format: IPS Settings
588 cmd.push_back(0x00); // Version
589 cmd.push_back(ipsEnabled ? 1 : 0); // IPS Enable
590 cmd.push_back(enterTime >> 8); // Enter Delay Time
591 cmd.push_back(enterTime & 0xFF); //
592 cmd.push_back(enterUtil); // Enter Utilization
593 cmd.push_back(exitTime >> 8); // Exit Delay Time
594 cmd.push_back(exitTime & 0xFF); //
595 cmd.push_back(exitUtil); // Exit Utilization
596 log<level::INFO>(fmt::format("PowerMode::sendIpsData: SET_CFG_DATA[IPS] "
597 "command to OCC{} ({} bytes)",
598 occInstance, cmd.size())
599 .c_str());
Chris Cain1be43372021-12-09 19:29:37 -0600600 CmdStatus status = occCmd->send(cmd, rsp);
Chris Cain36f9cde2021-11-22 11:18:21 -0600601 if (status == CmdStatus::SUCCESS)
602 {
603 if (rsp.size() == 5)
604 {
605 if (RspStatus::SUCCESS != RspStatus(rsp[2]))
606 {
607 log<level::ERR>(
608 fmt::format(
609 "PowerMode::sendIpsData: SET_CFG_DATA[IPS] failed with status 0x{:02X}",
610 rsp[2])
611 .c_str());
612 dump_hex(rsp);
613 status = CmdStatus::FAILURE;
614 }
615 }
616 else
617 {
618 log<level::ERR>(
619 "PowerMode::sendIpsData: INVALID SET_CFG_DATA[IPS] response");
620 dump_hex(rsp);
621 status = CmdStatus::FAILURE;
622 }
623 }
624 else
625 {
Chris Cainc567dc82022-04-01 15:09:17 -0500626 log<level::ERR>(
627 fmt::format(
628 "PowerMode::sendIpsData: SET_CFG_DATA[IPS] with status={}",
629 status)
630 .c_str());
Chris Cain36f9cde2021-11-22 11:18:21 -0600631 }
632
633 return status;
634}
635
Chris Caincde7bea2022-01-28 15:54:24 -0600636// Print the current values
Chris Cain1be43372021-12-09 19:29:37 -0600637void OccPersistData::print()
Chris Cain36f9cde2021-11-22 11:18:21 -0600638{
Chris Cain1be43372021-12-09 19:29:37 -0600639 if (modeData.modeInitialized)
640 {
641 log<level::INFO>(
642 fmt::format(
Ben Tyner3576d652022-05-22 18:05:53 -0500643 "OccPersistData: Mode: 0x{:02X}, OEM Mode Data: {} (0x{:04X} Locked{})",
644 modeData.mode, modeData.oemModeData, modeData.oemModeData,
645 modeData.modeLocked)
Chris Cain1be43372021-12-09 19:29:37 -0600646 .c_str());
647 }
648 if (modeData.ipsInitialized)
649 {
650 log<level::INFO>(
651 fmt::format(
652 "OccPersistData: IPS enabled:{}, enter:{}%/{}s, exit:{}%/{}s",
653 modeData.ipsEnabled, modeData.ipsEnterUtil,
654 modeData.ipsEnterTime, modeData.ipsExitUtil,
655 modeData.ipsExitTime)
656 .c_str());
657 }
Chris Cain36f9cde2021-11-22 11:18:21 -0600658}
659
660// Saves the OEM mode data in the filesystem using cereal.
661void OccPersistData::save()
662{
663 std::filesystem::path opath =
Chris Cain1be43372021-12-09 19:29:37 -0600664 std::filesystem::path{OCC_CONTROL_PERSIST_PATH} / powerModeFilename;
Chris Cain36f9cde2021-11-22 11:18:21 -0600665
666 if (!std::filesystem::exists(opath.parent_path()))
667 {
668 std::filesystem::create_directory(opath.parent_path());
669 }
670
671 log<level::DEBUG>(
Chris Cain1be43372021-12-09 19:29:37 -0600672 fmt::format(
673 "OccPersistData::save: Writing Power Mode persisted data to {}",
674 opath.c_str())
Chris Cain36f9cde2021-11-22 11:18:21 -0600675 .c_str());
Chris Caincde7bea2022-01-28 15:54:24 -0600676 // print();
Chris Cain36f9cde2021-11-22 11:18:21 -0600677
678 std::ofstream stream{opath.c_str()};
679 cereal::JSONOutputArchive oarchive{stream};
680
Chris Cain1be43372021-12-09 19:29:37 -0600681 oarchive(modeData);
Chris Cain36f9cde2021-11-22 11:18:21 -0600682}
683
684// Loads the OEM mode data in the filesystem using cereal.
685void OccPersistData::load()
686{
Chris Cain36f9cde2021-11-22 11:18:21 -0600687 std::filesystem::path ipath =
Chris Cain1be43372021-12-09 19:29:37 -0600688 std::filesystem::path{OCC_CONTROL_PERSIST_PATH} / powerModeFilename;
Chris Cain36f9cde2021-11-22 11:18:21 -0600689
690 if (!std::filesystem::exists(ipath))
691 {
Chris Cain1be43372021-12-09 19:29:37 -0600692 modeData.modeInitialized = false;
693 modeData.ipsInitialized = false;
Chris Cain36f9cde2021-11-22 11:18:21 -0600694 return;
695 }
696
697 log<level::DEBUG>(
Chris Cain1be43372021-12-09 19:29:37 -0600698 fmt::format(
699 "OccPersistData::load: Reading Power Mode persisted data from {}",
700 ipath.c_str())
Chris Cain36f9cde2021-11-22 11:18:21 -0600701 .c_str());
702 try
703 {
704 std::ifstream stream{ipath.c_str()};
705 cereal::JSONInputArchive iarchive(stream);
Chris Cain1be43372021-12-09 19:29:37 -0600706 iarchive(modeData);
Chris Cain36f9cde2021-11-22 11:18:21 -0600707 }
708 catch (const std::exception& e)
709 {
710 auto error = errno;
711 log<level::ERR>(
712 fmt::format("OccPersistData::load: failed to read {}, errno={}",
713 ipath.c_str(), error)
714 .c_str());
Chris Cain1be43372021-12-09 19:29:37 -0600715 modeData.modeInitialized = false;
716 modeData.ipsInitialized = false;
Chris Cain36f9cde2021-11-22 11:18:21 -0600717 }
718
Chris Caincde7bea2022-01-28 15:54:24 -0600719 // print();
Chris Cain36f9cde2021-11-22 11:18:21 -0600720}
721
Chris Cain1be43372021-12-09 19:29:37 -0600722// Called when PowerModeProperties defaults are available on DBus
Patrick Williamsaf408082022-07-22 19:26:54 -0500723void PowerMode::defaultsReady(sdbusplus::message_t& msg)
Chris Cain36f9cde2021-11-22 11:18:21 -0600724{
Chris Cain1be43372021-12-09 19:29:37 -0600725 std::map<std::string, std::variant<std::string>> properties{};
726 std::string interface;
727 msg.read(interface, properties);
Chris Cain36f9cde2021-11-22 11:18:21 -0600728
Chris Cain1be43372021-12-09 19:29:37 -0600729 // If persistent data exists, then don't need to read defaults
730 if ((!persistedData.modeAvailable()) || (!persistedData.ipsAvailable()))
Chris Cain36f9cde2021-11-22 11:18:21 -0600731 {
Chris Cain1be43372021-12-09 19:29:37 -0600732 log<level::INFO>(
733 fmt::format(
734 "Default PowerModeProperties are now available (persistent modeAvail={}, ipsAvail={})",
735 persistedData.modeAvailable() ? 'y' : 'n',
736 persistedData.modeAvailable() ? 'y' : 'n')
737 .c_str());
738
739 // Read default power mode defaults and update DBus
740 initPersistentData();
741 }
742}
743
744// Get the default power mode from DBus and return true if success
745bool PowerMode::getDefaultMode(SysPwrMode& defaultMode)
746{
747 try
748 {
749 auto& bus = utils::getBus();
750 std::string path = "/";
751 std::string service =
752 utils::getServiceUsingSubTree(PMODE_DEFAULT_INTERFACE, path);
Patrick Williamsa49c9872023-05-10 07:50:35 -0500753 auto method = bus.new_method_call(service.c_str(), path.c_str(),
754 "org.freedesktop.DBus.Properties",
755 "Get");
Chris Cain1be43372021-12-09 19:29:37 -0600756 method.append(PMODE_DEFAULT_INTERFACE, "PowerMode");
757 auto reply = bus.call(method);
758
759 std::variant<std::string> stateEntryValue;
760 reply.read(stateEntryValue);
761 auto propVal = std::get<std::string>(stateEntryValue);
762
Patrick Williamsa49c9872023-05-10 07:50:35 -0500763 const std::string fullModeString = PMODE_INTERFACE + ".PowerMode."s +
764 propVal;
Chris Cain1be43372021-12-09 19:29:37 -0600765 defaultMode = powermode::convertStringToMode(fullModeString);
766 if (!VALID_POWER_MODE_SETTING(defaultMode))
767 {
768 log<level::ERR>(
769 fmt::format(
770 "PowerMode::getDefaultMode: Invalid default power mode found: {}",
771 defaultMode)
772 .c_str());
773 // If default was read but not valid, use Max Performance
774 defaultMode = SysPwrMode::MAX_PERF;
775 return true;
776 }
777 }
Patrick Williamsaf408082022-07-22 19:26:54 -0500778 catch (const sdbusplus::exception_t& e)
Chris Cain1be43372021-12-09 19:29:37 -0600779 {
780 log<level::ERR>(
781 fmt::format("Unable to read Default Power Mode: {}", e.what())
782 .c_str());
783 return false;
Chris Cain36f9cde2021-11-22 11:18:21 -0600784 }
785
Chris Cain1be43372021-12-09 19:29:37 -0600786 return true;
787}
Chris Cain36f9cde2021-11-22 11:18:21 -0600788
Chris Cain1be43372021-12-09 19:29:37 -0600789/* Get the default Idle Power Saver properties and return true if successful */
790bool PowerMode::getDefaultIPSParms(bool& ipsEnabled, uint8_t& enterUtil,
791 uint16_t& enterTime, uint8_t& exitUtil,
792 uint16_t& exitTime)
793{
794 // Defaults:
795 ipsEnabled = true; // Enabled
796 enterUtil = 8; // Enter Utilization (8%)
797 enterTime = 240; // Enter Delay Time (240s)
798 exitUtil = 12; // Exit Utilization (12%)
799 exitTime = 10; // Exit Delay Time (10s)
800
801 std::map<std::string, std::variant<bool, uint8_t, uint16_t, uint64_t>>
802 ipsProperties{};
803
804 // Get all IPS properties from DBus
805 try
806 {
807 auto& bus = utils::getBus();
808 std::string path = "/";
809 std::string service =
810 utils::getServiceUsingSubTree(PMODE_DEFAULT_INTERFACE, path);
Patrick Williamsa49c9872023-05-10 07:50:35 -0500811 auto method = bus.new_method_call(service.c_str(), path.c_str(),
812 "org.freedesktop.DBus.Properties",
813 "GetAll");
Chris Cain1be43372021-12-09 19:29:37 -0600814 method.append(PMODE_DEFAULT_INTERFACE);
815 auto reply = bus.call(method);
816 reply.read(ipsProperties);
817 }
Patrick Williamsaf408082022-07-22 19:26:54 -0500818 catch (const sdbusplus::exception_t& e)
Chris Cain1be43372021-12-09 19:29:37 -0600819 {
820 log<level::ERR>(
821 fmt::format(
822 "Unable to read Default Idle Power Saver parameters so it will be disabled: {}",
823 e.what())
824 .c_str());
825 return false;
826 }
827
828 auto ipsEntry = ipsProperties.find("IdlePowerSaverEnabled");
829 if (ipsEntry != ipsProperties.end())
830 {
831 ipsEnabled = std::get<bool>(ipsEntry->second);
832 }
833 else
834 {
835 log<level::ERR>(
836 "PowerMode::getDefaultIPSParms could not find property: IdlePowerSaverEnabled");
837 }
838
839 ipsEntry = ipsProperties.find("EnterUtilizationPercent");
840 if (ipsEntry != ipsProperties.end())
841 {
842 enterUtil = std::get<uint64_t>(ipsEntry->second);
843 }
844 else
845 {
846 log<level::ERR>(
847 "PowerMode::getDefaultIPSParms could not find property: EnterUtilizationPercent");
848 }
849
850 ipsEntry = ipsProperties.find("EnterUtilizationDwellTime");
851 if (ipsEntry != ipsProperties.end())
852 {
853 enterTime = std::get<uint64_t>(ipsEntry->second);
854 }
855 else
856 {
857 log<level::ERR>(
858 "PowerMode::getDefaultIPSParms could not find property: EnterUtilizationDwellTime");
859 }
860
861 ipsEntry = ipsProperties.find("ExitUtilizationPercent");
862 if (ipsEntry != ipsProperties.end())
863 {
864 exitUtil = std::get<uint64_t>(ipsEntry->second);
865 }
866 else
867 {
868 log<level::ERR>(
869 "PowerMode::getDefaultIPSParms could not find property: ExitUtilizationPercent");
870 }
871
872 ipsEntry = ipsProperties.find("ExitUtilizationDwellTime");
873 if (ipsEntry != ipsProperties.end())
874 {
875 exitTime = std::get<uint64_t>(ipsEntry->second);
876 }
877 else
878 {
879 log<level::ERR>(
880 "PowerMode::getDefaultIPSParms could not find property: ExitUtilizationDwellTime");
881 }
882
883 if (enterUtil > exitUtil)
884 {
885 log<level::ERR>(
886 fmt::format(
887 "ERROR: Default Idle Power Saver Enter Utilization ({}%) is > Exit Utilization ({}%) - using Exit for both",
888 enterUtil, exitUtil)
889 .c_str());
890 enterUtil = exitUtil;
891 }
892
893 return true;
Chris Cain36f9cde2021-11-22 11:18:21 -0600894}
895
Chris Caincde7bea2022-01-28 15:54:24 -0600896/* Read default IPS parameters, save them to the persistent file and update
897 DBus. Return true if successful */
898bool PowerMode::useDefaultIPSParms()
899{
900 // Read the default IPS parameters
901 bool ipsEnabled;
902 uint8_t enterUtil, exitUtil;
903 uint16_t enterTime, exitTime;
904 if (!getDefaultIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil,
905 exitTime))
906 {
907 // Unable to read defaults
908 return false;
909 }
910 log<level::INFO>(
911 fmt::format(
912 "PowerMode::useDefaultIPSParms: Using default IPS parms: Enabled: {}, EnterUtil: {}%, EnterTime: {}s, ExitUtil: {}%, ExitTime: {}s",
913 ipsEnabled, enterUtil, enterTime, exitUtil, exitTime)
914 .c_str());
915
916 // Save IPS parms to the persistent file
917 persistedData.updateIPS(ipsEnabled, enterUtil, enterTime, exitUtil,
918 exitTime);
919
920 // Write IPS parms to DBus
921 return updateDbusIPS(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime);
922}
923
Sheldon Baileyea2b22e2022-04-04 12:24:46 -0500924#ifdef POWER10
925
926// Starts to watch for IPS active state changes.
927bool PowerMode::openIpsFile()
928{
929 bool rc = true;
930 fd = open(ipsStatusFile.c_str(), O_RDONLY | O_NONBLOCK);
931 const int open_errno = errno;
932 if (fd < 0)
933 {
934 log<level::ERR>(fmt::format("openIpsFile Error({})={} : File={}",
935 open_errno, strerror(open_errno),
936 ipsStatusFile.c_str())
937 .c_str());
938
939 close(fd);
940
941 using namespace sdbusplus::org::open_power::OCC::Device::Error;
942 report<OpenFailure>(
943 phosphor::logging::org::open_power::OCC::Device::OpenFailure::
944 CALLOUT_ERRNO(open_errno),
945 phosphor::logging::org::open_power::OCC::Device::OpenFailure::
946 CALLOUT_DEVICE_PATH(ipsStatusFile.c_str()));
947
948 // We are no longer watching the error
949 active(false);
950
951 watching = false;
952 rc = false;
953 // NOTE: this will leave the system not reporting IPS active state to
954 // Fan Controls, Until an APP reload, or IPL and we will attempt again.
955 }
956 return rc;
957}
958
959// Starts to watch for IPS active state changes.
960void PowerMode::addIpsWatch(bool poll)
961{
962 // open file and register callback on file if we are not currently watching,
963 // and if poll=true, and if we are the master.
964 if ((!watching) && poll)
965 {
966 // Open the file
967 if (openIpsFile())
968 {
969 // register the callback handler which sets 'watching'
970 registerIpsStatusCallBack();
971 }
972 }
973}
974
975// Stops watching for IPS active state changes.
976void PowerMode::removeIpsWatch()
977{
978 // NOTE: we want to remove event, close file, and IPS active false no
979 // matter what the 'watching' flags is set to.
980
981 // We are no longer watching the error
982 active(false);
983
984 watching = false;
985
986 // Close file
987 close(fd);
988
989 // clears sourcePtr in the event source.
990 eventSource.reset();
991}
992
993// Attaches the FD to event loop and registers the callback handler
994void PowerMode::registerIpsStatusCallBack()
995{
996 decltype(eventSource.get()) sourcePtr = nullptr;
997
998 auto r = sd_event_add_io(event.get(), &sourcePtr, fd, EPOLLPRI | EPOLLERR,
999 ipsStatusCallBack, this);
1000 if (r < 0)
1001 {
1002 log<level::ERR>(fmt::format("sd_event_add_io: Error({})={} : File={}",
1003 r, strerror(-r), ipsStatusFile.c_str())
1004 .c_str());
1005
1006 using InternalFailure =
1007 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
1008 report<InternalFailure>();
1009
1010 removeIpsWatch();
1011 // NOTE: this will leave the system not reporting IPS active state to
1012 // Fan Controls, Until an APP reload, or IPL and we will attempt again.
1013 }
1014 else
1015 {
1016 // puts sourcePtr in the event source.
1017 eventSource.reset(sourcePtr);
1018 // Set we are watching the error
1019 watching = true;
1020 }
1021}
1022
1023// Static function to redirect to non static analyze event function to be
1024// able to read file and push onto dBus.
1025int PowerMode::ipsStatusCallBack(sd_event_source* /*es*/, int /*fd*/,
1026 uint32_t /*revents*/, void* userData)
1027{
1028 auto pmode = static_cast<PowerMode*>(userData);
1029 pmode->analyzeIpsEvent();
1030 return 0;
1031}
1032
1033// Function to Read SysFs file change on IPS state and push on dBus.
1034void PowerMode::analyzeIpsEvent()
1035{
1036 // Need to seek to START, else the poll returns immediately telling
1037 // there is data to be read. if not done this floods the system.
1038 auto r = lseek(fd, 0, SEEK_SET);
1039 const int open_errno = errno;
1040 if (r < 0)
1041 {
1042 // NOTE: upon file access error we can not just re-open file, we have to
1043 // remove and add to watch.
1044 removeIpsWatch();
1045 addIpsWatch(true);
1046 }
1047
1048 // if we are 'watching' that is the file seek, or the re-open passed.. we
1049 // can read the data
1050 if (watching)
1051 {
1052 // This file gets created when polling OCCs. A value or length of 0 is
1053 // deemed success. That means we would disable IPS active on dbus.
1054 char data;
1055 bool ipsState = false;
1056 const auto len = read(fd, &data, sizeof(data));
1057 const int readErrno = errno;
1058 if (len <= 0)
1059 {
1060 removeIpsWatch();
1061
1062 log<level::ERR>(
1063 fmt::format("IPS state Read Error({})={} : File={} : len={}",
1064 readErrno, strerror(readErrno),
1065 ipsStatusFile.c_str(), len)
1066 .c_str());
1067
1068 report<ReadFailure>(
1069 phosphor::logging::org::open_power::OCC::Device::ReadFailure::
1070 CALLOUT_ERRNO(readErrno),
1071 phosphor::logging::org::open_power::OCC::Device::ReadFailure::
1072 CALLOUT_DEVICE_PATH(ipsStatusFile.c_str()));
1073
1074 // NOTE: this will leave the system not reporting IPS active state
1075 // to Fan Controls, Until an APP reload, or IPL and we will attempt
1076 // again.
1077 }
1078 else
1079 {
1080 // Data returned in ASCII.
1081 // convert to integer. atoi()
1082 // from OCC_P10_FW_Interfaces spec
1083 // Bit 6: IPS active 1 indicates enabled.
1084 // Bit 7: IPS enabled. 1 indicates enabled.
1085 // mask off bit 6 --> & 0x02
1086 // Shift left one bit and store as bool. >> 1
1087 ipsState = static_cast<bool>(((atoi(&data)) & 0x2) >> 1);
1088 }
1089
1090 // This will only set IPS active dbus if different than current.
1091 active(ipsState);
1092 }
1093 else
1094 {
1095 removeIpsWatch();
1096
1097 // If the Retry did not get to "watching = true" we already have an
1098 // error log, just post trace.
1099 log<level::ERR>(fmt::format("Retry on File seek Error({})={} : File={}",
1100 open_errno, strerror(open_errno),
1101 ipsStatusFile.c_str())
1102 .c_str());
1103
1104 // NOTE: this will leave the system not reporting IPS active state to
1105 // Fan Controls, Until an APP reload, or IPL and we will attempt again.
1106 }
1107
1108 return;
1109}
Ben Tyner3576d652022-05-22 18:05:53 -05001110
1111// overrides read/write to powerMode dbus property.
1112Mode::PowerMode PowerMode::powerMode(Mode::PowerMode value)
1113{
1114 if (persistedData.getModeLock())
1115 {
1116 log<level::INFO>("PowerMode::powerMode: mode property change blocked");
1117 elog<NotAllowed>(xyz::openbmc_project::Common::NotAllowed::REASON(
1118 "mode change not allowed due to lock"));
1119 return value;
1120 }
1121 else
1122 {
1123 return Mode::powerMode(value);
1124 }
1125}
Sheldon Baileyea2b22e2022-04-04 12:24:46 -05001126#endif
1127
Sheldon Bailey31a2f132022-05-20 11:31:52 -05001128/* Set dbus property to SAFE mode(true) or clear(false) only if different */
1129void PowerMode::updateDbusSafeMode(const bool safeModeReq)
1130{
1131 log<level::DEBUG>(
1132 fmt::format("PowerMode:updateDbusSafeMode: Update dbus state ({})",
1133 safeModeReq)
1134 .c_str());
1135
1136 // Note; this function checks and only updates if different.
1137 Mode::safeMode(safeModeReq);
1138}
1139
Chris Cain78e86012021-03-04 16:15:31 -06001140} // namespace powermode
1141
1142} // namespace occ
1143
1144} // namespace open_power