blob: 9b9f3cb17304278576608f107434165986adf317 [file] [log] [blame]
Chris Cain36f9cde2021-11-22 11:18:21 -06001#include "powermode.hpp"
2
Chris Cain78e86012021-03-04 16:15:31 -06003#include <fmt/core.h>
4
Chris Cain36f9cde2021-11-22 11:18:21 -06005#include <com/ibm/Host/Target/server.hpp>
Chris Cain78e86012021-03-04 16:15:31 -06006#include <phosphor-logging/log.hpp>
Chris Cain78e86012021-03-04 16:15:31 -06007#include <xyz/openbmc_project/Control/Power/Mode/server.hpp>
8
George Liub5ca1012021-09-10 12:53:11 +08009#include <cassert>
Chris Cain36f9cde2021-11-22 11:18:21 -060010#include <fstream>
George Liub5ca1012021-09-10 12:53:11 +080011#include <regex>
12
Chris Cain78e86012021-03-04 16:15:31 -060013namespace open_power
14{
15namespace occ
16{
17namespace powermode
18{
19
20using namespace phosphor::logging;
21using Mode = sdbusplus::xyz::openbmc_project::Control::Power::server::Mode;
22
Chris Cain6fa848a2022-01-24 14:54:38 -060023// Set the Master OCC
24void PowerMode::setMasterOcc(const std::string& occPath)
25{
26 path = occPath;
27 occInstance = path.back() - '0';
28 log<level::DEBUG>(fmt::format("PowerMode::setMasterOcc(OCC{}, {})",
29 occInstance, path.c_str())
30 .c_str());
31 occCmd = std::make_unique<open_power::occ::OccCommand>(occInstance,
32 path.c_str());
33 masterOccSet = true;
34};
35
Chris Cain36f9cde2021-11-22 11:18:21 -060036// Called when DBus power mode gets changed
Chris Cain78e86012021-03-04 16:15:31 -060037void PowerMode::modeChanged(sdbusplus::message::message& msg)
38{
Chris Cain78e86012021-03-04 16:15:31 -060039 std::map<std::string, std::variant<std::string>> properties{};
40 std::string interface;
41 std::string propVal;
42 msg.read(interface, properties);
43 const auto modeEntry = properties.find(POWER_MODE_PROP);
44 if (modeEntry != properties.end())
45 {
46 auto modeEntryValue = modeEntry->second;
47 propVal = std::get<std::string>(modeEntryValue);
Chris Cain6fa848a2022-01-24 14:54:38 -060048 SysPwrMode newMode = convertStringToMode(propVal);
Chris Cain36f9cde2021-11-22 11:18:21 -060049 if (newMode != SysPwrMode::NO_CHANGE)
Chris Cain78e86012021-03-04 16:15:31 -060050 {
Chris Cain36f9cde2021-11-22 11:18:21 -060051 // DBus mode changed, get rid of any OEM mode if set
52 persistedData.purge();
53
Chris Cain78e86012021-03-04 16:15:31 -060054 log<level::INFO>(
55 fmt::format("Power Mode Change Requested: {}", propVal)
56 .c_str());
57
Chris Cain36f9cde2021-11-22 11:18:21 -060058 // Send mode change to OCC
59 sendModeChange();
60 }
61 }
62}
63
64// Called from OCC PassThrough interface (via CE login / BMC command line)
65bool PowerMode::setMode(const SysPwrMode newMode, const uint16_t modeData)
66{
67 if (updateDbusMode(newMode) == false)
68 {
69 // Unsupported mode
70 return false;
71 }
72
73 // If new mode is valid customer mode, the DBus update will trigger the mode
74 // change request to OCC. For OEM modes, the request will be sent here.
75 if (VALID_OEM_POWER_MODE_SETTING(newMode))
76 {
77 // Save OEM mode
78 persistedData.writeModeFile(newMode, modeData);
79
80 // Send mode change to OCC
81 if (sendModeChange() != CmdStatus::SUCCESS)
82 {
83 // Mode change failed
84 return false;
Chris Cain78e86012021-03-04 16:15:31 -060085 }
86 }
87
Chris Cain36f9cde2021-11-22 11:18:21 -060088 return true;
Chris Cain78e86012021-03-04 16:15:31 -060089}
90
91// Convert PowerMode string to OCC SysPwrMode
Chris Cain36f9cde2021-11-22 11:18:21 -060092// Returns NO_CHANGE if OEM or unsupported mode
Chris Cain78e86012021-03-04 16:15:31 -060093SysPwrMode convertStringToMode(const std::string& i_modeString)
94{
95 SysPwrMode pmode = SysPwrMode::NO_CHANGE;
96
97 Mode::PowerMode mode = Mode::convertPowerModeFromString(i_modeString);
98 if (mode == Mode::PowerMode::MaximumPerformance)
99 {
100 pmode = SysPwrMode::MAX_PERF;
101 }
102 else if (mode == Mode::PowerMode::PowerSaving)
103 {
104 pmode = SysPwrMode::POWER_SAVING;
105 }
106 else if (mode == Mode::PowerMode::Static)
107 {
Chris Cain36f9cde2021-11-22 11:18:21 -0600108 pmode = SysPwrMode::STATIC;
Chris Cain78e86012021-03-04 16:15:31 -0600109 }
110 else
111 {
Chris Cain36f9cde2021-11-22 11:18:21 -0600112 if (mode != Mode::PowerMode::OEM)
113 {
114 log<level::ERR>(
115 fmt::format(
116 "convertStringToMode: Invalid Power Mode specified: {}",
117 i_modeString)
118 .c_str());
119 }
Chris Cain78e86012021-03-04 16:15:31 -0600120 }
121
122 return pmode;
123}
124
Chris Cain36f9cde2021-11-22 11:18:21 -0600125// Check if Hypervisor target is PowerVM
126bool isPowerVM()
Chris Cain1d51da22021-09-21 14:13:41 -0500127{
Chris Cain36f9cde2021-11-22 11:18:21 -0600128 using namespace open_power::occ::powermode;
129 namespace Hyper = sdbusplus::com::ibm::Host::server;
130 constexpr auto HYPE_PATH = "/com/ibm/host0/hypervisor";
131 constexpr auto HYPE_INTERFACE = "com.ibm.Host.Target";
132 constexpr auto HYPE_PROP = "Target";
133
134 bool powerVmTarget = false;
135
136 // This will throw exception on failure
137 auto& bus = utils::getBus();
138 auto service = utils::getService(HYPE_PATH, HYPE_INTERFACE);
139 auto method = bus.new_method_call(service.c_str(), HYPE_PATH,
140 "org.freedesktop.DBus.Properties", "Get");
141 method.append(HYPE_INTERFACE, HYPE_PROP);
142 auto reply = bus.call(method);
143
144 std::variant<std::string> hyperEntryValue;
145 reply.read(hyperEntryValue);
146 auto propVal = std::get<std::string>(hyperEntryValue);
147 if (Hyper::Target::convertHypervisorFromString(propVal) ==
148 Hyper::Target::Hypervisor::PowerVM)
149 {
150 powerVmTarget = true;
151 }
152
153 log<level::DEBUG>(
154 fmt::format("isPowerVM returning {}", powerVmTarget).c_str());
155
156 return powerVmTarget;
157}
158
159// Get the requested power mode from DBus
160SysPwrMode PowerMode::getDbusMode()
161{
162 using namespace open_power::occ::powermode;
Chris Cain6fa848a2022-01-24 14:54:38 -0600163 SysPwrMode currentMode;
Chris Cain36f9cde2021-11-22 11:18:21 -0600164
165 // This will throw exception on failure
166 auto& bus = utils::getBus();
167 auto service = utils::getService(PMODE_PATH, PMODE_INTERFACE);
168 auto method = bus.new_method_call(service.c_str(), PMODE_PATH,
169 "org.freedesktop.DBus.Properties", "Get");
170 method.append(PMODE_INTERFACE, POWER_MODE_PROP);
171 auto reply = bus.call(method);
172
173 std::variant<std::string> stateEntryValue;
174 reply.read(stateEntryValue);
175 auto propVal = std::get<std::string>(stateEntryValue);
176
177 currentMode = powermode::convertStringToMode(propVal);
178 if (!VALID_POWER_MODE_SETTING(currentMode))
179 {
180 log<level::ERR>(
181 fmt::format(
182 "PowerMode::getDbusMode Invalid power mode found on DBus: {}",
183 currentMode)
184 .c_str());
185 currentMode = SysPwrMode::NO_CHANGE;
186 }
187
188 return currentMode;
189}
190
191// Set the power mode on DBus
192bool PowerMode::updateDbusMode(const SysPwrMode newMode)
193{
194 using namespace open_power::occ::powermode;
195 using namespace std::literals::string_literals;
196
197 if (!VALID_POWER_MODE_SETTING(newMode) &&
198 !VALID_OEM_POWER_MODE_SETTING(newMode))
199 {
200 log<level::ERR>(
201 fmt::format(
202 "PowerMode::updateDbusMode - Requested power mode not supported: {}",
203 newMode)
204 .c_str());
205 return false;
206 }
207
208 // Mode::PowerMode dBusMode;
209 std::string dBusMode;
210 switch (newMode)
211 {
212 case SysPwrMode::STATIC:
213 dBusMode = PMODE_INTERFACE + ".PowerMode.Static"s;
214 break;
215 case SysPwrMode::POWER_SAVING:
216 dBusMode = PMODE_INTERFACE + ".PowerMode.PowerSaving"s;
217 break;
218 case SysPwrMode::MAX_PERF:
219 dBusMode = PMODE_INTERFACE + ".PowerMode.MaximumPerformance"s;
220 break;
221 default:
222 dBusMode = PMODE_INTERFACE + ".PowerMode.OEM"s;
223 }
224
225 utils::setProperty(PMODE_PATH, PMODE_INTERFACE, POWER_MODE_PROP,
226 std::move(dBusMode));
227
228 return true;
229}
230
231// Send mode change request to the master OCC
232CmdStatus PowerMode::sendModeChange()
233{
Chris Cain6fa848a2022-01-24 14:54:38 -0600234 CmdStatus status;
Chris Cain36f9cde2021-11-22 11:18:21 -0600235
Chris Cain6fa848a2022-01-24 14:54:38 -0600236 if (!masterActive || !masterOccSet)
Chris Cain36f9cde2021-11-22 11:18:21 -0600237 {
238 // Nothing to do
Chris Cain6fa848a2022-01-24 14:54:38 -0600239 log<level::DEBUG>("PowerMode::sendModeChange: OCC master not active");
Chris Cain36f9cde2021-11-22 11:18:21 -0600240 return CmdStatus::SUCCESS;
241 }
242
243 if (!isPowerVM())
244 {
245 // Mode change is only supported on PowerVM systems
246 log<level::DEBUG>(
247 "PowerMode::sendModeChange: MODE CHANGE does not get sent on non-PowerVM systems");
248 return CmdStatus::SUCCESS;
249 }
250
251 // Use OEM power mode if it was set
252 SysPwrMode newMode = SysPwrMode::NO_CHANGE;
253 uint16_t modeData = 0;
254 if (persistedData.getOemMode(newMode, modeData) == false)
255 {
256 // Read customer power mode from Dbus
257 newMode = getDbusMode();
258 }
259
260 if (VALID_POWER_MODE_SETTING(newMode) ||
261 VALID_OEM_POWER_MODE_SETTING(newMode))
262 {
263 std::vector<std::uint8_t> cmd, rsp;
264 cmd.reserve(9);
265 cmd.push_back(uint8_t(CmdType::SET_MODE_AND_STATE));
266 cmd.push_back(0x00); // Data Length (2 bytes)
267 cmd.push_back(0x06);
268 cmd.push_back(0x30); // Data (Version)
269 cmd.push_back(uint8_t(OccState::NO_CHANGE));
270 cmd.push_back(uint8_t(newMode));
271 cmd.push_back(modeData >> 8); // Mode Data (Freq Point)
272 cmd.push_back(modeData & 0xFF); //
273 cmd.push_back(0x00); // reserved
274 log<level::INFO>(
275 fmt::format(
276 "PowerMode::sendModeChange: SET_MODE({},{}) command to OCC{} ({} bytes)",
277 newMode, modeData, occInstance, cmd.size())
278 .c_str());
Chris Cain6fa848a2022-01-24 14:54:38 -0600279 status = occCmd->send(cmd, rsp);
Chris Cain36f9cde2021-11-22 11:18:21 -0600280 if (status == CmdStatus::SUCCESS)
281 {
282 if (rsp.size() == 5)
283 {
284 if (RspStatus::SUCCESS != RspStatus(rsp[2]))
285 {
286 log<level::ERR>(
287 fmt::format(
288 "PowerMode::sendModeChange: SET MODE failed with status 0x{:02X}",
289 rsp[2])
290 .c_str());
291 dump_hex(rsp);
292 status = CmdStatus::FAILURE;
293 }
294 }
295 else
296 {
297 log<level::ERR>(
298 "PowerMode::sendModeChange: INVALID SET MODE response");
299 dump_hex(rsp);
300 status = CmdStatus::FAILURE;
301 }
302 }
303 else
304 {
305 if (status == CmdStatus::OPEN_FAILURE)
306 {
307 // OCC not active yet
308 status = CmdStatus::SUCCESS;
309 }
310 else
311 {
312 log<level::ERR>("PowerMode::sendModeChange: SET_MODE FAILED!");
313 }
314 }
315 }
316 else
317 {
318 log<level::ERR>(
319 fmt::format(
320 "PowerMode::sendModeChange: Unable to set power mode to {}",
321 newMode)
322 .c_str());
323 status = CmdStatus::FAILURE;
324 }
325
326 return status;
327}
328
329void PowerMode::ipsChanged(sdbusplus::message::message& msg)
330{
Chris Cain6fa848a2022-01-24 14:54:38 -0600331 if (!masterActive || !masterOccSet)
Chris Cain1d51da22021-09-21 14:13:41 -0500332 {
333 // Nothing to do
334 return;
335 }
336
337 bool parmsChanged = false;
338 std::string interface;
339 std::map<std::string, std::variant<bool, uint8_t, uint64_t>>
340 ipsProperties{};
341 msg.read(interface, ipsProperties);
342
343 auto ipsEntry = ipsProperties.find(IPS_ENABLED_PROP);
344 if (ipsEntry != ipsProperties.end())
345 {
346 const auto ipsEnabled = std::get<bool>(ipsEntry->second);
347 log<level::INFO>(
348 fmt::format("Idle Power Saver change: Enabled={}", ipsEnabled)
349 .c_str());
350 parmsChanged = true;
351 }
352 ipsEntry = ipsProperties.find(IPS_ENTER_UTIL);
353 if (ipsEntry != ipsProperties.end())
354 {
355 const auto enterUtil = std::get<uint8_t>(ipsEntry->second);
356 log<level::INFO>(
357 fmt::format("Idle Power Saver change: Enter Util={}%", enterUtil)
358 .c_str());
359 parmsChanged = true;
360 }
361 ipsEntry = ipsProperties.find(IPS_ENTER_TIME);
362 if (ipsEntry != ipsProperties.end())
363 {
364 std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second));
365 const auto enterTime =
366 std::chrono::duration_cast<std::chrono::seconds>(ms).count();
367 log<level::INFO>(
368 fmt::format("Idle Power Saver change: Enter Time={}sec", enterTime)
369 .c_str());
370 parmsChanged = true;
371 }
372 ipsEntry = ipsProperties.find(IPS_EXIT_UTIL);
373 if (ipsEntry != ipsProperties.end())
374 {
375 const auto exitUtil = std::get<uint8_t>(ipsEntry->second);
376 log<level::INFO>(
377 fmt::format("Idle Power Saver change: Exit Util={}%", exitUtil)
378 .c_str());
379 parmsChanged = true;
380 }
381 ipsEntry = ipsProperties.find(IPS_EXIT_TIME);
382 if (ipsEntry != ipsProperties.end())
383 {
384 std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second));
385 const auto exitTime =
386 std::chrono::duration_cast<std::chrono::seconds>(ms).count();
387 log<level::INFO>(
388 fmt::format("Idle Power Saver change: Exit Time={}sec", exitTime)
389 .c_str());
390 parmsChanged = true;
391 }
392
393 if (parmsChanged)
394 {
395 // Trigger mode change to OCC
Chris Cain36f9cde2021-11-22 11:18:21 -0600396 sendIpsData();
Chris Cain1d51da22021-09-21 14:13:41 -0500397 }
398
399 return;
400}
401
Chris Cain36f9cde2021-11-22 11:18:21 -0600402/** @brief Get the Idle Power Saver properties
403 * @return true if IPS is enabled
404 */
405bool PowerMode::getIPSParms(uint8_t& enterUtil, uint16_t& enterTime,
406 uint8_t& exitUtil, uint16_t& exitTime)
407{
408 using namespace open_power::occ::powermode;
409 // Defaults:
410 bool ipsEnabled = false; // Disabled
411 enterUtil = 8; // Enter Utilization (8%)
412 enterTime = 240; // Enter Delay Time (240s)
413 exitUtil = 12; // Exit Utilization (12%)
414 exitTime = 10; // Exit Delay Time (10s)
415
416 std::map<std::string, std::variant<bool, uint8_t, uint64_t>>
417 ipsProperties{};
418
419 // Get all IPS properties from DBus
420 try
421 {
422 auto& bus = utils::getBus();
423 auto service = utils::getService(PIPS_PATH, PIPS_INTERFACE);
424 auto method =
425 bus.new_method_call(service.c_str(), PIPS_PATH,
426 "org.freedesktop.DBus.Properties", "GetAll");
427 method.append(PIPS_INTERFACE);
428 auto reply = bus.call(method);
429 reply.read(ipsProperties);
430 }
431 catch (const sdbusplus::exception::exception& e)
432 {
433 log<level::ERR>(
434 fmt::format(
435 "Unable to read Idle Power Saver parameters so it will be disabled: {}",
436 e.what())
437 .c_str());
438 return ipsEnabled;
439 }
440
441 auto ipsEntry = ipsProperties.find(IPS_ENABLED_PROP);
442 if (ipsEntry != ipsProperties.end())
443 {
444 ipsEnabled = std::get<bool>(ipsEntry->second);
445 }
446 else
447 {
448 log<level::ERR>(
449 fmt::format("PowerMode::getIPSParms could not find property: {}",
450 IPS_ENABLED_PROP)
451 .c_str());
452 }
453
454 ipsEntry = ipsProperties.find(IPS_ENTER_UTIL);
455 if (ipsEntry != ipsProperties.end())
456 {
457 enterUtil = std::get<uint8_t>(ipsEntry->second);
458 }
459 else
460 {
461 log<level::ERR>(
462 fmt::format("PowerMode::getIPSParms could not find property: {}",
463 IPS_ENTER_UTIL)
464 .c_str());
465 }
466
467 ipsEntry = ipsProperties.find(IPS_ENTER_TIME);
468 if (ipsEntry != ipsProperties.end())
469 {
470 std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second));
471 enterTime =
472 std::chrono::duration_cast<std::chrono::seconds>(ms).count();
473 }
474 else
475 {
476 log<level::ERR>(
477 fmt::format("PowerMode::getIPSParms could not find property: {}",
478 IPS_ENTER_TIME)
479 .c_str());
480 }
481
482 ipsEntry = ipsProperties.find(IPS_EXIT_UTIL);
483 if (ipsEntry != ipsProperties.end())
484 {
485 exitUtil = std::get<uint8_t>(ipsEntry->second);
486 }
487 else
488 {
489 log<level::ERR>(
490 fmt::format("PowerMode::getIPSParms could not find property: {}",
491 IPS_EXIT_UTIL)
492 .c_str());
493 }
494
495 ipsEntry = ipsProperties.find(IPS_EXIT_TIME);
496 if (ipsEntry != ipsProperties.end())
497 {
498 std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second));
499 exitTime = std::chrono::duration_cast<std::chrono::seconds>(ms).count();
500 }
501 else
502 {
503 log<level::ERR>(
504 fmt::format("PowerMode::getIPSParms could not find property: {}",
505 IPS_EXIT_TIME)
506 .c_str());
507 }
508
509 if (enterUtil > exitUtil)
510 {
511 log<level::ERR>(
512 fmt::format(
513 "ERROR: Idle Power Saver Enter Utilization ({}%) is > Exit Utilization ({}%) - using Exit for both",
514 enterUtil, exitUtil)
515 .c_str());
516 enterUtil = exitUtil;
517 }
518
519 return ipsEnabled;
520}
521
522// Send Idle Power Saver config data to the master OCC
523CmdStatus PowerMode::sendIpsData()
524{
Chris Cain6fa848a2022-01-24 14:54:38 -0600525 CmdStatus status;
Chris Cain36f9cde2021-11-22 11:18:21 -0600526
Chris Cain6fa848a2022-01-24 14:54:38 -0600527 if (!masterActive || !masterOccSet)
Chris Cain36f9cde2021-11-22 11:18:21 -0600528 {
529 // Nothing to do
530 return CmdStatus::SUCCESS;
531 }
532
533 if (!isPowerVM())
534 {
535 // Idle Power Saver data is only supported on PowerVM systems
536 log<level::DEBUG>(
537 "PowerMode::sendIpsData: SET_CFG_DATA[IPS] does not get sent on non-PowerVM systems");
538 return CmdStatus::SUCCESS;
539 }
540
541 uint8_t enterUtil, exitUtil;
542 uint16_t enterTime, exitTime;
543 const bool ipsEnabled =
544 getIPSParms(enterUtil, enterTime, exitUtil, exitTime);
545
546 log<level::INFO>(
547 fmt::format(
548 "Idle Power Saver Parameters: enabled:{}, enter:{}%/{}s, exit:{}%/{}s",
549 ipsEnabled, enterUtil, enterTime, exitUtil, exitTime)
550 .c_str());
551
552 std::vector<std::uint8_t> cmd, rsp;
553 cmd.reserve(12);
554 cmd.push_back(uint8_t(CmdType::SET_CONFIG_DATA));
555 cmd.push_back(0x00); // Data Length (2 bytes)
556 cmd.push_back(0x09); //
557 cmd.push_back(0x11); // Config Format: IPS Settings
558 cmd.push_back(0x00); // Version
559 cmd.push_back(ipsEnabled ? 1 : 0); // IPS Enable
560 cmd.push_back(enterTime >> 8); // Enter Delay Time
561 cmd.push_back(enterTime & 0xFF); //
562 cmd.push_back(enterUtil); // Enter Utilization
563 cmd.push_back(exitTime >> 8); // Exit Delay Time
564 cmd.push_back(exitTime & 0xFF); //
565 cmd.push_back(exitUtil); // Exit Utilization
566 log<level::INFO>(fmt::format("PowerMode::sendIpsData: SET_CFG_DATA[IPS] "
567 "command to OCC{} ({} bytes)",
568 occInstance, cmd.size())
569 .c_str());
Chris Cain6fa848a2022-01-24 14:54:38 -0600570 status = occCmd->send(cmd, rsp);
Chris Cain36f9cde2021-11-22 11:18:21 -0600571 if (status == CmdStatus::SUCCESS)
572 {
573 if (rsp.size() == 5)
574 {
575 if (RspStatus::SUCCESS != RspStatus(rsp[2]))
576 {
577 log<level::ERR>(
578 fmt::format(
579 "PowerMode::sendIpsData: SET_CFG_DATA[IPS] failed with status 0x{:02X}",
580 rsp[2])
581 .c_str());
582 dump_hex(rsp);
583 status = CmdStatus::FAILURE;
584 }
585 }
586 else
587 {
588 log<level::ERR>(
589 "PowerMode::sendIpsData: INVALID SET_CFG_DATA[IPS] response");
590 dump_hex(rsp);
591 status = CmdStatus::FAILURE;
592 }
593 }
594 else
595 {
596 if (status == CmdStatus::OPEN_FAILURE)
597 {
598 // OCC not active yet
599 status = CmdStatus::SUCCESS;
600 }
601 else
602 {
603 log<level::ERR>(
604 "PowerMode::sendIpsData: SET_CFG_DATA[IPS] FAILED!");
605 }
606 }
607
608 return status;
609}
610
611inline void OccPersistData::print()
612{
613 log<level::DEBUG>(
614 fmt::format(
615 "OccPersistData: OEM Mode: 0x{:02X}, OEM Mode Freq: {} (0x{:04X})",
616 oemData.oemMode, oemData.oemModeFreq, oemData.oemModeFreq)
617 .c_str());
618}
619
620// Saves the OEM mode data in the filesystem using cereal.
621void OccPersistData::save()
622{
623 std::filesystem::path opath =
624 std::filesystem::path{OCC_CONTROL_PERSIST_PATH} / oemModeFilename;
625
626 if (!std::filesystem::exists(opath.parent_path()))
627 {
628 std::filesystem::create_directory(opath.parent_path());
629 }
630
631 log<level::DEBUG>(
632 fmt::format("OccPersistData::save: Writing OEM persisted data to {}",
633 opath.c_str())
634 .c_str());
635 print();
636
637 std::ofstream stream{opath.c_str()};
638 cereal::JSONOutputArchive oarchive{stream};
639
640 oarchive(oemData);
641}
642
643// Loads the OEM mode data in the filesystem using cereal.
644void OccPersistData::load()
645{
646
647 std::filesystem::path ipath =
648 std::filesystem::path{OCC_CONTROL_PERSIST_PATH} / oemModeFilename;
649
650 if (!std::filesystem::exists(ipath))
651 {
652 return;
653 }
654
655 log<level::DEBUG>(
656 fmt::format("OccPersistData::load: Reading OEM persisted data from {}",
657 ipath.c_str())
658 .c_str());
659 try
660 {
661 std::ifstream stream{ipath.c_str()};
662 cereal::JSONInputArchive iarchive(stream);
663 iarchive(oemData);
664
665 oemSet = true;
666 }
667 catch (const std::exception& e)
668 {
669 auto error = errno;
670 log<level::ERR>(
671 fmt::format("OccPersistData::load: failed to read {}, errno={}",
672 ipath.c_str(), error)
673 .c_str());
674 }
675
676 print();
677}
678
679void OccPersistData::purge()
680{
681 std::filesystem::path opath =
682 std::filesystem::path{OCC_CONTROL_PERSIST_PATH} / oemModeFilename;
683
684 if (!std::filesystem::exists(opath))
685 {
686 return;
687 }
688
689 print();
690 log<level::DEBUG>("OccPersistData::purge() Removing OEM data");
691
692 oemSet = false;
693 oemData.oemMode = SysPwrMode::NO_CHANGE;
694 oemData.oemModeFreq = 0x0000;
695 remove(opath.c_str());
696}
697
Chris Cain78e86012021-03-04 16:15:31 -0600698} // namespace powermode
699
700} // namespace occ
701
702} // namespace open_power