blob: 342188ee4007a9e3376fd68789fde4b41cba2778 [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 }
Chris Cain2ff28862024-01-31 10:21:13 -0600177 else if (mode == Mode::PowerMode::EfficiencyFavorPower)
178 {
179 pmode = SysPwrMode::EFF_FAVOR_POWER;
180 }
181 else if (mode == Mode::PowerMode::EfficiencyFavorPerformance)
182 {
183 pmode = SysPwrMode::EFF_FAVOR_PERF;
184 }
185 else if (mode == Mode::PowerMode::BalancedPerformance)
186 {
187 pmode = SysPwrMode::BALANCED_PERF;
188 }
Chris Cain78e86012021-03-04 16:15:31 -0600189 else
190 {
Chris Cain36f9cde2021-11-22 11:18:21 -0600191 if (mode != Mode::PowerMode::OEM)
192 {
193 log<level::ERR>(
194 fmt::format(
195 "convertStringToMode: Invalid Power Mode specified: {}",
196 i_modeString)
197 .c_str());
198 }
Chris Cain78e86012021-03-04 16:15:31 -0600199 }
200
201 return pmode;
202}
203
Chris Cain36f9cde2021-11-22 11:18:21 -0600204// Check if Hypervisor target is PowerVM
205bool isPowerVM()
Chris Cain1d51da22021-09-21 14:13:41 -0500206{
Chris Cain52cce032023-02-09 15:38:31 -0600207 bool powerVmTarget = true;
208#ifdef POWERVM_CHECK
Chris Cain36f9cde2021-11-22 11:18:21 -0600209 namespace Hyper = sdbusplus::com::ibm::Host::server;
210 constexpr auto HYPE_PATH = "/com/ibm/host0/hypervisor";
211 constexpr auto HYPE_INTERFACE = "com.ibm.Host.Target";
212 constexpr auto HYPE_PROP = "Target";
213
Chris Cain36f9cde2021-11-22 11:18:21 -0600214 // This will throw exception on failure
215 auto& bus = utils::getBus();
216 auto service = utils::getService(HYPE_PATH, HYPE_INTERFACE);
217 auto method = bus.new_method_call(service.c_str(), HYPE_PATH,
218 "org.freedesktop.DBus.Properties", "Get");
219 method.append(HYPE_INTERFACE, HYPE_PROP);
220 auto reply = bus.call(method);
221
222 std::variant<std::string> hyperEntryValue;
223 reply.read(hyperEntryValue);
224 auto propVal = std::get<std::string>(hyperEntryValue);
225 if (Hyper::Target::convertHypervisorFromString(propVal) ==
226 Hyper::Target::Hypervisor::PowerVM)
227 {
228 powerVmTarget = true;
229 }
230
231 log<level::DEBUG>(
232 fmt::format("isPowerVM returning {}", powerVmTarget).c_str());
Chris Cain52cce032023-02-09 15:38:31 -0600233#endif
Chris Cain36f9cde2021-11-22 11:18:21 -0600234
235 return powerVmTarget;
236}
237
Chris Cain1be43372021-12-09 19:29:37 -0600238// Initialize persistent data and return true if successful
239bool PowerMode::initPersistentData()
Chris Cain36f9cde2021-11-22 11:18:21 -0600240{
Chris Cain1be43372021-12-09 19:29:37 -0600241 if (!persistedData.modeAvailable())
Chris Cain36f9cde2021-11-22 11:18:21 -0600242 {
Chris Cain1be43372021-12-09 19:29:37 -0600243 // Read the default mode
244 SysPwrMode currentMode;
245 if (!getDefaultMode(currentMode))
246 {
247 // Unable to read defaults
248 return false;
249 }
250 log<level::INFO>(
251 fmt::format("PowerMode::initPersistentData: Using default mode: {}",
252 currentMode)
Chris Cain36f9cde2021-11-22 11:18:21 -0600253 .c_str());
Chris Cain1be43372021-12-09 19:29:37 -0600254
255 // Save default mode as current mode
256 persistedData.updateMode(currentMode, 0);
257
258 // Write default mode to DBus
259 updateDbusMode(currentMode);
Chris Cain36f9cde2021-11-22 11:18:21 -0600260 }
261
Chris Cain1be43372021-12-09 19:29:37 -0600262 if (!persistedData.ipsAvailable())
263 {
Chris Caincde7bea2022-01-28 15:54:24 -0600264 // Read the default IPS parameters, write persistent file and update
265 // DBus
266 return useDefaultIPSParms();
Chris Cain1be43372021-12-09 19:29:37 -0600267 }
268 return true;
269}
270
271// Get the requested power mode and return true if successful
272bool PowerMode::getMode(SysPwrMode& currentMode, uint16_t& oemModeData)
273{
274 currentMode = SysPwrMode::NO_CHANGE;
275 oemModeData = 0;
276
277 if (!persistedData.getMode(currentMode, oemModeData))
278 {
279 // Persistent data not initialized, read defaults and update DBus
280 if (!initPersistentData())
281 {
282 // Unable to read defaults from entity manager yet
283 return false;
284 }
285 return persistedData.getMode(currentMode, oemModeData);
286 }
287
288 return true;
Chris Cain36f9cde2021-11-22 11:18:21 -0600289}
290
291// Set the power mode on DBus
292bool PowerMode::updateDbusMode(const SysPwrMode newMode)
293{
Chris Cain36f9cde2021-11-22 11:18:21 -0600294 if (!VALID_POWER_MODE_SETTING(newMode) &&
295 !VALID_OEM_POWER_MODE_SETTING(newMode))
296 {
297 log<level::ERR>(
298 fmt::format(
299 "PowerMode::updateDbusMode - Requested power mode not supported: {}",
300 newMode)
301 .c_str());
302 return false;
303 }
304
Chris Cain1be43372021-12-09 19:29:37 -0600305 // Convert mode for DBus
306 ModeInterface::PowerMode dBusMode;
Chris Cain36f9cde2021-11-22 11:18:21 -0600307 switch (newMode)
308 {
309 case SysPwrMode::STATIC:
Chris Cain1be43372021-12-09 19:29:37 -0600310 dBusMode = Mode::PowerMode::Static;
Chris Cain36f9cde2021-11-22 11:18:21 -0600311 break;
312 case SysPwrMode::POWER_SAVING:
Chris Cain1be43372021-12-09 19:29:37 -0600313 dBusMode = Mode::PowerMode::PowerSaving;
Chris Cain36f9cde2021-11-22 11:18:21 -0600314 break;
315 case SysPwrMode::MAX_PERF:
Chris Cain1be43372021-12-09 19:29:37 -0600316 dBusMode = Mode::PowerMode::MaximumPerformance;
Chris Cain36f9cde2021-11-22 11:18:21 -0600317 break;
Chris Cain2ff28862024-01-31 10:21:13 -0600318 case SysPwrMode::EFF_FAVOR_POWER:
319 dBusMode = Mode::PowerMode::EfficiencyFavorPower;
320 break;
321 case SysPwrMode::EFF_FAVOR_PERF:
322 dBusMode = Mode::PowerMode::EfficiencyFavorPerformance;
323 break;
324 case SysPwrMode::BALANCED_PERF:
325 dBusMode = Mode::PowerMode::BalancedPerformance;
326 break;
Chris Cain36f9cde2021-11-22 11:18:21 -0600327 default:
Chris Cain1be43372021-12-09 19:29:37 -0600328 dBusMode = Mode::PowerMode::OEM;
Chris Cain36f9cde2021-11-22 11:18:21 -0600329 }
330
Chris Cain1be43372021-12-09 19:29:37 -0600331 // true = skip update signal
332 ModeInterface::setPropertyByName(POWER_MODE_PROP, dBusMode, true);
Chris Cain36f9cde2021-11-22 11:18:21 -0600333
334 return true;
335}
336
337// Send mode change request to the master OCC
338CmdStatus PowerMode::sendModeChange()
339{
Chris Cain6fa848a2022-01-24 14:54:38 -0600340 CmdStatus status;
Chris Cain36f9cde2021-11-22 11:18:21 -0600341
Chris Cain6fa848a2022-01-24 14:54:38 -0600342 if (!masterActive || !masterOccSet)
Chris Cain36f9cde2021-11-22 11:18:21 -0600343 {
344 // Nothing to do
Chris Cain6fa848a2022-01-24 14:54:38 -0600345 log<level::DEBUG>("PowerMode::sendModeChange: OCC master not active");
Chris Cain36f9cde2021-11-22 11:18:21 -0600346 return CmdStatus::SUCCESS;
347 }
348
349 if (!isPowerVM())
350 {
351 // Mode change is only supported on PowerVM systems
352 log<level::DEBUG>(
353 "PowerMode::sendModeChange: MODE CHANGE does not get sent on non-PowerVM systems");
354 return CmdStatus::SUCCESS;
355 }
356
Chris Cain1be43372021-12-09 19:29:37 -0600357 SysPwrMode newMode;
358 uint16_t oemModeData = 0;
359 getMode(newMode, oemModeData);
Chris Cain36f9cde2021-11-22 11:18:21 -0600360
361 if (VALID_POWER_MODE_SETTING(newMode) ||
362 VALID_OEM_POWER_MODE_SETTING(newMode))
363 {
364 std::vector<std::uint8_t> cmd, rsp;
365 cmd.reserve(9);
366 cmd.push_back(uint8_t(CmdType::SET_MODE_AND_STATE));
367 cmd.push_back(0x00); // Data Length (2 bytes)
368 cmd.push_back(0x06);
369 cmd.push_back(0x30); // Data (Version)
370 cmd.push_back(uint8_t(OccState::NO_CHANGE));
371 cmd.push_back(uint8_t(newMode));
Chris Cain1be43372021-12-09 19:29:37 -0600372 cmd.push_back(oemModeData >> 8); // Mode Data (Freq Point)
373 cmd.push_back(oemModeData & 0xFF); //
374 cmd.push_back(0x00); // reserved
Chris Cain36f9cde2021-11-22 11:18:21 -0600375 log<level::INFO>(
376 fmt::format(
377 "PowerMode::sendModeChange: SET_MODE({},{}) command to OCC{} ({} bytes)",
Chris Cain1be43372021-12-09 19:29:37 -0600378 newMode, oemModeData, occInstance, cmd.size())
Chris Cain36f9cde2021-11-22 11:18:21 -0600379 .c_str());
Chris Cain6fa848a2022-01-24 14:54:38 -0600380 status = occCmd->send(cmd, rsp);
Chris Cain36f9cde2021-11-22 11:18:21 -0600381 if (status == CmdStatus::SUCCESS)
382 {
383 if (rsp.size() == 5)
384 {
385 if (RspStatus::SUCCESS != RspStatus(rsp[2]))
386 {
387 log<level::ERR>(
388 fmt::format(
389 "PowerMode::sendModeChange: SET MODE failed with status 0x{:02X}",
390 rsp[2])
391 .c_str());
392 dump_hex(rsp);
393 status = CmdStatus::FAILURE;
394 }
395 }
396 else
397 {
398 log<level::ERR>(
399 "PowerMode::sendModeChange: INVALID SET MODE response");
400 dump_hex(rsp);
401 status = CmdStatus::FAILURE;
402 }
403 }
404 else
405 {
Chris Cainc567dc82022-04-01 15:09:17 -0500406 log<level::ERR>(
407 fmt::format(
408 "PowerMode::sendModeChange: SET_MODE FAILED with status={}",
409 status)
410 .c_str());
Chris Cain36f9cde2021-11-22 11:18:21 -0600411 }
412 }
413 else
414 {
415 log<level::ERR>(
416 fmt::format(
417 "PowerMode::sendModeChange: Unable to set power mode to {}",
418 newMode)
419 .c_str());
420 status = CmdStatus::FAILURE;
421 }
422
423 return status;
424}
425
Patrick Williamsaf408082022-07-22 19:26:54 -0500426void PowerMode::ipsChanged(sdbusplus::message_t& msg)
Chris Cain36f9cde2021-11-22 11:18:21 -0600427{
Chris Cain1d51da22021-09-21 14:13:41 -0500428 bool parmsChanged = false;
429 std::string interface;
430 std::map<std::string, std::variant<bool, uint8_t, uint64_t>>
431 ipsProperties{};
432 msg.read(interface, ipsProperties);
433
Chris Cain1be43372021-12-09 19:29:37 -0600434 // Read persisted values
435 bool ipsEnabled;
436 uint8_t enterUtil, exitUtil;
437 uint16_t enterTime, exitTime;
438 getIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime);
439
440 // Check for any changed data
Chris Cain1d51da22021-09-21 14:13:41 -0500441 auto ipsEntry = ipsProperties.find(IPS_ENABLED_PROP);
442 if (ipsEntry != ipsProperties.end())
443 {
Chris Cain1be43372021-12-09 19:29:37 -0600444 ipsEnabled = std::get<bool>(ipsEntry->second);
Chris Cain1d51da22021-09-21 14:13:41 -0500445 log<level::INFO>(
446 fmt::format("Idle Power Saver change: Enabled={}", ipsEnabled)
447 .c_str());
448 parmsChanged = true;
449 }
450 ipsEntry = ipsProperties.find(IPS_ENTER_UTIL);
451 if (ipsEntry != ipsProperties.end())
452 {
Chris Cain1be43372021-12-09 19:29:37 -0600453 enterUtil = std::get<uint8_t>(ipsEntry->second);
Chris Cain1d51da22021-09-21 14:13:41 -0500454 log<level::INFO>(
455 fmt::format("Idle Power Saver change: Enter Util={}%", enterUtil)
456 .c_str());
457 parmsChanged = true;
458 }
459 ipsEntry = ipsProperties.find(IPS_ENTER_TIME);
460 if (ipsEntry != ipsProperties.end())
461 {
462 std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second));
Chris Cain1be43372021-12-09 19:29:37 -0600463 enterTime =
Chris Cain1d51da22021-09-21 14:13:41 -0500464 std::chrono::duration_cast<std::chrono::seconds>(ms).count();
465 log<level::INFO>(
466 fmt::format("Idle Power Saver change: Enter Time={}sec", enterTime)
467 .c_str());
468 parmsChanged = true;
469 }
470 ipsEntry = ipsProperties.find(IPS_EXIT_UTIL);
471 if (ipsEntry != ipsProperties.end())
472 {
Chris Cain1be43372021-12-09 19:29:37 -0600473 exitUtil = std::get<uint8_t>(ipsEntry->second);
Chris Cain1d51da22021-09-21 14:13:41 -0500474 log<level::INFO>(
475 fmt::format("Idle Power Saver change: Exit Util={}%", exitUtil)
476 .c_str());
477 parmsChanged = true;
478 }
479 ipsEntry = ipsProperties.find(IPS_EXIT_TIME);
480 if (ipsEntry != ipsProperties.end())
481 {
482 std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second));
Chris Cain1be43372021-12-09 19:29:37 -0600483 exitTime = std::chrono::duration_cast<std::chrono::seconds>(ms).count();
Chris Cain1d51da22021-09-21 14:13:41 -0500484 log<level::INFO>(
485 fmt::format("Idle Power Saver change: Exit Time={}sec", exitTime)
486 .c_str());
487 parmsChanged = true;
488 }
489
490 if (parmsChanged)
491 {
Chris Caincde7bea2022-01-28 15:54:24 -0600492 if (exitUtil == 0)
493 {
494 // Setting the exitUtil to 0 will force restoring the default IPS
495 // parmeters (0 is not valid exit utilization)
496 log<level::INFO>(
497 "Idle Power Saver Exit Utilization is 0%. Restoring default parameters");
498 // Read the default IPS parameters, write persistent file and update
499 // DBus
500 useDefaultIPSParms();
501 }
502 else
503 {
504 // Update persistant data with new DBus values
505 persistedData.updateIPS(ipsEnabled, enterUtil, enterTime, exitUtil,
506 exitTime);
507 }
Chris Cain1be43372021-12-09 19:29:37 -0600508
509 // Trigger IPS data to get sent to the OCC
Chris Cain36f9cde2021-11-22 11:18:21 -0600510 sendIpsData();
Chris Cain1d51da22021-09-21 14:13:41 -0500511 }
512
513 return;
514}
515
Chris Cain1be43372021-12-09 19:29:37 -0600516/** @brief Get the Idle Power Saver properties from persisted data
517 * @return true if IPS parameters were read
Chris Cain36f9cde2021-11-22 11:18:21 -0600518 */
Chris Cain1be43372021-12-09 19:29:37 -0600519bool PowerMode::getIPSParms(bool& ipsEnabled, uint8_t& enterUtil,
520 uint16_t& enterTime, uint8_t& exitUtil,
521 uint16_t& exitTime)
Chris Cain36f9cde2021-11-22 11:18:21 -0600522{
Chris Cain36f9cde2021-11-22 11:18:21 -0600523 // Defaults:
Chris Cain1be43372021-12-09 19:29:37 -0600524 ipsEnabled = true; // Enabled
525 enterUtil = 8; // Enter Utilization (8%)
526 enterTime = 240; // Enter Delay Time (240s)
527 exitUtil = 12; // Exit Utilization (12%)
528 exitTime = 10; // Exit Delay Time (10s)
Chris Cain36f9cde2021-11-22 11:18:21 -0600529
Chris Cain1be43372021-12-09 19:29:37 -0600530 if (!persistedData.getIPS(ipsEnabled, enterUtil, enterTime, exitUtil,
531 exitTime))
532 {
533 // Persistent data not initialized, read defaults and update DBus
534 if (!initPersistentData())
535 {
536 // Unable to read defaults from entity manager yet
537 return false;
538 }
Chris Cain36f9cde2021-11-22 11:18:21 -0600539
Chris Cain1be43372021-12-09 19:29:37 -0600540 persistedData.getIPS(ipsEnabled, enterUtil, enterTime, exitUtil,
541 exitTime);
Chris Cain36f9cde2021-11-22 11:18:21 -0600542 }
543
544 if (enterUtil > exitUtil)
545 {
546 log<level::ERR>(
547 fmt::format(
548 "ERROR: Idle Power Saver Enter Utilization ({}%) is > Exit Utilization ({}%) - using Exit for both",
549 enterUtil, exitUtil)
550 .c_str());
551 enterUtil = exitUtil;
552 }
553
Chris Cain1be43372021-12-09 19:29:37 -0600554 return true;
555}
556
557// Set the Idle Power Saver data on DBus
558bool PowerMode::updateDbusIPS(const bool enabled, const uint8_t enterUtil,
559 const uint16_t enterTime, const uint8_t exitUtil,
560 const uint16_t exitTime)
561{
562 // true = skip update signal
563 IpsInterface::setPropertyByName(IPS_ENABLED_PROP, enabled, true);
564 IpsInterface::setPropertyByName(IPS_ENTER_UTIL, enterUtil, true);
565 // Convert time from seconds to ms
566 uint64_t msTime = enterTime * 1000;
567 IpsInterface::setPropertyByName(IPS_ENTER_TIME, msTime, true);
568 IpsInterface::setPropertyByName(IPS_EXIT_UTIL, exitUtil, true);
569 msTime = exitTime * 1000;
570 IpsInterface::setPropertyByName(IPS_EXIT_TIME, msTime, true);
571
572 return true;
Chris Cain36f9cde2021-11-22 11:18:21 -0600573}
574
575// Send Idle Power Saver config data to the master OCC
576CmdStatus PowerMode::sendIpsData()
577{
Chris Cain6fa848a2022-01-24 14:54:38 -0600578 if (!masterActive || !masterOccSet)
Chris Cain36f9cde2021-11-22 11:18:21 -0600579 {
580 // Nothing to do
581 return CmdStatus::SUCCESS;
582 }
583
584 if (!isPowerVM())
585 {
586 // Idle Power Saver data is only supported on PowerVM systems
587 log<level::DEBUG>(
588 "PowerMode::sendIpsData: SET_CFG_DATA[IPS] does not get sent on non-PowerVM systems");
589 return CmdStatus::SUCCESS;
590 }
591
Chris Cain1be43372021-12-09 19:29:37 -0600592 bool ipsEnabled;
Chris Cain36f9cde2021-11-22 11:18:21 -0600593 uint8_t enterUtil, exitUtil;
594 uint16_t enterTime, exitTime;
Chris Cain1be43372021-12-09 19:29:37 -0600595 getIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime);
Chris Cain36f9cde2021-11-22 11:18:21 -0600596
597 log<level::INFO>(
598 fmt::format(
599 "Idle Power Saver Parameters: enabled:{}, enter:{}%/{}s, exit:{}%/{}s",
600 ipsEnabled, enterUtil, enterTime, exitUtil, exitTime)
601 .c_str());
602
603 std::vector<std::uint8_t> cmd, rsp;
604 cmd.reserve(12);
605 cmd.push_back(uint8_t(CmdType::SET_CONFIG_DATA));
606 cmd.push_back(0x00); // Data Length (2 bytes)
607 cmd.push_back(0x09); //
608 cmd.push_back(0x11); // Config Format: IPS Settings
609 cmd.push_back(0x00); // Version
610 cmd.push_back(ipsEnabled ? 1 : 0); // IPS Enable
611 cmd.push_back(enterTime >> 8); // Enter Delay Time
612 cmd.push_back(enterTime & 0xFF); //
613 cmd.push_back(enterUtil); // Enter Utilization
614 cmd.push_back(exitTime >> 8); // Exit Delay Time
615 cmd.push_back(exitTime & 0xFF); //
616 cmd.push_back(exitUtil); // Exit Utilization
617 log<level::INFO>(fmt::format("PowerMode::sendIpsData: SET_CFG_DATA[IPS] "
618 "command to OCC{} ({} bytes)",
619 occInstance, cmd.size())
620 .c_str());
Chris Cain1be43372021-12-09 19:29:37 -0600621 CmdStatus status = occCmd->send(cmd, rsp);
Chris Cain36f9cde2021-11-22 11:18:21 -0600622 if (status == CmdStatus::SUCCESS)
623 {
624 if (rsp.size() == 5)
625 {
626 if (RspStatus::SUCCESS != RspStatus(rsp[2]))
627 {
628 log<level::ERR>(
629 fmt::format(
630 "PowerMode::sendIpsData: SET_CFG_DATA[IPS] failed with status 0x{:02X}",
631 rsp[2])
632 .c_str());
633 dump_hex(rsp);
634 status = CmdStatus::FAILURE;
635 }
636 }
637 else
638 {
639 log<level::ERR>(
640 "PowerMode::sendIpsData: INVALID SET_CFG_DATA[IPS] response");
641 dump_hex(rsp);
642 status = CmdStatus::FAILURE;
643 }
644 }
645 else
646 {
Chris Cainc567dc82022-04-01 15:09:17 -0500647 log<level::ERR>(
648 fmt::format(
649 "PowerMode::sendIpsData: SET_CFG_DATA[IPS] with status={}",
650 status)
651 .c_str());
Chris Cain36f9cde2021-11-22 11:18:21 -0600652 }
653
654 return status;
655}
656
Chris Caincde7bea2022-01-28 15:54:24 -0600657// Print the current values
Chris Cain1be43372021-12-09 19:29:37 -0600658void OccPersistData::print()
Chris Cain36f9cde2021-11-22 11:18:21 -0600659{
Chris Cain1be43372021-12-09 19:29:37 -0600660 if (modeData.modeInitialized)
661 {
662 log<level::INFO>(
663 fmt::format(
Ben Tyner3576d652022-05-22 18:05:53 -0500664 "OccPersistData: Mode: 0x{:02X}, OEM Mode Data: {} (0x{:04X} Locked{})",
665 modeData.mode, modeData.oemModeData, modeData.oemModeData,
666 modeData.modeLocked)
Chris Cain1be43372021-12-09 19:29:37 -0600667 .c_str());
668 }
669 if (modeData.ipsInitialized)
670 {
671 log<level::INFO>(
672 fmt::format(
673 "OccPersistData: IPS enabled:{}, enter:{}%/{}s, exit:{}%/{}s",
674 modeData.ipsEnabled, modeData.ipsEnterUtil,
675 modeData.ipsEnterTime, modeData.ipsExitUtil,
676 modeData.ipsExitTime)
677 .c_str());
678 }
Chris Cain36f9cde2021-11-22 11:18:21 -0600679}
680
681// Saves the OEM mode data in the filesystem using cereal.
682void OccPersistData::save()
683{
684 std::filesystem::path opath =
Chris Cain1be43372021-12-09 19:29:37 -0600685 std::filesystem::path{OCC_CONTROL_PERSIST_PATH} / powerModeFilename;
Chris Cain36f9cde2021-11-22 11:18:21 -0600686
687 if (!std::filesystem::exists(opath.parent_path()))
688 {
689 std::filesystem::create_directory(opath.parent_path());
690 }
691
692 log<level::DEBUG>(
Chris Cain1be43372021-12-09 19:29:37 -0600693 fmt::format(
694 "OccPersistData::save: Writing Power Mode persisted data to {}",
695 opath.c_str())
Chris Cain36f9cde2021-11-22 11:18:21 -0600696 .c_str());
Chris Caincde7bea2022-01-28 15:54:24 -0600697 // print();
Chris Cain36f9cde2021-11-22 11:18:21 -0600698
699 std::ofstream stream{opath.c_str()};
700 cereal::JSONOutputArchive oarchive{stream};
701
Chris Cain1be43372021-12-09 19:29:37 -0600702 oarchive(modeData);
Chris Cain36f9cde2021-11-22 11:18:21 -0600703}
704
705// Loads the OEM mode data in the filesystem using cereal.
706void OccPersistData::load()
707{
Chris Cain36f9cde2021-11-22 11:18:21 -0600708 std::filesystem::path ipath =
Chris Cain1be43372021-12-09 19:29:37 -0600709 std::filesystem::path{OCC_CONTROL_PERSIST_PATH} / powerModeFilename;
Chris Cain36f9cde2021-11-22 11:18:21 -0600710
711 if (!std::filesystem::exists(ipath))
712 {
Chris Cain1be43372021-12-09 19:29:37 -0600713 modeData.modeInitialized = false;
714 modeData.ipsInitialized = false;
Chris Cain36f9cde2021-11-22 11:18:21 -0600715 return;
716 }
717
718 log<level::DEBUG>(
Chris Cain1be43372021-12-09 19:29:37 -0600719 fmt::format(
720 "OccPersistData::load: Reading Power Mode persisted data from {}",
721 ipath.c_str())
Chris Cain36f9cde2021-11-22 11:18:21 -0600722 .c_str());
723 try
724 {
725 std::ifstream stream{ipath.c_str()};
726 cereal::JSONInputArchive iarchive(stream);
Chris Cain1be43372021-12-09 19:29:37 -0600727 iarchive(modeData);
Chris Cain36f9cde2021-11-22 11:18:21 -0600728 }
729 catch (const std::exception& e)
730 {
731 auto error = errno;
732 log<level::ERR>(
733 fmt::format("OccPersistData::load: failed to read {}, errno={}",
734 ipath.c_str(), error)
735 .c_str());
Chris Cain1be43372021-12-09 19:29:37 -0600736 modeData.modeInitialized = false;
737 modeData.ipsInitialized = false;
Chris Cain36f9cde2021-11-22 11:18:21 -0600738 }
739
Chris Caincde7bea2022-01-28 15:54:24 -0600740 // print();
Chris Cain36f9cde2021-11-22 11:18:21 -0600741}
742
Chris Cain1be43372021-12-09 19:29:37 -0600743// Called when PowerModeProperties defaults are available on DBus
Patrick Williamsaf408082022-07-22 19:26:54 -0500744void PowerMode::defaultsReady(sdbusplus::message_t& msg)
Chris Cain36f9cde2021-11-22 11:18:21 -0600745{
Chris Cain1be43372021-12-09 19:29:37 -0600746 std::map<std::string, std::variant<std::string>> properties{};
747 std::string interface;
748 msg.read(interface, properties);
Chris Cain36f9cde2021-11-22 11:18:21 -0600749
Chris Cain1be43372021-12-09 19:29:37 -0600750 // If persistent data exists, then don't need to read defaults
751 if ((!persistedData.modeAvailable()) || (!persistedData.ipsAvailable()))
Chris Cain36f9cde2021-11-22 11:18:21 -0600752 {
Chris Cain1be43372021-12-09 19:29:37 -0600753 log<level::INFO>(
754 fmt::format(
755 "Default PowerModeProperties are now available (persistent modeAvail={}, ipsAvail={})",
756 persistedData.modeAvailable() ? 'y' : 'n',
757 persistedData.modeAvailable() ? 'y' : 'n')
758 .c_str());
759
760 // Read default power mode defaults and update DBus
761 initPersistentData();
762 }
763}
764
765// Get the default power mode from DBus and return true if success
766bool PowerMode::getDefaultMode(SysPwrMode& defaultMode)
767{
768 try
769 {
770 auto& bus = utils::getBus();
771 std::string path = "/";
772 std::string service =
773 utils::getServiceUsingSubTree(PMODE_DEFAULT_INTERFACE, path);
Patrick Williamsa49c9872023-05-10 07:50:35 -0500774 auto method = bus.new_method_call(service.c_str(), path.c_str(),
775 "org.freedesktop.DBus.Properties",
776 "Get");
Chris Cain1be43372021-12-09 19:29:37 -0600777 method.append(PMODE_DEFAULT_INTERFACE, "PowerMode");
778 auto reply = bus.call(method);
779
780 std::variant<std::string> stateEntryValue;
781 reply.read(stateEntryValue);
782 auto propVal = std::get<std::string>(stateEntryValue);
783
Patrick Williamsa49c9872023-05-10 07:50:35 -0500784 const std::string fullModeString = PMODE_INTERFACE + ".PowerMode."s +
785 propVal;
Chris Cain1be43372021-12-09 19:29:37 -0600786 defaultMode = powermode::convertStringToMode(fullModeString);
787 if (!VALID_POWER_MODE_SETTING(defaultMode))
788 {
789 log<level::ERR>(
790 fmt::format(
791 "PowerMode::getDefaultMode: Invalid default power mode found: {}",
792 defaultMode)
793 .c_str());
794 // If default was read but not valid, use Max Performance
795 defaultMode = SysPwrMode::MAX_PERF;
796 return true;
797 }
798 }
Patrick Williamsaf408082022-07-22 19:26:54 -0500799 catch (const sdbusplus::exception_t& e)
Chris Cain1be43372021-12-09 19:29:37 -0600800 {
801 log<level::ERR>(
802 fmt::format("Unable to read Default Power Mode: {}", e.what())
803 .c_str());
804 return false;
Chris Cain36f9cde2021-11-22 11:18:21 -0600805 }
806
Chris Cain1be43372021-12-09 19:29:37 -0600807 return true;
808}
Chris Cain36f9cde2021-11-22 11:18:21 -0600809
Chris Cain1be43372021-12-09 19:29:37 -0600810/* Get the default Idle Power Saver properties and return true if successful */
811bool PowerMode::getDefaultIPSParms(bool& ipsEnabled, uint8_t& enterUtil,
812 uint16_t& enterTime, uint8_t& exitUtil,
813 uint16_t& exitTime)
814{
815 // Defaults:
816 ipsEnabled = true; // Enabled
817 enterUtil = 8; // Enter Utilization (8%)
818 enterTime = 240; // Enter Delay Time (240s)
819 exitUtil = 12; // Exit Utilization (12%)
820 exitTime = 10; // Exit Delay Time (10s)
821
822 std::map<std::string, std::variant<bool, uint8_t, uint16_t, uint64_t>>
823 ipsProperties{};
824
825 // Get all IPS properties from DBus
826 try
827 {
828 auto& bus = utils::getBus();
829 std::string path = "/";
830 std::string service =
831 utils::getServiceUsingSubTree(PMODE_DEFAULT_INTERFACE, path);
Patrick Williamsa49c9872023-05-10 07:50:35 -0500832 auto method = bus.new_method_call(service.c_str(), path.c_str(),
833 "org.freedesktop.DBus.Properties",
834 "GetAll");
Chris Cain1be43372021-12-09 19:29:37 -0600835 method.append(PMODE_DEFAULT_INTERFACE);
836 auto reply = bus.call(method);
837 reply.read(ipsProperties);
838 }
Patrick Williamsaf408082022-07-22 19:26:54 -0500839 catch (const sdbusplus::exception_t& e)
Chris Cain1be43372021-12-09 19:29:37 -0600840 {
841 log<level::ERR>(
842 fmt::format(
843 "Unable to read Default Idle Power Saver parameters so it will be disabled: {}",
844 e.what())
845 .c_str());
846 return false;
847 }
848
849 auto ipsEntry = ipsProperties.find("IdlePowerSaverEnabled");
850 if (ipsEntry != ipsProperties.end())
851 {
852 ipsEnabled = std::get<bool>(ipsEntry->second);
853 }
854 else
855 {
856 log<level::ERR>(
857 "PowerMode::getDefaultIPSParms could not find property: IdlePowerSaverEnabled");
858 }
859
860 ipsEntry = ipsProperties.find("EnterUtilizationPercent");
861 if (ipsEntry != ipsProperties.end())
862 {
863 enterUtil = std::get<uint64_t>(ipsEntry->second);
864 }
865 else
866 {
867 log<level::ERR>(
868 "PowerMode::getDefaultIPSParms could not find property: EnterUtilizationPercent");
869 }
870
871 ipsEntry = ipsProperties.find("EnterUtilizationDwellTime");
872 if (ipsEntry != ipsProperties.end())
873 {
874 enterTime = std::get<uint64_t>(ipsEntry->second);
875 }
876 else
877 {
878 log<level::ERR>(
879 "PowerMode::getDefaultIPSParms could not find property: EnterUtilizationDwellTime");
880 }
881
882 ipsEntry = ipsProperties.find("ExitUtilizationPercent");
883 if (ipsEntry != ipsProperties.end())
884 {
885 exitUtil = std::get<uint64_t>(ipsEntry->second);
886 }
887 else
888 {
889 log<level::ERR>(
890 "PowerMode::getDefaultIPSParms could not find property: ExitUtilizationPercent");
891 }
892
893 ipsEntry = ipsProperties.find("ExitUtilizationDwellTime");
894 if (ipsEntry != ipsProperties.end())
895 {
896 exitTime = std::get<uint64_t>(ipsEntry->second);
897 }
898 else
899 {
900 log<level::ERR>(
901 "PowerMode::getDefaultIPSParms could not find property: ExitUtilizationDwellTime");
902 }
903
904 if (enterUtil > exitUtil)
905 {
906 log<level::ERR>(
907 fmt::format(
908 "ERROR: Default Idle Power Saver Enter Utilization ({}%) is > Exit Utilization ({}%) - using Exit for both",
909 enterUtil, exitUtil)
910 .c_str());
911 enterUtil = exitUtil;
912 }
913
914 return true;
Chris Cain36f9cde2021-11-22 11:18:21 -0600915}
916
Chris Caincde7bea2022-01-28 15:54:24 -0600917/* Read default IPS parameters, save them to the persistent file and update
918 DBus. Return true if successful */
919bool PowerMode::useDefaultIPSParms()
920{
921 // Read the default IPS parameters
922 bool ipsEnabled;
923 uint8_t enterUtil, exitUtil;
924 uint16_t enterTime, exitTime;
925 if (!getDefaultIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil,
926 exitTime))
927 {
928 // Unable to read defaults
929 return false;
930 }
931 log<level::INFO>(
932 fmt::format(
933 "PowerMode::useDefaultIPSParms: Using default IPS parms: Enabled: {}, EnterUtil: {}%, EnterTime: {}s, ExitUtil: {}%, ExitTime: {}s",
934 ipsEnabled, enterUtil, enterTime, exitUtil, exitTime)
935 .c_str());
936
937 // Save IPS parms to the persistent file
938 persistedData.updateIPS(ipsEnabled, enterUtil, enterTime, exitUtil,
939 exitTime);
940
941 // Write IPS parms to DBus
942 return updateDbusIPS(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime);
943}
944
Sheldon Baileyea2b22e2022-04-04 12:24:46 -0500945#ifdef POWER10
946
947// Starts to watch for IPS active state changes.
948bool PowerMode::openIpsFile()
949{
950 bool rc = true;
951 fd = open(ipsStatusFile.c_str(), O_RDONLY | O_NONBLOCK);
952 const int open_errno = errno;
953 if (fd < 0)
954 {
955 log<level::ERR>(fmt::format("openIpsFile Error({})={} : File={}",
956 open_errno, strerror(open_errno),
957 ipsStatusFile.c_str())
958 .c_str());
959
960 close(fd);
961
962 using namespace sdbusplus::org::open_power::OCC::Device::Error;
963 report<OpenFailure>(
964 phosphor::logging::org::open_power::OCC::Device::OpenFailure::
965 CALLOUT_ERRNO(open_errno),
966 phosphor::logging::org::open_power::OCC::Device::OpenFailure::
967 CALLOUT_DEVICE_PATH(ipsStatusFile.c_str()));
968
969 // We are no longer watching the error
970 active(false);
971
972 watching = false;
973 rc = false;
974 // NOTE: this will leave the system not reporting IPS active state to
975 // Fan Controls, Until an APP reload, or IPL and we will attempt again.
976 }
977 return rc;
978}
979
980// Starts to watch for IPS active state changes.
981void PowerMode::addIpsWatch(bool poll)
982{
983 // open file and register callback on file if we are not currently watching,
984 // and if poll=true, and if we are the master.
985 if ((!watching) && poll)
986 {
987 // Open the file
988 if (openIpsFile())
989 {
990 // register the callback handler which sets 'watching'
991 registerIpsStatusCallBack();
992 }
993 }
994}
995
996// Stops watching for IPS active state changes.
997void PowerMode::removeIpsWatch()
998{
999 // NOTE: we want to remove event, close file, and IPS active false no
1000 // matter what the 'watching' flags is set to.
1001
1002 // We are no longer watching the error
1003 active(false);
1004
1005 watching = false;
1006
1007 // Close file
1008 close(fd);
1009
1010 // clears sourcePtr in the event source.
1011 eventSource.reset();
1012}
1013
1014// Attaches the FD to event loop and registers the callback handler
1015void PowerMode::registerIpsStatusCallBack()
1016{
1017 decltype(eventSource.get()) sourcePtr = nullptr;
1018
1019 auto r = sd_event_add_io(event.get(), &sourcePtr, fd, EPOLLPRI | EPOLLERR,
1020 ipsStatusCallBack, this);
1021 if (r < 0)
1022 {
1023 log<level::ERR>(fmt::format("sd_event_add_io: Error({})={} : File={}",
1024 r, strerror(-r), ipsStatusFile.c_str())
1025 .c_str());
1026
1027 using InternalFailure =
1028 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
1029 report<InternalFailure>();
1030
1031 removeIpsWatch();
1032 // NOTE: this will leave the system not reporting IPS active state to
1033 // Fan Controls, Until an APP reload, or IPL and we will attempt again.
1034 }
1035 else
1036 {
1037 // puts sourcePtr in the event source.
1038 eventSource.reset(sourcePtr);
1039 // Set we are watching the error
1040 watching = true;
1041 }
1042}
1043
1044// Static function to redirect to non static analyze event function to be
1045// able to read file and push onto dBus.
1046int PowerMode::ipsStatusCallBack(sd_event_source* /*es*/, int /*fd*/,
1047 uint32_t /*revents*/, void* userData)
1048{
1049 auto pmode = static_cast<PowerMode*>(userData);
1050 pmode->analyzeIpsEvent();
1051 return 0;
1052}
1053
1054// Function to Read SysFs file change on IPS state and push on dBus.
1055void PowerMode::analyzeIpsEvent()
1056{
1057 // Need to seek to START, else the poll returns immediately telling
1058 // there is data to be read. if not done this floods the system.
1059 auto r = lseek(fd, 0, SEEK_SET);
1060 const int open_errno = errno;
1061 if (r < 0)
1062 {
1063 // NOTE: upon file access error we can not just re-open file, we have to
1064 // remove and add to watch.
1065 removeIpsWatch();
1066 addIpsWatch(true);
1067 }
1068
1069 // if we are 'watching' that is the file seek, or the re-open passed.. we
1070 // can read the data
1071 if (watching)
1072 {
1073 // This file gets created when polling OCCs. A value or length of 0 is
1074 // deemed success. That means we would disable IPS active on dbus.
1075 char data;
1076 bool ipsState = false;
1077 const auto len = read(fd, &data, sizeof(data));
1078 const int readErrno = errno;
1079 if (len <= 0)
1080 {
1081 removeIpsWatch();
1082
1083 log<level::ERR>(
1084 fmt::format("IPS state Read Error({})={} : File={} : len={}",
1085 readErrno, strerror(readErrno),
1086 ipsStatusFile.c_str(), len)
1087 .c_str());
1088
1089 report<ReadFailure>(
1090 phosphor::logging::org::open_power::OCC::Device::ReadFailure::
1091 CALLOUT_ERRNO(readErrno),
1092 phosphor::logging::org::open_power::OCC::Device::ReadFailure::
1093 CALLOUT_DEVICE_PATH(ipsStatusFile.c_str()));
1094
1095 // NOTE: this will leave the system not reporting IPS active state
1096 // to Fan Controls, Until an APP reload, or IPL and we will attempt
1097 // again.
1098 }
1099 else
1100 {
1101 // Data returned in ASCII.
1102 // convert to integer. atoi()
1103 // from OCC_P10_FW_Interfaces spec
1104 // Bit 6: IPS active 1 indicates enabled.
1105 // Bit 7: IPS enabled. 1 indicates enabled.
1106 // mask off bit 6 --> & 0x02
1107 // Shift left one bit and store as bool. >> 1
1108 ipsState = static_cast<bool>(((atoi(&data)) & 0x2) >> 1);
1109 }
1110
1111 // This will only set IPS active dbus if different than current.
1112 active(ipsState);
1113 }
1114 else
1115 {
1116 removeIpsWatch();
1117
1118 // If the Retry did not get to "watching = true" we already have an
1119 // error log, just post trace.
1120 log<level::ERR>(fmt::format("Retry on File seek Error({})={} : File={}",
1121 open_errno, strerror(open_errno),
1122 ipsStatusFile.c_str())
1123 .c_str());
1124
1125 // NOTE: this will leave the system not reporting IPS active state to
1126 // Fan Controls, Until an APP reload, or IPL and we will attempt again.
1127 }
1128
1129 return;
1130}
Ben Tyner3576d652022-05-22 18:05:53 -05001131
1132// overrides read/write to powerMode dbus property.
1133Mode::PowerMode PowerMode::powerMode(Mode::PowerMode value)
1134{
1135 if (persistedData.getModeLock())
1136 {
1137 log<level::INFO>("PowerMode::powerMode: mode property change blocked");
1138 elog<NotAllowed>(xyz::openbmc_project::Common::NotAllowed::REASON(
1139 "mode change not allowed due to lock"));
1140 return value;
1141 }
1142 else
1143 {
1144 return Mode::powerMode(value);
1145 }
1146}
Sheldon Baileyea2b22e2022-04-04 12:24:46 -05001147#endif
1148
Sheldon Bailey31a2f132022-05-20 11:31:52 -05001149/* Set dbus property to SAFE mode(true) or clear(false) only if different */
1150void PowerMode::updateDbusSafeMode(const bool safeModeReq)
1151{
1152 log<level::DEBUG>(
1153 fmt::format("PowerMode:updateDbusSafeMode: Update dbus state ({})",
1154 safeModeReq)
1155 .c_str());
1156
1157 // Note; this function checks and only updates if different.
1158 Mode::safeMode(safeModeReq);
1159}
1160
Chris Cain78e86012021-03-04 16:15:31 -06001161} // namespace powermode
1162
1163} // namespace occ
1164
1165} // namespace open_power