Read proc temps and dimm temps
This commit uses openpower-occ-control to monitor the temperature and
power sensors, and create sensors on D-BUS. In the loop, read the
sensor values every 1 seconds.
Tested:
I use virtual data to get sensor values:
busctl tree org.open_power.OCC.Control
|-/org
| `-/org/open_power
| `-/org/open_power/control
| |-/org/open_power/control/occ0
| `-/org/open_power/control/occ1
`-/xyz
`-/xyz/openbmc_project
`-/xyz/openbmc_project/sensors
|-/xyz/openbmc_project/sensors/power
| |-/xyz/openbmc_project/sensors/power/p0_mem_2_power
| |-/xyz/openbmc_project/sensors/power/p0_mem_power
| |-/xyz/openbmc_project/sensors/power/p0_power
| |-/xyz/openbmc_project/sensors/power/p1_mem_power
| |-/xyz/openbmc_project/sensors/power/p1_power
| |-/xyz/openbmc_project/sensors/power/p2_mem_power
| |-/xyz/openbmc_project/sensors/power/p2_power
| |-/xyz/openbmc_project/sensors/power/p3_mem_power
| |-/xyz/openbmc_project/sensors/power/p3_power
| `-/xyz/openbmc_project/sensors/power/total_power
`-/xyz/openbmc_project/sensors/temperature
|-/xyz/openbmc_project/sensors/temperature/dimm5_dram_temp
|-/xyz/openbmc_project/sensors/temperature/dimm9_dram_temp
|-/xyz/openbmc_project/sensors/temperature/proc0_core2_temp
|-/xyz/openbmc_project/sensors/temperature/proc0_core3_temp
|-/xyz/openbmc_project/sensors/temperature/proc1_core2_temp
|-/xyz/openbmc_project/sensors/temperature/proc1_core3_temp
|-/xyz/openbmc_project/sensors/temperature/vrm_vdd0_temp
`-/xyz/openbmc_project/sensors/temperature/vrm_vdd1_temp
busctl introspect org.open_power.OCC.Control
/xyz/openbmc_project/sensors/temperature/proc0_core3_temp
NAME TYPE SIGNATURE RESULT/VALUE
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.Sensor.Value interface - -
.MaxValue property d 0
.MinValue property d 0
.Unit property s "xyz.openbmc...
.Value property d 49
xyz.openbmc_project.State.Decorator.OperationalStatus interface - -
.Functional property b true
busctl introspect org.open_power.OCC.Control
/xyz/openbmc_project/sensors/power/total_power
NAME TYPE SIGNATURE RESULT/VALUE
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
.Set method ssv -
.PropertiesChanged signal sa{sv}as -
xyz.openbmc_project.Sensor.Value interface - -
.MaxValue property d 0
.MinValue property d 0
.Unit property s "xyz.openbmc...
.Value property d 83
xyz.openbmc_project.State.Decorator.OperationalStatus interface - -
.Functional property b true
Signed-off-by: Chicago Duan <duanzhijia01@inspur.com>
Change-Id: Iff30ab51745dab500fa19aa4c35b07e0052ac665
diff --git a/app.cpp b/app.cpp
index a26fa3c..59c872d 100644
--- a/app.cpp
+++ b/app.cpp
@@ -35,6 +35,9 @@
bus.attach_event(eventP.get(), SD_EVENT_PRIORITY_NORMAL);
sdbusplus::server::manager::manager objManager(bus, OCC_CONTROL_ROOT);
+#ifdef READ_OCC_SENSORS
+ sdbusplus::server::manager::manager objManagerXyz(bus, OCC_SENSORS_ROOT);
+#endif
open_power::occ::Manager mgr(eventP);
// Claim the bus since all the house keeping is done now
diff --git a/configure.ac b/configure.ac
index b3c62e9..32a6ecc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -74,6 +74,17 @@
AC_SUBST([CPPFLAGS], [$cpp_flags])
)
+ AC_ARG_ENABLE([read-occ-sensors],
+ AS_HELP_STRING([--enable-read-occ-sensors], [Enable read occ sensors support])
+ )
+ AS_IF([test "x$enable_read_occ_sensors" == "xyes"],
+ AC_MSG_NOTICE([Enabling read occ sensors])
+ [
+ cpp_flags="$CPPFLAGS -DREAD_OCC_SENSORS"
+ ]
+ AC_SUBST([CPPFLAGS], [$cpp_flags])
+ )
+
AC_ARG_WITH([host-communication-protocol],
AS_HELP_STRING([--with-host-communication-protocol], [To specify the host communication protocol])
)
@@ -108,6 +119,10 @@
AS_IF([test "x$OCC_CONTROL_ROOT" == "x"], [OCC_CONTROL_ROOT="/org/open_power/control"])
AC_DEFINE_UNQUOTED([OCC_CONTROL_ROOT], ["$OCC_CONTROL_ROOT"], [The Dbus root])
+AC_ARG_VAR(OCC_SENSORS_ROOT, [The sensors Dbus root])
+AS_IF([test "x$OCC_SENSORS_ROOT" == "x"], [OCC_SENSORS_ROOT="/xyz/openbmc_project/sensors"])
+AC_DEFINE_UNQUOTED([OCC_SENSORS_ROOT], ["$OCC_SENSORS_ROOT"], [The sensors Dbus root])
+
AC_ARG_VAR(MAX_CPUS, [The max number of CPUs])
AS_IF([test "x$MAX_CPUS" == "x"], [MAX_CPUS=2])
AC_DEFINE_UNQUOTED([MAX_CPUS], [$MAX_CPUS], [The max number of CPUs])
@@ -124,6 +139,14 @@
AS_IF([test "x$OCC_MASTER_NAME" == "x"], [OCC_MASTER_NAME="occ-hwmon.1"])
AC_DEFINE_UNQUOTED([OCC_MASTER_NAME], ["$OCC_MASTER_NAME"], [The OCC master object name])
+AC_ARG_VAR(OCC_CPU_TEMP_SENSOR_TYPE, [The CPU temp sensor type])
+AS_IF([test "x$OCC_CPU_TEMP_SENSOR_TYPE" == "x"], [OCC_CPU_TEMP_SENSOR_TYPE="C0"])
+AC_DEFINE_UNQUOTED([OCC_CPU_TEMP_SENSOR_TYPE], ["$OCC_CPU_TEMP_SENSOR_TYPE"], [The CPU temp sensor type])
+
+AC_ARG_VAR(OCC_DIMM_TEMP_SENSOR_TYPE, [The dimm temp sensor type])
+AS_IF([test "x$OCC_DIMM_TEMP_SENSOR_TYPE" == "x"], [OCC_DIMM_TEMP_SENSOR_TYPE="D0"])
+AC_DEFINE_UNQUOTED([OCC_DIMM_TEMP_SENSOR_TYPE], ["$OCC_DIMM_TEMP_SENSOR_TYPE"], [The dimm temp sensor type])
+
AC_ARG_VAR(OCC_HWMON_PATH, [The OCC hwmon path])
AC_ARG_VAR(DEV_PATH, [The device path])
AC_ARG_VAR(I2C_OCC_DEVICE_NAME, [The device name of i2c occ hwmon])
diff --git a/occ_dbus.hpp b/occ_dbus.hpp
index 7a7c69c..330f140 100644
--- a/occ_dbus.hpp
+++ b/occ_dbus.hpp
@@ -12,9 +12,11 @@
using ObjectPath = std::string;
-using SensorIntf = sdbusplus::xyz::openbmc_project::Sensor::server::Value;
-using OperationalStatusIntf = sdbusplus::xyz::openbmc_project::State::
- Decorator::server::OperationalStatus;
+using SensorIntf = sdbusplus::server::object::object<
+ sdbusplus::xyz::openbmc_project::Sensor::server::Value>;
+using OperationalStatusIntf =
+ sdbusplus::server::object::object<sdbusplus::xyz::openbmc_project::State::
+ Decorator::server::OperationalStatus>;
/** @class OccDBusSensors
* @brief This is a custom D-Bus object, used to add D-Bus interface and update
diff --git a/occ_manager.cpp b/occ_manager.cpp
index 3ebd90a..4c979df 100644
--- a/occ_manager.cpp
+++ b/occ_manager.cpp
@@ -3,11 +3,14 @@
#include "occ_manager.hpp"
#include "i2c_occ.hpp"
+#include "occ_dbus.hpp"
#include "utils.hpp"
+#include <cmath>
#include <experimental/filesystem>
#include <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/log.hpp>
+#include <regex>
#include <xyz/openbmc_project/Common/error.hpp>
namespace open_power
@@ -175,11 +178,321 @@
{
// Read sysfs to force kernel to poll OCC
obj->readOccState();
+
+#ifdef READ_OCC_SENSORS
+ // Read occ sensor values
+ auto id = obj->getOccInstanceID();
+ if (!obj->occActive())
+ {
+ // Occ not activated
+ setSensorValueToNaN(id);
+ continue;
+ }
+ getSensorValues(id, obj->isMasterOcc());
+#endif
}
// Restart OCC poll timer
_pollTimer->restartOnce(std::chrono::seconds(pollInterval));
}
+#ifdef READ_OCC_SENSORS
+void Manager::readTempSensors(const fs::path& path, uint32_t id)
+{
+ const int open_errno = errno;
+ std::regex expr{"temp\\d+_label$"}; // Example: temp5_label
+ for (auto& file : fs::directory_iterator(path))
+ {
+ if (!std::regex_search(file.path().string(), expr))
+ {
+ continue;
+ }
+ std::ifstream fileOpen(file.path(), std::ios::in);
+ if (!fileOpen)
+ {
+ // If not able to read, OCC may be offline
+ log<level::DEBUG>(
+ fmt::format("readTempSensors: open failed(errno = {}) ",
+ open_errno)
+ .c_str());
+
+ continue;
+ }
+ std::string labelValue;
+ fileOpen >> labelValue;
+ fileOpen.close();
+
+ const std::string& tempLabel = "label";
+ const std::string filePathString = file.path().string().substr(
+ 0, file.path().string().length() - tempLabel.length());
+ std::ifstream fruTypeFile(filePathString + "fru_type", std::ios::in);
+ if (!fruTypeFile)
+ {
+ // If not able to read, OCC may be offline
+ log<level::DEBUG>(
+ fmt::format("readTempSensors: open failed(errno = {}) ",
+ open_errno)
+ .c_str());
+ continue;
+ }
+ uint32_t fruTypeValue{0};
+ fruTypeFile >> fruTypeValue;
+ fruTypeFile.close();
+
+ std::string sensorPath =
+ OCC_SENSORS_ROOT + std::string("/temperature/");
+
+ if (fruTypeValue == VRMVdd)
+ {
+ sensorPath.append("vrm_vdd" + std::to_string(id) + "_temp");
+ }
+ else
+ {
+ auto sensorTypeID =
+ open_power::occ::utils::checkLabelValue(labelValue);
+ if (sensorTypeID == std::nullopt)
+ {
+ continue;
+ }
+ auto& [type, instanceID] = *sensorTypeID;
+
+ if (type == OCC_DIMM_TEMP_SENSOR_TYPE)
+ {
+ auto iter = dimmTempSensorName.find(fruTypeValue);
+ if (iter == dimmTempSensorName.end())
+ {
+ log<level::ERR>(fmt::format("readTempSensors: Fru type "
+ "error! fruTypeValue = {}) ",
+ fruTypeValue)
+ .c_str());
+ continue;
+ }
+
+ sensorPath.append("dimm" + std::to_string(instanceID) +
+ iter->second);
+ }
+ else if (type == OCC_CPU_TEMP_SENSOR_TYPE)
+ {
+ if (fruTypeValue != processorCore)
+ {
+ log<level::ERR>(fmt::format("readTempSensors: Fru type "
+ "error! fruTypeValue = {}) ",
+ fruTypeValue)
+ .c_str());
+ continue;
+ }
+
+ sensorPath.append("proc" + std::to_string(id) + "_core" +
+ std::to_string(instanceID) + "_temp");
+ }
+ else
+ {
+ continue;
+ }
+ }
+
+ std::ifstream faultPathFile(filePathString + "fault", std::ios::in);
+ if (faultPathFile)
+ {
+ uint32_t faultValue;
+ faultPathFile >> faultValue;
+ faultPathFile.close();
+
+ if (faultValue != 0)
+ {
+ open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue(
+ sensorPath, std::numeric_limits<double>::quiet_NaN());
+
+ open_power::occ::dbus::OccDBusSensors::getOccDBus()
+ .setOperationalStatus(sensorPath, false);
+
+ continue;
+ }
+ }
+
+ std::ifstream inputFile(filePathString + "input", std::ios::in);
+ if (inputFile)
+ {
+ double tempValue;
+ inputFile >> tempValue;
+
+ inputFile.close();
+
+ open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue(
+ sensorPath, tempValue * std::pow(10, -3));
+
+ open_power::occ::dbus::OccDBusSensors::getOccDBus()
+ .setOperationalStatus(sensorPath, true);
+
+ existingSensors[sensorPath] = id;
+ }
+ else
+ {
+ // If not able to read, OCC may be offline
+ log<level::DEBUG>(
+ fmt::format("readTempSensors: open failed(errno = {}) ",
+ open_errno)
+ .c_str());
+ }
+ }
+ return;
+}
+
+std::optional<std::string>
+ Manager::getPowerLabelFunctionID(const std::string& value)
+{
+ // If the value is "system", then the FunctionID is "system".
+ if (value == "system")
+ {
+ return value;
+ }
+
+ // If the value is not "system", then the label value have 3 numbers, of
+ // which we only care about the middle one:
+ // <sensor id>_<function id>_<apss channel>
+ // eg: The value is "0_10_5" , then the FunctionID is "10".
+ if (value.find("_") == std::string::npos)
+ {
+ return std::nullopt;
+ }
+
+ auto powerLabelValue = value.substr((value.find("_") + 1));
+
+ if (powerLabelValue.find("_") == std::string::npos)
+ {
+ return std::nullopt;
+ }
+
+ return powerLabelValue.substr(0, powerLabelValue.find("_"));
+}
+
+void Manager::readPowerSensors(const fs::path& path, uint32_t id)
+{
+ const int open_errno = errno;
+ std::regex expr{"power\\d+_label$"}; // Example: power5_label
+ for (auto& file : fs::directory_iterator(path))
+ {
+ if (!std::regex_search(file.path().string(), expr))
+ {
+ continue;
+ }
+ std::ifstream fileOpen(file.path(), std::ios::in);
+ if (!fileOpen)
+ {
+ // If not able to read, OCC may be offline
+ log<level::DEBUG>(
+ fmt::format("readPowerSensors: open failed(errno = {}) ",
+ open_errno)
+ .c_str());
+
+ continue;
+ }
+ std::string labelValue;
+ fileOpen >> labelValue;
+ fileOpen.close();
+
+ auto functionID = getPowerLabelFunctionID(labelValue);
+ if (functionID == std::nullopt)
+ {
+ continue;
+ }
+
+ const std::string& tempLabel = "label";
+ const std::string filePathString = file.path().string().substr(
+ 0, file.path().string().length() - tempLabel.length());
+
+ std::string sensorPath = OCC_SENSORS_ROOT + std::string("/power/");
+
+ auto iter = powerSensorName.find(*functionID);
+ if (iter == powerSensorName.end())
+ {
+ continue;
+ }
+ sensorPath.append(iter->second);
+
+ std::ifstream faultPathFile(filePathString + "fault", std::ios::in);
+ if (faultPathFile)
+ {
+ uint32_t faultValue{0};
+ faultPathFile >> faultValue;
+ faultPathFile.close();
+
+ if (faultValue != 0)
+ {
+ open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue(
+ sensorPath, std::numeric_limits<double>::quiet_NaN());
+
+ open_power::occ::dbus::OccDBusSensors::getOccDBus()
+ .setOperationalStatus(sensorPath, false);
+
+ continue;
+ }
+ }
+
+ std::ifstream inputFile(filePathString + "input", std::ios::in);
+ if (inputFile)
+ {
+ double tempValue;
+ inputFile >> tempValue;
+ inputFile.close();
+
+ open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue(
+ sensorPath, tempValue * std::pow(10, -3) * std::pow(10, -3));
+
+ open_power::occ::dbus::OccDBusSensors::getOccDBus()
+ .setOperationalStatus(sensorPath, true);
+
+ existingSensors[sensorPath] = id;
+ }
+ else
+ {
+ // If not able to read, OCC may be offline
+ log<level::DEBUG>(
+ fmt::format("readPowerSensors: open failed(errno = {}) ",
+ open_errno)
+ .c_str());
+ }
+ }
+ return;
+}
+
+void Manager::setSensorValueToNaN(uint32_t id)
+{
+ for (const auto& [sensorPath, occId] : existingSensors)
+ {
+ if (occId == id)
+ {
+ open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue(
+ sensorPath, std::numeric_limits<double>::quiet_NaN());
+ }
+ }
+ return;
+}
+
+void Manager::getSensorValues(uint32_t id, bool masterOcc)
+{
+ const auto occ = std::string("occ-hwmon.") + std::to_string(id + 1);
+
+ fs::path fileName{OCC_HWMON_PATH + occ + "/hwmon/"};
+
+ // Need to get the hwmonXX directory name, there better only be 1 dir
+ assert(std::distance(fs::directory_iterator(fileName),
+ fs::directory_iterator{}) == 1);
+ // Now set our path to this full path, including this hwmonXX directory
+ fileName = fs::path(*fs::directory_iterator(fileName));
+
+ // Read temperature sensors
+ readTempSensors(fileName, id);
+
+ if (masterOcc)
+ {
+ // Read power sensors
+ readPowerSensors(fileName, id);
+ }
+
+ return;
+}
+#endif
+
} // namespace occ
} // namespace open_power
diff --git a/occ_manager.hpp b/occ_manager.hpp
index ece7fb7..e6e8cbb 100644
--- a/occ_manager.hpp
+++ b/occ_manager.hpp
@@ -24,8 +24,21 @@
namespace occ
{
+#ifdef READ_OCC_SENSORS
+enum occFruType
+{
+ processorCore = 0,
+ internalMemCtlr = 1,
+ dimm = 2,
+ memCtrlAndDimm = 3,
+ VRMVdd = 6,
+ PMIC = 7,
+ memCtlrExSensor = 8
+};
+#endif
+
/** @brief Default time, in seconds, between OCC poll commands */
-constexpr unsigned int defaultPollingInterval = 10;
+constexpr unsigned int defaultPollingInterval = 1;
/** @class Manager
* @brief Builds and manages OCC objects
@@ -178,6 +191,68 @@
* OCC. The poll timer will then be restarted.
* */
void pollerTimerExpired();
+
+#ifdef READ_OCC_SENSORS
+ /**
+ * @brief Gets the occ sensor values.
+ * @param[in] id - Id of the OCC.
+ * @param[in] masterOcc - Is this OCC the master OCC.
+ * */
+ void getSensorValues(uint32_t id, bool masterOcc);
+
+ /**
+ * @brief Trigger OCC driver to read the temperature sensors.
+ * @param[in] path - path of the OCC sensors.
+ * @param[in] id - Id of the OCC.
+ * */
+ void readTempSensors(const fs::path& path, uint32_t id);
+
+ /**
+ * @brief Trigger OCC driver to read the power sensors.
+ * @param[in] path - path of the OCC sensors.
+ * @param[in] id - Id of the OCC.
+ * */
+ void readPowerSensors(const fs::path& path, uint32_t id);
+
+ /**
+ * @brief Set all sensor values of this OCC to NaN.
+ * @param[in] id - Id of the OCC.
+ * */
+ void setSensorValueToNaN(uint32_t id);
+
+ /** @brief Store the existing OCC sensors on D-BUS */
+ std::map<std::string, uint32_t> existingSensors;
+
+ /** @brief Get FunctionID from the `powerX_label` file.
+ * @param[in] value - the value of the `powerX_label` file.
+ * @returns FunctionID of the power sensors.
+ */
+ std::optional<std::string>
+ getPowerLabelFunctionID(const std::string& value);
+
+ /** @brief The power sensor names map */
+ const std::map<std::string, std::string> powerSensorName = {
+ {"system", "total_power"}, {"1", "p0_mem_power"},
+ {"2", "p1_mem_power"}, {"3", "p2_mem_power"},
+ {"4", "p3_mem_power"}, {"5", "p0_power"},
+ {"6", "p1_power"}, {"7", "p2_power"},
+ {"8", "p3_power"}, {"9", "p0_cache_power"},
+ {"10", "p1_cache_power"}, {"11", "p2_cache_power"},
+ {"12", "p3_cache_power"}, {"13", "io_a_power"},
+ {"14", "io_b_power"}, {"15", "io_c_power"},
+ {"16", "fans_a_power"}, {"17", "fans_b_power"},
+ {"18", "storage_a_power"}, {"19", "storage_b_power"},
+ {"23", "mem_cache_power"}, {"25", "p0_mem_0_power"},
+ {"26", "p0_mem_1_power"}, {"27", "p0_mem_2_power"}};
+
+ /** @brief The dimm temperature sensor names map */
+ const std::map<uint32_t, std::string> dimmTempSensorName = {
+ {internalMemCtlr, "_intmb_temp"},
+ {dimm, "_dram_temp"},
+ {memCtrlAndDimm, "_dram_extmb_temp"},
+ {PMIC, "_pmic_temp"},
+ {memCtlrExSensor, "_extmb_temp"}};
+#endif
};
} // namespace occ
diff --git a/occ_status.hpp b/occ_status.hpp
index 415e0b7..a1cf82e 100644
--- a/occ_status.hpp
+++ b/occ_status.hpp
@@ -146,6 +146,18 @@
return device.addPresenceWatchMaster();
}
+ /** @brief Gets the occ instance number */
+ unsigned int getOccInstanceID()
+ {
+ return instance;
+ }
+
+ /** @brief Is this OCC the master OCC */
+ bool isMasterOcc()
+ {
+ return device.master();
+ }
+
/** @brief Read OCC state (will trigger kernel to poll the OCC) */
void readOccState();