summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick Venture <venture@google.com>2018-01-29 09:48:47 -0800
committerPatrick Venture <venture@google.com>2018-02-01 18:55:18 +0000
commit9331ab7846750a05b90efd845935bfd3275e694c (patch)
treeed061448835b198e1330f8a78fbf2fbd4b38df70
parentc8a8e0102e1bb9dd1e231f809e6327513eea3559 (diff)
downloadphosphor-hwmon-9331ab7846750a05b90efd845935bfd3275e694c.tar.gz
phosphor-hwmon-9331ab7846750a05b90efd845935bfd3275e694c.zip
Add fan pwm interface target
The current daemon only supports RPM-based fan control, whereas the hwmon interface for PWM is often present. This implements the Fan Control PWM dbus interface. This CL is not the complete solution, but if mixed with a follow-on CL that does this, I think it'll be ideal. For instance, this assumes the pwm number matches, whereas the other CL lets you specify the corresponding PWM target for the fan. Change-Id: I23aaa0619cdefba0a004ac0d26dc6b928e78f1e8 Signed-off-by: Patrick Venture <venture@google.com>
-rw-r--r--Makefile.am3
-rw-r--r--env.cpp4
-rw-r--r--env.hpp4
-rw-r--r--fan_pwm.cpp63
-rw-r--r--fan_pwm.hpp63
-rw-r--r--interface.hpp5
-rw-r--r--mainloop.cpp10
-rw-r--r--sysfs.hpp4
-rw-r--r--targets.hpp62
9 files changed, 202 insertions, 16 deletions
diff --git a/Makefile.am b/Makefile.am
index 359db2e..aaa55bf 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -22,6 +22,7 @@ libhwmon_la_SOURCES = \
mainloop.cpp \
sysfs.cpp \
env.cpp \
- fan_speed.cpp
+ fan_speed.cpp \
+ fan_pwm.cpp
SUBDIRS = . test msl
diff --git a/env.cpp b/env.cpp
index 48963f9..ab4b35c 100644
--- a/env.cpp
+++ b/env.cpp
@@ -16,9 +16,9 @@
#include <cstdlib>
#include <fstream>
-#include <string>
+
+#include "env.hpp"
#include "hwmon.hpp"
-#include "sensorset.hpp"
std::string getEnv(
const char* prefix, const SensorSet::key_type& sensor)
diff --git a/env.hpp b/env.hpp
index 1b64a93..e14dd17 100644
--- a/env.hpp
+++ b/env.hpp
@@ -1,6 +1,8 @@
#pragma once
-class SensorSet;
+#include <string>
+
+#include "sensorset.hpp"
/** @brief Reads an environment variable
*
diff --git a/fan_pwm.cpp b/fan_pwm.cpp
new file mode 100644
index 0000000..04cb1b5
--- /dev/null
+++ b/fan_pwm.cpp
@@ -0,0 +1,63 @@
+#include "env.hpp"
+#include "fan_pwm.hpp"
+#include "hwmon.hpp"
+#include "sensorset.hpp"
+#include "sysfs.hpp"
+
+#include <phosphor-logging/elog-errors.hpp>
+#include <xyz/openbmc_project/Control/Device/error.hpp>
+
+#include <experimental/filesystem>
+#include <string>
+
+using namespace phosphor::logging;
+
+namespace hwmon
+{
+
+uint64_t FanPwm::target(uint64_t value)
+{
+ auto curValue = FanPwmObject::target();
+ using namespace std::literals;
+
+ if (curValue != value)
+ {
+ std::string empty;
+ //Write target out to sysfs
+ try {
+ ioAccess.write(
+ value,
+ type,
+ id,
+ empty,
+ sysfs::hwmonio::retries,
+ sysfs::hwmonio::delay);
+ }
+ catch (const std::system_error& e)
+ {
+ using namespace sdbusplus::xyz::openbmc_project::Control::
+ Device::Error;
+ report<WriteFailure>(
+ xyz::openbmc_project::Control::Device::
+ WriteFailure::CALLOUT_ERRNO(e.code().value()),
+ xyz::openbmc_project::Control::Device::
+ WriteFailure::CALLOUT_DEVICE_PATH(devPath.c_str()));
+
+ auto file = sysfs::make_sysfs_path(
+ ioAccess.path(),
+ type,
+ id,
+ empty);
+
+ log<level::INFO>("Logging failing sysfs file",
+ phosphor::logging::entry("FILE=%s", file.c_str()));
+
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ return FanPwmObject::target(value);
+}
+
+} // namespace hwmon
+
diff --git a/fan_pwm.hpp b/fan_pwm.hpp
new file mode 100644
index 0000000..1541779
--- /dev/null
+++ b/fan_pwm.hpp
@@ -0,0 +1,63 @@
+#pragma once
+
+#include "interface.hpp"
+#include "sysfs.hpp"
+
+namespace hwmon
+{
+
+/**
+ * @class FanPwm
+ * @brief Target fan pwm control implementation
+ * @details Derived FanPwmObject type that writes the target value to sysfs
+ * which in turn sets the fan speed to that target value
+ */
+class FanPwm : public FanPwmObject
+{
+ public:
+
+ /**
+ * @brief Constructs FanPwm Object
+ *
+ * @param[in] instancePath - The hwmon instance path
+ * (ex. /sys/class/hwmon/hwmon1)
+ * @param[in] devPath - The /sys/devices sysfs path
+ * @param[in] id - The hwmon id
+ * @param[in] bus - Dbus bus object
+ * @param[in] objPath - Dbus object path
+ * @param[in] defer - Dbus object registration defer
+ */
+ FanPwm(const std::string& instancePath,
+ const std::string& devPath,
+ const std::string& id,
+ sdbusplus::bus::bus& bus,
+ const char* objPath,
+ bool defer,
+ uint64_t target) : FanPwmObject(bus, objPath, defer),
+ id(id),
+ ioAccess(instancePath),
+ devPath(devPath)
+ {
+ FanPwmObject::target(target);
+ }
+
+ /**
+ * @brief Set the value of target
+ *
+ * @return Value of target
+ */
+ uint64_t target(uint64_t value) override;
+
+ private:
+ /** @brief hwmon type */
+ static constexpr auto type = "pwm";
+ /** @brief hwmon id */
+ std::string id;
+ /** @brief Hwmon sysfs access. */
+ sysfs::hwmonio::HwmonIO ioAccess;
+ /** @brief Physical device path. */
+ std::string devPath;
+};
+
+} // namespace hwmon
+
diff --git a/interface.hpp b/interface.hpp
index 535d301..da939c2 100644
--- a/interface.hpp
+++ b/interface.hpp
@@ -4,6 +4,7 @@
#include "xyz/openbmc_project/Sensor/Threshold/Warning/server.hpp"
#include "xyz/openbmc_project/Sensor/Threshold/Critical/server.hpp"
#include "xyz/openbmc_project/Control/FanSpeed/server.hpp"
+#include "xyz/openbmc_project/Control/FanPwm/server.hpp"
#include <sdbusplus/server.hpp>
template <typename... T>
@@ -20,6 +21,9 @@ using CriticalObject = ServerObject<CriticalInterface>;
using FanSpeedInterface =
sdbusplus::xyz::openbmc_project::Control::server::FanSpeed;
using FanSpeedObject = ServerObject<FanSpeedInterface>;
+using FanPwmInterface =
+ sdbusplus::xyz::openbmc_project::Control::server::FanPwm;
+using FanPwmObject = ServerObject<FanPwmInterface>;
enum class InterfaceType
{
@@ -27,6 +31,7 @@ enum class InterfaceType
WARN,
CRIT,
FAN_SPEED,
+ FAN_PWM,
};
// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
diff --git a/mainloop.cpp b/mainloop.cpp
index 2aa9e0f..419bfc7 100644
--- a/mainloop.cpp
+++ b/mainloop.cpp
@@ -29,6 +29,7 @@
#include "thresholds.hpp"
#include "targets.hpp"
#include "fan_speed.hpp"
+#include "fan_pwm.hpp"
#include <xyz/openbmc_project/Sensor/Device/error.hpp>
@@ -354,6 +355,8 @@ void MainLoop::run()
target->enable();
}
+ addTarget<hwmon::FanPwm>(i.first, ioAccess, _devPath, info);
+
// All the interfaces have been created. Go ahead
// and emit InterfacesAdded.
valueInterface->emit_object_added();
@@ -406,6 +409,11 @@ void MainLoop::run()
{
// Read value from sensor.
int64_t value;
+ std::string input = hwmon::entry::cinput;
+ if (i.first.first == "pwm") {
+ input = "";
+ }
+
try
{
// Retry for up to a second if device is busy
@@ -414,7 +422,7 @@ void MainLoop::run()
value = ioAccess.read(
i.first.first,
i.first.second,
- hwmon::entry::cinput,
+ input,
sysfs::hwmonio::retries,
sysfs::hwmonio::delay);
diff --git a/sysfs.hpp b/sysfs.hpp
index e3090c3..3bcca53 100644
--- a/sysfs.hpp
+++ b/sysfs.hpp
@@ -14,6 +14,10 @@ inline std::string make_sysfs_path(const std::string& path,
{
using namespace std::literals;
+ if (entry.empty()) {
+ return path + "/"s + type + id;
+ }
+
return path + "/"s + type + id + "_"s + entry;
}
diff --git a/targets.hpp b/targets.hpp
index 5e938b0..b671467 100644
--- a/targets.hpp
+++ b/targets.hpp
@@ -5,6 +5,7 @@
#include <phosphor-logging/log.hpp>
#include <xyz/openbmc_project/Sensor/Device/error.hpp>
#include "fan_speed.hpp"
+#include "fan_pwm.hpp"
/** @class Targets
* @brief Target type traits.
@@ -27,6 +28,12 @@ struct Targets<hwmon::FanSpeed>
static constexpr InterfaceType type = InterfaceType::FAN_SPEED;
};
+template <>
+struct Targets<hwmon::FanPwm>
+{
+ static constexpr InterfaceType type = InterfaceType::FAN_PWM;
+};
+
/** @brief addTarget
*
* Creates the target type interface
@@ -54,25 +61,58 @@ std::shared_ptr<T> addTarget(const SensorSet::key_type& sensor,
auto& bus = *std::get<sdbusplus::bus::bus*>(info);
auto& obj = std::get<Object>(info);
auto& objPath = std::get<std::string>(info);
+ auto type = Targets<T>::type;
// Check if target sysfs file exists
- auto sysfsFullPath = sysfs::make_sysfs_path(ioAccess.path(),
- sensor.first,
- sensor.second,
- hwmon::entry::target);
+ std::string sysfsFullPath;
+
+ using namespace std::literals;
+ const std::string pwm = "pwm"s;
+ const std::string empty = ""s;
+
+ if (InterfaceType::FAN_PWM == type)
+ {
+ /* We're leveraging that the sensor ID matches for PWM.
+ * TODO(venture): There's a CL from intel that allows
+ * this to be specified via an environment variable.
+ */
+ sysfsFullPath = sysfs::make_sysfs_path(ioAccess.path(),
+ pwm,
+ sensor.second,
+ empty);
+ }
+ else
+ {
+ sysfsFullPath = sysfs::make_sysfs_path(ioAccess.path(),
+ sensor.first,
+ sensor.second,
+ hwmon::entry::target);
+ }
+
if (fs::exists(sysfsFullPath))
{
uint32_t targetSpeed = 0;
try
{
- targetSpeed = ioAccess.read(
- sensor.first,
- sensor.second,
- hwmon::entry::target,
- sysfs::hwmonio::retries,
- sysfs::hwmonio::delay);
-
+ if (InterfaceType::FAN_PWM == type)
+ {
+ targetSpeed = ioAccess.read(
+ pwm,
+ sensor.second,
+ empty,
+ sysfs::hwmonio::retries,
+ sysfs::hwmonio::delay);
+ }
+ else
+ {
+ targetSpeed = ioAccess.read(
+ sensor.first,
+ sensor.second,
+ hwmon::entry::target,
+ sysfs::hwmonio::retries,
+ sysfs::hwmonio::delay);
+ }
}
catch (const std::system_error& e)
{
OpenPOWER on IntegriCloud