diff options
author | Patrick Venture <venture@google.com> | 2018-01-29 09:48:47 -0800 |
---|---|---|
committer | Patrick Venture <venture@google.com> | 2018-02-01 18:55:18 +0000 |
commit | 9331ab7846750a05b90efd845935bfd3275e694c (patch) | |
tree | ed061448835b198e1330f8a78fbf2fbd4b38df70 | |
parent | c8a8e0102e1bb9dd1e231f809e6327513eea3559 (diff) | |
download | phosphor-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.am | 3 | ||||
-rw-r--r-- | env.cpp | 4 | ||||
-rw-r--r-- | env.hpp | 4 | ||||
-rw-r--r-- | fan_pwm.cpp | 63 | ||||
-rw-r--r-- | fan_pwm.hpp | 63 | ||||
-rw-r--r-- | interface.hpp | 5 | ||||
-rw-r--r-- | mainloop.cpp | 10 | ||||
-rw-r--r-- | sysfs.hpp | 4 | ||||
-rw-r--r-- | targets.hpp | 62 |
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 @@ -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) @@ -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); @@ -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) { |