Disable Idle Power Saver support in efficiency modes
IPS will not be published on DBUS when the PowerMode is set to one of
the newer efficiency modes:
EfficiencyFavorPower
EfficiencyFavorPerformance (OEM only)
This will prevent the Redfish interface from allowing GET/PATCH
commands and provides a way for the GUI to know when to suppress
B
displaying the parameters on the customer GUI.
Testing:
Verified on Rainier.
When in a non-efficiency mode, the Redfish query returns IPS data:
(GET /redfish/v1/Systems/system)
'''
...
"Id": "system",
"IdlePowerSaver": {
"Enabled": true,
"EnterDwellTimeSeconds": 240,
"EnterUtilizationPercent": 8,
"ExitDwellTimeSeconds": 10,
"ExitUtilizationPercent": 12
},
"IndicatorLED": "Off",
...
'''
When in an efficiency mode, the Redfish query does not return IPS data.
'''
...
"Id": "system",
"IndicatorLED": "Off",
...
'''
Verified across re-ipls, OCC resets, app restarts.
Change-Id: I45bb0d8e97dab33a1a66c0d791f7bb4848bfce41
Signed-off-by: Chris Cain <cjcain@us.ibm.com>
diff --git a/occ_status.cpp b/occ_status.cpp
index 7d654b9..4b6e276 100644
--- a/occ_status.cpp
+++ b/occ_status.cpp
@@ -251,6 +251,10 @@
{
CmdStatus status = CmdStatus::SUCCESS;
+ // IPS data will get sent automatically after a mode change if the mode
+ // supports it.
+ pmode->needToSendIPS();
+
status = pmode->sendModeChange();
if (status != CmdStatus::SUCCESS)
{
@@ -263,22 +267,6 @@
// Disable and reset to try recovering
deviceError();
}
-
- status = pmode->sendIpsData();
- if (status != CmdStatus::SUCCESS)
- {
- log<level::ERR>(
- std::format(
- "Status::occsWentActive: Sending Idle Power Save Config data failed with status {}",
- status)
- .c_str());
-
- if (status == CmdStatus::COMM_FAILURE)
- {
- // Disable and reset to try recovering
- deviceError();
- }
- }
}
// Send Ambient and Altitude to the OCC
diff --git a/powermode.cpp b/powermode.cpp
index 776edc4..2179bd8 100644
--- a/powermode.cpp
+++ b/powermode.cpp
@@ -44,14 +44,16 @@
((mode == SysPwrMode::SFP) || (mode == SysPwrMode::FFO) || \
(mode == SysPwrMode::MAX_FREQ) || \
(mode == SysPwrMode::NON_DETERMINISTIC))
+// List of all Power Modes that disable IPS
+#define IS_ECO_MODE(mode) \
+ ((mode == SysPwrMode::EFF_FAVOR_POWER) || \
+ (mode == SysPwrMode::EFF_FAVOR_PERF))
// Constructor
PowerMode::PowerMode(const Manager& managerRef, const char* modePath,
const char* ipsPath, EventPtr& event) :
ModeInterface(utils::getBus(), modePath,
ModeInterface::action::emit_no_signals),
- IpsInterface(utils::getBus(), ipsPath,
- IpsInterface::action::emit_no_signals),
manager(managerRef),
ipsMatch(utils::getBus(),
sdbusplus::bus::match::rules::propertiesChanged(PIPS_PATH,
@@ -62,7 +64,8 @@
sdbusplus::bus::match::rules::propertiesChangedNamespace(
"/xyz/openbmc_project/inventory", PMODE_DEFAULT_INTERFACE),
[this](auto& msg) { this->defaultsReady(msg); }),
- masterOccSet(false), masterActive(false), event(event)
+ masterOccSet(false), masterActive(false), ipsObjectPath(ipsPath),
+ event(event)
{
// Get supported power modes from entity manager
if (false == getSupportedModes())
@@ -84,7 +87,7 @@
// Validate persisted mode is supported
if (isValidMode(currentMode))
{
- // Update power mode on DBus
+ // Update power mode on DBus and create IPS object if allowed
updateDbusMode(currentMode);
}
else
@@ -99,18 +102,46 @@
initPersistentData();
}
}
-
- uint8_t enterUtil, exitUtil;
- uint16_t enterTime, exitTime;
- bool ipsEnabled;
- // Read the persisted Idle Power Saver parametres
- if (getIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime))
- {
- // Update Idle Power Saver parameters on DBus
- updateDbusIPS(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime);
- }
};
+void PowerMode::createIpsObject()
+{
+ if (!ipsObject)
+ {
+ log<level::INFO>("createIpsObject: Creating IPS object");
+ ipsObject =
+ std::make_unique<IpsInterface>(utils::getBus(), ipsObjectPath);
+
+ uint8_t enterUtil, exitUtil;
+ uint16_t enterTime, exitTime;
+ bool ipsEnabled;
+ // Read the persisted Idle Power Saver parametres
+ if (getIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime))
+ {
+ // Update Idle Power Saver parameters on DBus
+ updateDbusIPS(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime);
+ }
+
+ // Starts watching for IPS state changes.
+ addIpsWatch(true);
+
+ needToSendIpsData = true;
+ }
+}
+
+void PowerMode::removeIpsObject()
+{
+ if (ipsObject)
+ {
+ // Stop watching for IPS state changes.
+ removeIpsWatch();
+
+ log<level::INFO>("removeIpsObject: Deleting IPS object");
+ ipsObject.reset(nullptr);
+ }
+ needToSendIpsData = false;
+}
+
// Set the Master OCC
void PowerMode::setMasterOcc(const std::string& masterOccPath)
{
@@ -323,7 +354,7 @@
// Save default mode as current mode
persistedData.updateMode(currentMode, 0);
- // Write default mode to DBus
+ // Write default mode to DBus and create IPS object if allowed
updateDbusMode(currentMode);
}
@@ -356,7 +387,7 @@
return true;
}
-// Set the power mode on DBus
+// Set the power mode on DBus and create IPS object if allowed/needed
bool PowerMode::updateDbusMode(const SysPwrMode newMode)
{
if (!isValidMode(newMode))
@@ -399,6 +430,16 @@
}
// else return OEM mode
+ // Determine if IPS is allowed and create/remove as needed
+ if (IS_ECO_MODE(newMode))
+ {
+ removeIpsObject();
+ }
+ else
+ {
+ createIpsObject();
+ }
+
ModeInterface::powerMode(dBusMode);
return true;
@@ -409,27 +450,42 @@
{
CmdStatus status;
- if (!masterActive || !masterOccSet)
- {
- // Nothing to do
- log<level::DEBUG>("PowerMode::sendModeChange: OCC master not active");
- return CmdStatus::SUCCESS;
- }
-
- if (!isPowerVM())
- {
- // Mode change is only supported on PowerVM systems
- log<level::DEBUG>(
- "PowerMode::sendModeChange: MODE CHANGE does not get sent on non-PowerVM systems");
- return CmdStatus::SUCCESS;
- }
-
SysPwrMode newMode;
uint16_t oemModeData = 0;
getMode(newMode, oemModeData);
if (isValidMode(newMode))
{
+ if (IS_ECO_MODE(newMode))
+ {
+ // Customer no longer able to enable IPS
+ removeIpsObject();
+ }
+ else
+ {
+ // Customer now able to enable IPS
+ if (!ipsObject)
+ {
+ createIpsObject();
+ }
+ }
+
+ if (!masterActive || !masterOccSet)
+ {
+ // Nothing to do until OCC goes active
+ log<level::DEBUG>(
+ "PowerMode::sendModeChange: OCC master not active");
+ return CmdStatus::SUCCESS;
+ }
+
+ if (!isPowerVM())
+ {
+ // Mode change is only supported on PowerVM systems
+ log<level::DEBUG>(
+ "PowerMode::sendModeChange: MODE CHANGE does not get sent on non-PowerVM systems");
+ return CmdStatus::SUCCESS;
+ }
+
std::vector<std::uint8_t> cmd, rsp;
cmd.reserve(9);
cmd.push_back(uint8_t(CmdType::SET_MODE_AND_STATE));
@@ -451,7 +507,16 @@
{
if (rsp.size() == 5)
{
- if (RspStatus::SUCCESS != RspStatus(rsp[2]))
+ if (RspStatus::SUCCESS == RspStatus(rsp[2]))
+ {
+ if (needToSendIpsData)
+ {
+ // Successful mode change and IPS is now allowed, so
+ // send IPS config
+ sendIpsData();
+ }
+ }
+ else
{
log<level::ERR>(
std::format(
@@ -492,6 +557,7 @@
return status;
}
+// Handle IPS changed event (from GUI/Redfish)
void PowerMode::ipsChanged(sdbusplus::message_t& msg)
{
bool parmsChanged = false;
@@ -506,6 +572,13 @@
uint16_t enterTime, exitTime;
getIPSParms(ipsEnabled, enterUtil, enterTime, exitUtil, exitTime);
+ if (!ipsObject)
+ {
+ log<level::WARNING>(
+ "ipsChanged: Idle Power Saver can not be modified in an ECO power mode");
+ return;
+ }
+
// Check for any changed data
auto ipsEntry = ipsProperties.find(IPS_ENABLED_PROP);
if (ipsEntry != ipsProperties.end())
@@ -628,15 +701,22 @@
const uint16_t enterTime, const uint8_t exitUtil,
const uint16_t exitTime)
{
- // true = skip update signal
- IpsInterface::setPropertyByName(IPS_ENABLED_PROP, enabled, true);
- IpsInterface::setPropertyByName(IPS_ENTER_UTIL, enterUtil, true);
- // Convert time from seconds to ms
- uint64_t msTime = enterTime * 1000;
- IpsInterface::setPropertyByName(IPS_ENTER_TIME, msTime, true);
- IpsInterface::setPropertyByName(IPS_EXIT_UTIL, exitUtil, true);
- msTime = exitTime * 1000;
- IpsInterface::setPropertyByName(IPS_EXIT_TIME, msTime, true);
+ if (ipsObject)
+ {
+ // true = skip update signal
+ ipsObject->setPropertyByName(IPS_ENABLED_PROP, enabled, true);
+ ipsObject->setPropertyByName(IPS_ENTER_UTIL, enterUtil, true);
+ // Convert time from seconds to ms
+ uint64_t msTime = enterTime * 1000;
+ ipsObject->setPropertyByName(IPS_ENTER_TIME, msTime, true);
+ ipsObject->setPropertyByName(IPS_EXIT_UTIL, exitUtil, true);
+ msTime = exitTime * 1000;
+ ipsObject->setPropertyByName(IPS_EXIT_TIME, msTime, true);
+ }
+ else
+ {
+ log<level::WARNING>("updateDbusIPS: No IPS object was found");
+ }
return true;
}
@@ -658,6 +738,14 @@
return CmdStatus::SUCCESS;
}
+ if (!ipsObject)
+ {
+ // Idle Power Saver data is not available in Eco Modes
+ log<level::INFO>(
+ "PowerMode::sendIpsData: Skipping IPS data due to being in an ECO Power Mode");
+ return CmdStatus::SUCCESS;
+ }
+
bool ipsEnabled;
uint8_t enterUtil, exitUtil;
uint16_t enterTime, exitTime;
@@ -692,7 +780,11 @@
{
if (rsp.size() == 5)
{
- if (RspStatus::SUCCESS != RspStatus(rsp[2]))
+ if (RspStatus::SUCCESS == RspStatus(rsp[2]))
+ {
+ needToSendIpsData = false;
+ }
+ else
{
log<level::ERR>(
std::format(
@@ -1050,7 +1142,10 @@
CALLOUT_DEVICE_PATH(ipsStatusFile.c_str()));
// We are no longer watching the error
- active(false);
+ if (ipsObject)
+ {
+ ipsObject->active(false);
+ }
watching = false;
rc = false;
@@ -1083,7 +1178,10 @@
// matter what the 'watching' flags is set to.
// We are no longer watching the error
- active(false);
+ if (ipsObject)
+ {
+ ipsObject->active(false);
+ }
watching = false;
@@ -1192,7 +1290,10 @@
}
// This will only set IPS active dbus if different than current.
- active(ipsState);
+ if (ipsObject)
+ {
+ ipsObject->active(ipsState);
+ }
}
else
{
diff --git a/powermode.hpp b/powermode.hpp
index a9b01de..715499b 100644
--- a/powermode.hpp
+++ b/powermode.hpp
@@ -241,7 +241,7 @@
* the power mode to the OCC if the mode is changed while the occ is active.
*/
-class PowerMode : public ModeInterface, public IpsInterface
+class PowerMode : public ModeInterface
{
public:
/** @brief PowerMode object to inform occ of changes to mode
@@ -339,6 +339,15 @@
*/
bool isValidMode(const SysPwrMode mode);
+ /** @brief If IPS is supported, set flag indicating need to send IPS data */
+ void needToSendIPS()
+ {
+ if (ipsObject)
+ {
+ needToSendIpsData = true;
+ }
+ }
+
private:
/** @brief OCC manager object */
const Manager& manager;
@@ -385,6 +394,15 @@
/** @brief Current state of error watching */
bool watching = false;
+ /** @brief Set at IPS object creation and cleared after sending IPS data */
+ bool needToSendIpsData = false;
+
+ /** @brief Object path for IPS on DBUS */
+ const char* ipsObjectPath;
+
+ /** @brief IPS DBUS Object */
+ std::unique_ptr<IpsInterface> ipsObject;
+
/** @brief register for the callback from the POLL IPS changed event */
void registerIpsStatusCallBack();
@@ -483,6 +501,12 @@
*/
bool getSupportedModes();
+ /** @brief Create IPS DBUS Object */
+ void createIpsObject();
+
+ /** @brief Remove IPS DBUS Object */
+ void removeIpsObject();
+
/** @brief callback for the POLL IPS changed event
*
* @param[in] es - Populated event source