Use Idle Power Saver parameters from DBus
Allows users to enable and update the IPS parameters instead of
using hardcoded values.
Change-Id: I9010c4b4d3dbdf130a4a778f71c87279681a9f1a
Signed-off-by: Chris Cain <cjcain@us.ibm.com>
diff --git a/occ_manager.cpp b/occ_manager.cpp
index ea2020c..b83feb3 100644
--- a/occ_manager.cpp
+++ b/occ_manager.cpp
@@ -159,6 +159,12 @@
pmode = std::make_unique<open_power::occ::powermode::PowerMode>(
*statusObjects.front());
}
+ // Create the idle power saver monitor object for master occ (0)
+ if (!pips)
+ {
+ pips = std::make_unique<open_power::occ::powermode::PowerIPS>(
+ *statusObjects.front());
+ }
#endif
}
@@ -235,6 +241,8 @@
#ifdef POWER10
pmode = std::make_unique<open_power::occ::powermode::PowerMode>(
*statusObjects.front());
+ pips = std::make_unique<open_power::occ::powermode::PowerIPS>(
+ *statusObjects.front());
#endif
}
#endif
diff --git a/occ_manager.hpp b/occ_manager.hpp
index 43cc32f..5b97abc 100644
--- a/occ_manager.hpp
+++ b/occ_manager.hpp
@@ -147,6 +147,9 @@
#ifdef POWER10
/** @brief Power mode monitor and notification object */
std::unique_ptr<open_power::occ::powermode::PowerMode> pmode;
+
+ /** @brief Idle Power Saver monitor and notification object */
+ std::unique_ptr<open_power::occ::powermode::PowerIPS> pips;
#endif
/** @brief sbdbusplus match objects */
diff --git a/occ_status.cpp b/occ_status.cpp
index ab6b9d1..b1893fd 100644
--- a/occ_status.cpp
+++ b/occ_status.cpp
@@ -172,11 +172,6 @@
fs::path(DEV_PATH) /
fs::path(sysfsName + "." + std::to_string(instance + 1)) / "occ_state";
- log<level::DEBUG>(
- fmt::format("Status::readOccState: reading OCC{} state from {}",
- instance, filename.c_str())
- .c_str());
-
std::ifstream file(filename, std::ios::in);
const int open_errno = errno;
if (file)
@@ -272,6 +267,124 @@
return pmode;
}
+// Get the requested power mode
+bool Status::getIPSParms(uint8_t& enterUtil, uint16_t& enterTime,
+ uint8_t& exitUtil, uint16_t& exitTime)
+{
+ using namespace open_power::occ::powermode;
+ // Defaults:
+ bool ipsEnabled = false; // Disabled
+ enterUtil = 8; // Enter Utilization (8%)
+ enterTime = 240; // Enter Delay Time (240s)
+ exitUtil = 12; // Exit Utilization (12%)
+ exitTime = 10; // Exit Delay Time (10s)
+
+ std::map<std::string, std::variant<bool, uint8_t, uint64_t>>
+ ipsProperties{};
+
+ // Get all IPS properties from DBus
+ try
+ {
+ auto& bus = utils::getBus();
+ auto service = utils::getService(PIPS_PATH, PIPS_INTERFACE);
+ auto method =
+ bus.new_method_call(service.c_str(), PIPS_PATH,
+ "org.freedesktop.DBus.Properties", "GetAll");
+ method.append(PIPS_INTERFACE);
+ auto reply = bus.call(method);
+ reply.read(ipsProperties);
+ }
+ catch (const sdbusplus::exception::exception& e)
+ {
+ log<level::ERR>(
+ fmt::format(
+ "Unable to read Idle Power Saver parameters so it will be disabled: {}",
+ e.what())
+ .c_str());
+ return ipsEnabled;
+ }
+
+ auto ipsEntry = ipsProperties.find(IPS_ENABLED_PROP);
+ if (ipsEntry != ipsProperties.end())
+ {
+ ipsEnabled = std::get<bool>(ipsEntry->second);
+ }
+ else
+ {
+ log<level::ERR>(
+ fmt::format("Status::getIPSParms could not find property: {}",
+ IPS_ENABLED_PROP)
+ .c_str());
+ }
+
+ ipsEntry = ipsProperties.find(IPS_ENTER_UTIL);
+ if (ipsEntry != ipsProperties.end())
+ {
+ enterUtil = std::get<uint8_t>(ipsEntry->second);
+ }
+ else
+ {
+ log<level::ERR>(
+ fmt::format("Status::getIPSParms could not find property: {}",
+ IPS_ENTER_UTIL)
+ .c_str());
+ }
+
+ ipsEntry = ipsProperties.find(IPS_ENTER_TIME);
+ if (ipsEntry != ipsProperties.end())
+ {
+ std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second));
+ enterTime =
+ std::chrono::duration_cast<std::chrono::seconds>(ms).count();
+ }
+ else
+ {
+ log<level::ERR>(
+ fmt::format("Status::getIPSParms could not find property: {}",
+ IPS_ENTER_TIME)
+ .c_str());
+ }
+
+ ipsEntry = ipsProperties.find(IPS_EXIT_UTIL);
+ if (ipsEntry != ipsProperties.end())
+ {
+ exitUtil = std::get<uint8_t>(ipsEntry->second);
+ }
+ else
+ {
+ log<level::ERR>(
+ fmt::format("Status::getIPSParms could not find property: {}",
+ IPS_EXIT_UTIL)
+ .c_str());
+ }
+
+ ipsEntry = ipsProperties.find(IPS_EXIT_TIME);
+ if (ipsEntry != ipsProperties.end())
+ {
+ std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second));
+ exitTime = std::chrono::duration_cast<std::chrono::seconds>(ms).count();
+ }
+ else
+ {
+ log<level::ERR>(
+ fmt::format("Status::getIPSParms could not find property: {}",
+ IPS_EXIT_TIME)
+ .c_str());
+ }
+
+ if (enterUtil > exitUtil)
+ {
+ log<level::ERR>(
+ fmt::format(
+ "ERROR: Idle Power Saver Enter Utilization ({}%) is > Exit Utilization ({}%) - using Exit for both",
+ enterUtil, exitUtil)
+ .c_str());
+ enterUtil = exitUtil;
+ }
+
+ return ipsEnabled;
+}
+
// Special processing that needs to happen once the OCCs change to ACTIVE state
void Status::occsWentActive()
{
@@ -325,6 +438,7 @@
if (VALID_POWER_MODE_SETTING(newMode))
{
std::vector<std::uint8_t> cmd, rsp;
+ cmd.reserve(9);
cmd.push_back(uint8_t(CmdType::SET_MODE_AND_STATE));
cmd.push_back(0x00); // Data Length (2 bytes)
cmd.push_back(0x06);
@@ -344,18 +458,15 @@
{
if (rsp.size() == 5)
{
- if (RspStatus::SUCCESS == RspStatus(rsp[2]))
- {
- log<level::DEBUG>(
- "Status::sendModeChange: - Mode change completed successfully");
- }
- else
+ if (RspStatus::SUCCESS != RspStatus(rsp[2]))
{
log<level::ERR>(
fmt::format(
"Status::sendModeChange: SET MODE failed with status 0x{:02X}",
rsp[2])
.c_str());
+ dump_hex(rsp);
+ status = CmdStatus::FAILURE;
}
}
else
@@ -363,14 +474,15 @@
log<level::ERR>(
"Status::sendModeChange: INVALID SET MODE response");
dump_hex(rsp);
+ status = CmdStatus::FAILURE;
}
}
else
{
if (status == CmdStatus::OPEN_FAILURE)
{
- log<level::WARNING>(
- "Status::sendModeChange: OCC not active yet");
+ log<level::INFO>("Status::sendModeChange: OCC not active yet");
+ status = CmdStatus::SUCCESS;
}
else
{
@@ -385,6 +497,7 @@
"Status::sendModeChange: Unable to set power mode to {}",
newMode)
.c_str());
+ status = CmdStatus::FAILURE;
}
return status;
@@ -412,42 +525,49 @@
return CmdStatus::SUCCESS;
}
- std::vector<std::uint8_t> cmd, rsp;
- cmd.push_back(uint8_t(CmdType::SET_CONFIG_DATA));
- cmd.push_back(0x00); // Data Length (2 bytes)
- cmd.push_back(0x09);
- // Data:
- cmd.push_back(0x11); // Config Format: IPS Settings
- cmd.push_back(0x00); // Version
- cmd.push_back(0x00); // IPS Enable: disabled
- cmd.push_back(0x00); // Enter Delay Time (240s)
- cmd.push_back(0xF0); //
- cmd.push_back(0x08); // Enter Utilization (8%)
- cmd.push_back(0x00); // Exit Delay Time (10s)
- cmd.push_back(0x0A); //
- cmd.push_back(0x0C); // Exit Utilization (12%)
+ uint8_t enterUtil, exitUtil;
+ uint16_t enterTime, exitTime;
+ const bool ipsEnabled =
+ getIPSParms(enterUtil, enterTime, exitUtil, exitTime);
+
log<level::INFO>(
fmt::format(
- "Status::sendIpsData: SET_CFG_DATA[IPS] command to OCC{} ({} bytes)",
- instance, cmd.size())
+ "Idle Power Saver Parameters: enabled:{}, enter:{}%/{}s, exit:{}%/{}s",
+ ipsEnabled, enterUtil, enterTime, exitUtil, exitTime)
.c_str());
+
+ std::vector<std::uint8_t> cmd, rsp;
+ cmd.reserve(12);
+ cmd.push_back(uint8_t(CmdType::SET_CONFIG_DATA));
+ cmd.push_back(0x00); // Data Length (2 bytes)
+ cmd.push_back(0x09); //
+ cmd.push_back(0x11); // Config Format: IPS Settings
+ cmd.push_back(0x00); // Version
+ cmd.push_back(ipsEnabled ? 1 : 0); // IPS Enable
+ cmd.push_back(enterTime >> 8); // Enter Delay Time
+ cmd.push_back(enterTime & 0xFF); //
+ cmd.push_back(enterUtil); // Enter Utilization
+ cmd.push_back(exitTime >> 8); // Exit Delay Time
+ cmd.push_back(exitTime & 0xFF); //
+ cmd.push_back(exitUtil); // Exit Utilization
+ log<level::INFO>(fmt::format("Status::sendIpsData: SET_CFG_DATA[IPS] "
+ "command to OCC{} ({} bytes)",
+ instance, cmd.size())
+ .c_str());
status = occCmd.send(cmd, rsp);
if (status == CmdStatus::SUCCESS)
{
if (rsp.size() == 5)
{
- if (RspStatus::SUCCESS == RspStatus(rsp[2]))
- {
- log<level::DEBUG>(
- "Status::sendIpsData: - SET_CFG_DATA[IPS] completed successfully");
- }
- else
+ if (RspStatus::SUCCESS != RspStatus(rsp[2]))
{
log<level::ERR>(
fmt::format(
"Status::sendIpsData: SET_CFG_DATA[IPS] failed with status 0x{:02X}",
rsp[2])
.c_str());
+ dump_hex(rsp);
+ status = CmdStatus::FAILURE;
}
}
else
@@ -455,13 +575,15 @@
log<level::ERR>(
"Status::sendIpsData: INVALID SET_CFG_DATA[IPS] response");
dump_hex(rsp);
+ status = CmdStatus::FAILURE;
}
}
else
{
if (status == CmdStatus::OPEN_FAILURE)
{
- log<level::WARNING>("Status::sendIpsData: OCC not active yet");
+ log<level::INFO>("Status::sendIpsData: OCC not active yet");
+ status = CmdStatus::SUCCESS;
}
else
{
diff --git a/occ_status.hpp b/occ_status.hpp
index 5856ee9..ceff8f3 100644
--- a/occ_status.hpp
+++ b/occ_status.hpp
@@ -171,6 +171,11 @@
* @return SUCCESS on success
*/
CmdStatus sendModeChange();
+
+ /** @brief Send Idle Power Saver config data to the master OCC
+ * @return SUCCESS on success
+ */
+ CmdStatus sendIpsData();
#endif // POWER10
private:
@@ -241,10 +246,11 @@
*/
SysPwrMode getMode();
- /** @brief Send Idle Power Saver config data to the master OCC
- * @return SUCCESS on success
+ /** @brief Get the Idle Power Saver properties
+ * @return true if IPS is enabled
*/
- CmdStatus sendIpsData();
+ bool getIPSParms(uint8_t& enterUtil, uint16_t& enterTime, uint8_t& exitUtil,
+ uint16_t& exitTime);
#endif // POWER10
/** @brief Override the sensor name with name from the definition.
diff --git a/powermode.cpp b/powermode.cpp
index 32af335..a78c37e 100644
--- a/powermode.cpp
+++ b/powermode.cpp
@@ -21,7 +21,7 @@
{
if (!occStatus.occActive())
{
- // Nothing to do
+ // Nothing to do
return;
}
@@ -81,6 +81,79 @@
return pmode;
}
+void PowerIPS::ipsChanged(sdbusplus::message::message& msg)
+{
+ if (!occStatus.occActive())
+ {
+ // Nothing to do
+ return;
+ }
+
+ bool parmsChanged = false;
+ std::string interface;
+ std::map<std::string, std::variant<bool, uint8_t, uint64_t>>
+ ipsProperties{};
+ msg.read(interface, ipsProperties);
+
+ auto ipsEntry = ipsProperties.find(IPS_ENABLED_PROP);
+ if (ipsEntry != ipsProperties.end())
+ {
+ const auto ipsEnabled = std::get<bool>(ipsEntry->second);
+ log<level::INFO>(
+ fmt::format("Idle Power Saver change: Enabled={}", ipsEnabled)
+ .c_str());
+ parmsChanged = true;
+ }
+ ipsEntry = ipsProperties.find(IPS_ENTER_UTIL);
+ if (ipsEntry != ipsProperties.end())
+ {
+ const auto enterUtil = std::get<uint8_t>(ipsEntry->second);
+ log<level::INFO>(
+ fmt::format("Idle Power Saver change: Enter Util={}%", enterUtil)
+ .c_str());
+ parmsChanged = true;
+ }
+ ipsEntry = ipsProperties.find(IPS_ENTER_TIME);
+ if (ipsEntry != ipsProperties.end())
+ {
+ std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second));
+ const auto enterTime =
+ std::chrono::duration_cast<std::chrono::seconds>(ms).count();
+ log<level::INFO>(
+ fmt::format("Idle Power Saver change: Enter Time={}sec", enterTime)
+ .c_str());
+ parmsChanged = true;
+ }
+ ipsEntry = ipsProperties.find(IPS_EXIT_UTIL);
+ if (ipsEntry != ipsProperties.end())
+ {
+ const auto exitUtil = std::get<uint8_t>(ipsEntry->second);
+ log<level::INFO>(
+ fmt::format("Idle Power Saver change: Exit Util={}%", exitUtil)
+ .c_str());
+ parmsChanged = true;
+ }
+ ipsEntry = ipsProperties.find(IPS_EXIT_TIME);
+ if (ipsEntry != ipsProperties.end())
+ {
+ std::chrono::milliseconds ms(std::get<uint64_t>(ipsEntry->second));
+ const auto exitTime =
+ std::chrono::duration_cast<std::chrono::seconds>(ms).count();
+ log<level::INFO>(
+ fmt::format("Idle Power Saver change: Exit Time={}sec", exitTime)
+ .c_str());
+ parmsChanged = true;
+ }
+
+ if (parmsChanged)
+ {
+ // Trigger mode change to OCC
+ occStatus.sendIpsData();
+ }
+
+ return;
+}
+
} // namespace powermode
} // namespace occ
diff --git a/powermode.hpp b/powermode.hpp
index fd7d466..c9d3f0e 100644
--- a/powermode.hpp
+++ b/powermode.hpp
@@ -21,6 +21,15 @@
constexpr auto PMODE_INTERFACE = "xyz.openbmc_project.Control.Power.Mode";
constexpr auto POWER_MODE_PROP = "PowerMode";
+constexpr auto PIPS_PATH = "/xyz/openbmc_project/control/host0/power_ips";
+constexpr auto PIPS_INTERFACE =
+ "xyz.openbmc_project.Control.Power.IdlePowerSaver";
+constexpr auto IPS_ENABLED_PROP = "Enabled";
+constexpr auto IPS_ENTER_UTIL = "EnterUtilizationPercent";
+constexpr auto IPS_ENTER_TIME = "EnterDwellTime";
+constexpr auto IPS_EXIT_UTIL = "ExitUtilizationPercent";
+constexpr auto IPS_EXIT_TIME = "ExitDwellTime";
+
/** @brief Convert power mode string to OCC SysPwrMode value
*
* @param[in] i_modeString - power mode string
@@ -72,6 +81,42 @@
sdbusplus::bus::match_t pmodeMatch;
};
+class PowerIPS
+{
+ public:
+ /** @brief PowerIPS object to inform occ of changes to Idle Power Saver
+ * parms
+ *
+ * This object will monitor for changes to the Idle Power Saver settings.
+ * If a change is detected, and the occ is active, then this object will
+ * notify the OCC of the change.
+ *
+ * @param[in] occStatus - The occ status object
+ */
+ PowerIPS(Status& occStatus) :
+ occStatus(occStatus),
+ ipsMatch(utils::getBus(),
+ sdbusplus::bus::match::rules::propertiesChanged(
+ PIPS_PATH, PIPS_INTERFACE),
+ [this](auto& msg) { this->ipsChanged(msg); }){};
+
+ private:
+ /** @brief Callback for IPS setting changes
+ *
+ * Process change and inform OCC
+ *
+ * @param[in] msg - Data associated with IPS change signal
+ *
+ */
+ void ipsChanged(sdbusplus::message::message& msg);
+
+ /* @brief OCC Status object */
+ Status& occStatus;
+
+ /** @brief Used to subscribe to dbus IPS property changes **/
+ sdbusplus::bus::match_t ipsMatch;
+};
+
} // namespace powermode
} // namespace occ