Implement processor throttle dbus properties
- create processor throttle dbus objects for each OCC (processor)
- update throttle properties based on OCC poll response data
or safe mode status.
Throttle data will be made available via Redfish
NAME TYPE SIGNATURE RESULT/VALUE FLAGS
org.freedesktop.DBus.Introspectable interface - - -
.Introspect method - s -
org.freedesktop.DBus.Peer interface - - -
.GetMachineId method - s -
.Ping method - - -
org.freedesktop.DBus.Properties interface - - -
.Get method ss v -
.GetAll method s a{sv} -
.Set method ssv - -
.PropertiesChanged signal sa{sv}as - -
xyz.openbmc_project.Control.Power.Throttle interface - - -
.ThrottleCauses property as 0 emits-change
.Throttled property b false emits-change
Example of throttled processor (due to a power limit):
as 1 "xyz.openbmc_project.Control.Power.Throttle.ThrottleReasons.PowerLimit"
Change-Id: I0af9d82fab9d694427d0adaa45f4a372d25fbc12
Signed-off-by: Chris Cain <cjcain@us.ibm.com>
diff --git a/app.cpp b/app.cpp
index a7e5f63..1d0ece3 100644
--- a/app.cpp
+++ b/app.cpp
@@ -37,6 +37,7 @@
// Attach the bus to sd_event to service user requests
bus.attach_event(eventP.get(), SD_EVENT_PRIORITY_NORMAL);
+ // Add object manager interfaces (for mapper)
sdbusplus::server::manager_t objManager(bus, OCC_CONTROL_ROOT);
#ifdef READ_OCC_SENSORS
sdbusplus::server::manager_t objManagerXyz(bus, OCC_SENSORS_ROOT);
@@ -45,6 +46,8 @@
sdbusplus::server::manager_t objManagerXyzControl(
bus, "/xyz/openbmc_project/control");
#endif
+ sdbusplus::server::manager_t objManagerXyzInventory(
+ bus, "/xyz/openbmc_project/inventory");
open_power::occ::Manager mgr(eventP);
// Claim the bus since all the house keeping is done now
diff --git a/occ_device.cpp b/occ_device.cpp
index 0ca4fdc..26aee75 100644
--- a/occ_device.cpp
+++ b/occ_device.cpp
@@ -118,11 +118,15 @@
void Device::throttleProcTempCallback(int error)
{
statusObject.throttleProcTemp(error);
+ // Update the processor throttle on dbus
+ statusObject.updateThrottle(error, THROTTLED_THERMAL);
}
void Device::throttleProcPowerCallback(int error)
{
statusObject.throttleProcPower(error);
+ // Update the processor throttle on dbus
+ statusObject.updateThrottle(error, THROTTLED_POWER);
}
void Device::throttleMemTempCallback(int error)
diff --git a/occ_manager.cpp b/occ_manager.cpp
index 4833d5a..69d3bc9 100644
--- a/occ_manager.cpp
+++ b/occ_manager.cpp
@@ -114,6 +114,12 @@
}
statusObjCreated = true;
waitingForAllOccActiveSensors = true;
+
+ // Find/update the processor path associated with each OCC
+ for (auto& obj : statusObjects)
+ {
+ obj->updateProcAssociation();
+ }
}
}
@@ -555,6 +561,11 @@
#ifdef POWER10
pmode->updateDbusSafeMode(safeMode);
#endif
+ // Update the processor throttle status on dbus
+ for (auto& obj : statusObjects)
+ {
+ obj->updateThrottle(safeMode, THROTTLED_SAFE);
+ }
}
void Manager::sbeHRESETResult(instanceID instance, bool success)
diff --git a/occ_status.cpp b/occ_status.cpp
index 85b70ee..b89e469 100644
--- a/occ_status.cpp
+++ b/occ_status.cpp
@@ -18,6 +18,9 @@
using namespace phosphor::logging;
+using ThrottleObj =
+ sdbusplus::xyz::openbmc_project::Control::Power::server::Throttle;
+
// Handles updates to occActive property
bool Status::occActive(bool value)
{
@@ -28,6 +31,9 @@
.c_str());
if (value)
{
+ // Clear prior throttle reason (before setting device active)
+ updateThrottle(false, THROTTLED_ALL);
+
// Set the device active
device.setActive(true);
@@ -77,6 +83,9 @@
// Set the device inactive
device.setActive(false);
+
+ // Clear throttles (OCC not active after disabling device)
+ updateThrottle(false, THROTTLED_ALL);
}
}
else if (value && !device.active())
@@ -555,5 +564,121 @@
}
}
+// Update processor throttle status on dbus
+void Status::updateThrottle(const bool isThrottled, const uint8_t newReason)
+{
+ if (!throttleHandle)
+ {
+ return;
+ }
+
+ uint8_t newThrottleCause = throttleCause;
+
+ if (isThrottled) // throttled due to newReason
+ {
+ if ((newReason & throttleCause) == 0)
+ {
+ // set the bit(s) for passed in reason
+ newThrottleCause |= newReason;
+ }
+ // else no change
+ }
+ else // no longer throttled due to newReason
+ {
+ if ((newReason & throttleCause) != 0)
+ {
+ // clear the bit(s) for passed in reason
+ newThrottleCause &= ~newReason;
+ }
+ // else no change
+ }
+
+ if (newThrottleCause != throttleCause)
+ {
+ if (newThrottleCause == THROTTLED_NONE)
+ {
+ log<level::DEBUG>(
+ fmt::format(
+ "updateThrottle: OCC{} no longer throttled (prior reason: {})",
+ instance, throttleCause)
+ .c_str());
+ throttleCause = THROTTLED_NONE;
+ throttleHandle->throttled(false);
+ throttleHandle->throttleCauses({});
+ }
+ else
+ {
+ log<level::DEBUG>(
+ fmt::format(
+ "updateThrottle: OCC{} is throttled with reason {} (prior reason: {})",
+ instance, newThrottleCause, throttleCause)
+ .c_str());
+ throttleCause = newThrottleCause;
+
+ std::vector<ThrottleObj::ThrottleReasons> updatedCauses;
+ if (throttleCause & THROTTLED_POWER)
+ {
+ updatedCauses.push_back(
+ throttleHandle->ThrottleReasons::PowerLimit);
+ }
+ if (throttleCause & THROTTLED_THERMAL)
+ {
+ updatedCauses.push_back(
+ throttleHandle->ThrottleReasons::ThermalLimit);
+ }
+ if (throttleCause & THROTTLED_SAFE)
+ {
+ updatedCauses.push_back(
+ throttleHandle->ThrottleReasons::ManagementDetectedFault);
+ }
+ throttleHandle->throttleCauses(updatedCauses);
+ throttleHandle->throttled(true);
+ }
+ }
+ // else no change to throttle status
+}
+
+// Get processor path associated with this OCC
+void Status::readProcAssociation()
+{
+ std::string managingPath = path + "/power_managing";
+ log<level::DEBUG>(
+ fmt::format("readProcAssociation: getting endpoints for {} ({})",
+ managingPath, path)
+ .c_str());
+ try
+ {
+ utils::PropertyValue procPathProperty{};
+ procPathProperty = utils::getProperty(
+ managingPath, "xyz.openbmc_project.Association", "endpoints");
+ auto result = std::get<std::vector<std::string>>(procPathProperty);
+ if (result.size() > 0)
+ {
+ procPath = result[0];
+ log<level::INFO>(
+ fmt::format("readProcAssociation: OCC{} has proc={}", instance,
+ procPath.c_str())
+ .c_str());
+ }
+ else
+ {
+ log<level::ERR>(
+ fmt::format(
+ "readProcAssociation: No processor associated with OCC{} / {}",
+ instance, path)
+ .c_str());
+ }
+ }
+ catch (const sdbusplus::exception_t& e)
+ {
+ log<level::ERR>(
+ fmt::format(
+ "readProcAssociation: Unable to get proc assocated with {} - {}",
+ path, e.what())
+ .c_str());
+ procPath = {};
+ }
+}
+
} // namespace occ
} // namespace open_power
diff --git a/occ_status.hpp b/occ_status.hpp
index ce3df77..a07c272 100644
--- a/occ_status.hpp
+++ b/occ_status.hpp
@@ -17,6 +17,7 @@
#include <sdeventplus/event.hpp>
#include <sdeventplus/utility/timer.hpp>
#endif
+#include <xyz/openbmc_project/Control/Power/Throttle/server.hpp>
#include <functional>
@@ -29,6 +30,9 @@
namespace Base = sdbusplus::org::open_power::OCC::server;
using Interface = sdbusplus::server::object_t<Base::Status>;
+namespace xyzBase = sdbusplus::xyz::openbmc_project::Control::Power::server;
+using ThrottleInterface = sdbusplus::server::object_t<xyzBase::Throttle>;
+
// IPMID's host control application
namespace Control = sdbusplus::org::open_power::Control::server;
@@ -50,6 +54,12 @@
// OCC sysfs name prefix
const std::string sysfsName = "occ-hwmon";
+const uint8_t THROTTLED_NONE = 0x00;
+const uint8_t THROTTLED_POWER = 0x01;
+const uint8_t THROTTLED_THERMAL = 0x02;
+const uint8_t THROTTLED_SAFE = 0x04;
+const uint8_t THROTTLED_ALL = 0xFF;
+
/** @class Status
* @brief Implementation of OCC Active Status
*/
@@ -222,7 +232,6 @@
{
return pldmSensorStateReceived;
}
-
#endif // POWER10
/** @brief Return the HWMON path for this OCC
@@ -231,10 +240,33 @@
*/
fs::path getHwmonPath();
+ /** @brief Update the processor path associated with this OCC
+ */
+ void updateProcAssociation()
+ {
+ readProcAssociation();
+ if (nullptr != throttleHandle)
+ {
+ throttleHandle.reset();
+ }
+ if (!procPath.empty())
+ {
+ throttleHandle = std::make_unique<ThrottleInterface>(
+ utils::getBus(), procPath.c_str());
+ }
+ }
+
+ /** @brief Update the processor throttle status on dbus
+ */
+ void updateThrottle(const bool isThrottled, const uint8_t reason);
+
private:
/** @brief OCC dbus object path */
std::string path;
+ /** @brief Processor path associated with this OCC */
+ std::string procPath;
+
/** @brief Callback handler to be invoked during property change.
* This is a handler in Manager class
*/
@@ -360,6 +392,15 @@
#ifdef PLDM
std::function<void(instanceID)> resetCallBack = nullptr;
#endif
+
+ /** @brief Current throttle reason(s) for this processor */
+ uint8_t throttleCause = THROTTLED_NONE;
+
+ /** @brief Throttle interface for the processor associated with this OCC */
+ std::unique_ptr<ThrottleInterface> throttleHandle;
+
+ /** @brief Read the processor path associated with this OCC */
+ void readProcAssociation();
};
} // namespace occ
diff --git a/utils.hpp b/utils.hpp
index 8cb8333..eb38c03 100644
--- a/utils.hpp
+++ b/utils.hpp
@@ -19,7 +19,8 @@
constexpr auto DBUS_PROPERTY_IFACE = "org.freedesktop.DBus.Properties";
// The value of the property(type: variant, contains some basic types)
-using PropertyValue = std::variant<uint32_t, bool, double, std::string>;
+using PropertyValue =
+ std::variant<uint32_t, bool, double, std::string, std::vector<std::string>>;
/** @brief Get the bus connection. */
static auto& getBus()