diff options
-rw-r--r-- | monitor/Makefile.am | 4 | ||||
-rw-r--r-- | monitor/fan.cpp | 113 | ||||
-rw-r--r-- | monitor/fan.hpp | 134 | ||||
-rw-r--r-- | monitor/tach_sensor.cpp | 49 | ||||
-rw-r--r-- | monitor/tach_sensor.hpp | 146 |
5 files changed, 445 insertions, 1 deletions
diff --git a/monitor/Makefile.am b/monitor/Makefile.am index ceec3dd..26b66b5 100644 --- a/monitor/Makefile.am +++ b/monitor/Makefile.am @@ -5,8 +5,10 @@ sbin_PROGRAMS = \ phosphor-fan-monitor phosphor_fan_monitor_SOURCES = \ + fan.cpp \ generated.cpp \ - main.cpp + main.cpp \ + tach_sensor.cpp phosphor_fan_monitor_LDADD = \ $(SDBUSPLUS_LIBS) \ diff --git a/monitor/fan.cpp b/monitor/fan.cpp new file mode 100644 index 0000000..b29eaab --- /dev/null +++ b/monitor/fan.cpp @@ -0,0 +1,113 @@ +/** + * Copyright © 2017 IBM Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <algorithm> +#include <phosphor-logging/log.hpp> +#include "fan.hpp" +#include "types.hpp" + +namespace phosphor +{ +namespace fan +{ +namespace monitor +{ + +using namespace phosphor::logging; + +Fan::Fan(sdbusplus::bus::bus& bus, + std::shared_ptr<sd_event>& events, + const FanDefinition& def) : + _bus(bus), + _name(std::get<fanNameField>(def)), + _deviation(std::get<fanDeviationField>(def)), + _numSensorFailsForNonFunc(std::get<numSensorFailsForNonfuncField>(def)) +{ + auto& sensors = std::get<sensorListField>(def); + + for (auto& s : sensors) + { + _sensors.emplace_back( + std::make_unique<TachSensor>(bus, + *this, + std::get<sensorNameField>(s), + std::get<hasTargetField>(s), + std::get<timeoutField>(def))); + + } + +} + + +uint64_t Fan::getTargetSpeed(const TachSensor& sensor) +{ + uint64_t target = 0; + + if (sensor.hasTarget()) + { + target = sensor.getTarget(); + } + else + { + //The sensor doesn't support a target, + //so get it from another sensor. + auto s = std::find_if(_sensors.begin(), _sensors.end(), + [](const auto& s) + { + return s->hasTarget(); + }); + + if (s != _sensors.end()) + { + target = (*s)->getTarget(); + } + } + + return target; +} + + +bool Fan::tooManySensorsNonfunctional() +{ + size_t numFailed = std::count_if(_sensors.begin(), _sensors.end(), + [](const auto& s) + { + return !s->functional(); + }); + + return (numFailed >= _numSensorFailsForNonFunc); +} + + +bool Fan::outOfRange(const TachSensor& sensor) +{ + auto actual = static_cast<uint64_t>(sensor.getInput()); + auto target = getTargetSpeed(sensor); + + uint64_t min = target * (100 - _deviation) / 100; + uint64_t max = target * (100 + _deviation) / 100; + + if ((actual < min) || (actual > max)) + { + return true; + } + + return false; +} + + +} +} +} diff --git a/monitor/fan.hpp b/monitor/fan.hpp new file mode 100644 index 0000000..6cbd370 --- /dev/null +++ b/monitor/fan.hpp @@ -0,0 +1,134 @@ +#pragma once + +#include <sdbusplus/bus.hpp> +#include <tuple> +#include <vector> +#include "tach_sensor.hpp" +#include "types.hpp" + +namespace phosphor +{ +namespace fan +{ +namespace monitor +{ + + +/** + * @class Fan + * + * Represents a fan, which can contain 1 or more sensors which + * loosely correspond to rotors. See below. + * + * There is a sensor when hwmon exposes one, which means there is a + * speed value to be read. Sometimes there is a sensor per rotor, + * and other times multiple rotors just use 1 sensor total where + * the sensor reports the slowest speed of all of the rotors. + * + * A rotor's speed is set by writing the Target value of a sensor. + * Sometimes each sensor in a fan supports having a Target, and other + * times not all of them do. A TachSensor object knows if it supports + * the Target property. + * + * The strategy for monitoring fan speeds is as follows: + * + * Every time a Target (new speed written) or Input (actual speed read) + * sensor changes, check if the input value is within some range of the target + * value. If it isn't, start a timer at the end of which the sensor will be + * set to not functional. If enough sensors in the fan are now nonfunctional, + * set the whole fan to nonfunctional in the inventory. + * + * When sensor inputs come back within a specified range of the target, + * stop its timer if running, make the sensor functional again if it wasn't, + * and if enough sensors in the fan are now functional set the whole fan + * back to functional in the inventory. + */ +class Fan +{ + + public: + + Fan() = delete; + Fan(const Fan&) = delete; + Fan(Fan&&) = default; + Fan& operator=(const Fan&) = delete; + Fan& operator=(Fan&&) = default; + ~Fan() = default; + + /** + * @brief Constructor + * + * @param bus - the dbus object + * @param events - pointer to sd_event object + * @param def - the fan definition structure + */ + Fan(sdbusplus::bus::bus& bus, + std::shared_ptr<sd_event>& events, + const FanDefinition& def); + + + private: + + /** + * @brief Returns the target speed of the sensor + * + * If the sensor itself doesn't have a target, it finds + * the target speed from another sensor. + * + * @param[in] sensor - the sensor to get the target speed for + */ + uint64_t getTargetSpeed(const TachSensor& sensor); + + /** + * @brief Returns true if the sensor input is not within + * some deviation of the target. + * + * @param[in] sensor - the sensor to check + */ + bool outOfRange(const TachSensor& sensor); + + /** + * @brief Returns true if too many sensors are nonfunctional + * as defined by _numSensorFailsForNonFunc + */ + bool tooManySensorsNonfunctional(); + + + /** + * @brief the dbus object + */ + sdbusplus::bus::bus& _bus; + + /** + * @brief The inventory name of the fan + */ + const std::string _name; + + /** + * @brief The percentage that the input speed must be below + * the target speed to be considered an error. + * Between 0 and 100. + */ + const size_t _deviation; + + /** + * The number of sensors that must be nonfunctional at the + * same time in order for the fan to be set to nonfunctional + * in the inventory. + */ + const size_t _numSensorFailsForNonFunc; + + /** + * @brief The current functional state of the fan + */ + bool _functional = true; + + /** + * The sensor objects for the fan + */ + std::vector<std::unique_ptr<TachSensor>> _sensors; +}; + +} +} +} diff --git a/monitor/tach_sensor.cpp b/monitor/tach_sensor.cpp new file mode 100644 index 0000000..3264ddf --- /dev/null +++ b/monitor/tach_sensor.cpp @@ -0,0 +1,49 @@ +/** + * Copyright © 2017 IBM Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <phosphor-logging/log.hpp> +#include "fan.hpp" +#include "tach_sensor.hpp" +#include "../utility.hpp" + +namespace phosphor +{ +namespace fan +{ +namespace monitor +{ + +constexpr auto FAN_SENSOR_PATH = "/xyz/openbmc_project/sensors/fan_tach/"; + + +TachSensor::TachSensor(sdbusplus::bus::bus& bus, + Fan& fan, + const std::string& id, + bool hasTarget, + size_t timeout) : + + _bus(bus), + _fan(fan), + _name(FAN_SENSOR_PATH + id), + _hasTarget(hasTarget), + _timeout(timeout) +{ + //TODO +} + + +} +} +} diff --git a/monitor/tach_sensor.hpp b/monitor/tach_sensor.hpp new file mode 100644 index 0000000..df340f5 --- /dev/null +++ b/monitor/tach_sensor.hpp @@ -0,0 +1,146 @@ +#pragma once + +#include <chrono> +#include <sdbusplus/bus.hpp> +#include <sdbusplus/server.hpp> + +namespace phosphor +{ +namespace fan +{ +namespace monitor +{ + +class Fan; + + +/** + * @class TachSensor + * + * This class represents the sensor that reads a tach value. + * It may also support a Target, which is the property used to + * set a speed. Since it doesn't necessarily have a Target, it + * won't for sure know if it is running too slow, so it leaves + * that determination to other code. + * + * This class has a parent Fan object that knows about all + * sensors for that fan. + */ +class TachSensor +{ + public: + + TachSensor() = delete; + TachSensor(const TachSensor&) = delete; + TachSensor(TachSensor&&) = default; + TachSensor& operator=(const TachSensor&) = delete; + TachSensor& operator=(TachSensor&&) = default; + ~TachSensor() = default; + + /** + * @brief Constructor + * + * @param[in] bus - the dbus object + * @param[in] fan - the parent fan object + * @param[in] id - the id of the sensor + * @param[in] hasTarget - if the sensor supports + * setting the speed + * @param[in] timeout - Normal timeout value to use + */ + TachSensor(sdbusplus::bus::bus& bus, + Fan& fan, + const std::string& id, + bool hasTarget, + size_t timeout); + + /** + * @brief Returns the target speed value + */ + inline uint64_t getTarget() const + { + return _tachTarget; + } + + /** + * @brief Returns the input speed value + */ + inline int64_t getInput() const + { + return _tachInput; + } + + /** + * @brief Returns true if sensor has a target + */ + inline bool hasTarget() const + { + return _hasTarget; + } + + /** + * Returns true if the hardware behind this + * sensor is considered working OK/functional. + */ + inline bool functional() const + { + return _functional; + } + + /** + * Sets functional status + */ + inline void setFunctional(bool functional) + { + _functional = functional; + } + + private: + + /** + * @brief the dbus object + */ + sdbusplus::bus::bus& _bus; + + /** + * @brief Reference to the parent Fan object + */ + Fan& _fan; + + /** + * @brief The name of the sensor, including the full path + * + * For example /xyz/openbmc_project/sensors/fan_tach/fan0 + */ + const std::string _name; + + /** + * @brief If functional (not too slow). The parent + * fan object sets this. + */ + bool _functional = true; + + /** + * @brief If the sensor has a Target property (can set speed) + */ + const bool _hasTarget; + + /** + * @brief The input speed, from the Value dbus property + */ + int64_t _tachInput = 0; + + /** + * @brief The current target speed, from the Target dbus property + * (if applicable) + */ + uint64_t _tachTarget = 0; + + /** + * @brief The timeout value to use + */ + const size_t _timeout; +}; + +} +} +} |