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/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