blob: 317eec5ba9ae1a0e5862f1e71161fdd68ce3de96 [file] [log] [blame]
Matthew Barthbf7b7b12017-03-07 15:46:59 -06001#pragma once
2
Patrick Venture043d3232018-08-31 10:10:53 -07003#include "env.hpp"
4#include "fan_pwm.hpp"
5#include "fan_speed.hpp"
6#include "hwmonio.hpp"
7
Matthew Barthbf7b7b12017-03-07 15:46:59 -06008#include <experimental/filesystem>
Patrick Venture50552372018-06-07 10:53:56 -07009#include <memory>
Matt Spinlerb4e65572017-10-17 10:09:18 -050010#include <phosphor-logging/elog-errors.hpp>
11#include <phosphor-logging/log.hpp>
12#include <xyz/openbmc_project/Sensor/Device/error.hpp>
Matthew Barthbf7b7b12017-03-07 15:46:59 -060013
Matt Spinlera7e2c1e2018-02-23 12:18:19 -060014enum class targetType
15{
16 DEFAULT,
17 RPM,
18 PWM
19};
20
21static constexpr auto RPM_TARGET = "RPM";
22static constexpr auto PWM_TARGET = "PWM";
23
Matthew Barthbf7b7b12017-03-07 15:46:59 -060024/** @class Targets
25 * @brief Target type traits.
26 *
27 * @tparam T - The target type.
28 */
29template <typename T>
30struct Targets
31{
32 static void fail()
33 {
34 static_assert(sizeof(Targets) == -1, "Unsupported Target type");
35 }
36};
37
38/**@brief Targets specialization for fan speed. */
39template <>
Matthew Barth048ac872017-03-09 14:36:08 -060040struct Targets<hwmon::FanSpeed>
Matthew Barthbf7b7b12017-03-07 15:46:59 -060041{
42 static constexpr InterfaceType type = InterfaceType::FAN_SPEED;
Matthew Barthbf7b7b12017-03-07 15:46:59 -060043};
44
Patrick Venture9331ab72018-01-29 09:48:47 -080045template <>
46struct Targets<hwmon::FanPwm>
47{
48 static constexpr InterfaceType type = InterfaceType::FAN_PWM;
49};
50
Matthew Barthbf7b7b12017-03-07 15:46:59 -060051/** @brief addTarget
52 *
53 * Creates the target type interface
54 *
55 * @tparam T - The target type
56 *
57 * @param[in] sensor - A sensor type and name
Matt Spinlerb4e65572017-10-17 10:09:18 -050058 * @param[in] ioAccess - hwmon sysfs access object
59 * @param[in] devPath - The /sys/devices sysfs path
Matthew Barthbf7b7b12017-03-07 15:46:59 -060060 * @param[in] info - The sdbusplus server connection and interfaces
Matt Spinler0a8de642017-05-11 10:59:39 -050061 *
62 * @return A shared pointer to the target interface object
63 * Will be empty if no interface was created
Matthew Barthbf7b7b12017-03-07 15:46:59 -060064 */
65template <typename T>
Matt Spinler0a8de642017-05-11 10:59:39 -050066std::shared_ptr<T> addTarget(const SensorSet::key_type& sensor,
Patrick Venture75e56c62018-04-20 18:10:15 -070067 const hwmonio::HwmonIO& ioAccess,
Patrick Venture043d3232018-08-31 10:10:53 -070068 const std::string& devPath, ObjectInfo& info)
Matthew Barthbf7b7b12017-03-07 15:46:59 -060069{
Matt Spinler0a8de642017-05-11 10:59:39 -050070 std::shared_ptr<T> target;
Matthew Barthbf7b7b12017-03-07 15:46:59 -060071 namespace fs = std::experimental::filesystem;
72 static constexpr bool deferSignals = true;
73
74 auto& bus = *std::get<sdbusplus::bus::bus*>(info);
75 auto& obj = std::get<Object>(info);
76 auto& objPath = std::get<std::string>(info);
Patrick Venture9331ab72018-01-29 09:48:47 -080077 auto type = Targets<T>::type;
Matthew Barthbf7b7b12017-03-07 15:46:59 -060078
79 // Check if target sysfs file exists
Patrick Venture9331ab72018-01-29 09:48:47 -080080 std::string sysfsFullPath;
Lei YUa4bba962018-01-31 13:51:05 +080081 std::string targetName = sensor.first;
82 std::string targetId = sensor.second;
83 std::string entry = hwmon::entry::target;
Patrick Venture9331ab72018-01-29 09:48:47 -080084
85 using namespace std::literals;
86 const std::string pwm = "pwm"s;
87 const std::string empty = ""s;
88
89 if (InterfaceType::FAN_PWM == type)
90 {
Lei YUa4bba962018-01-31 13:51:05 +080091 targetName = pwm;
92 // If PWM_TARGET is set, use the specified pwm id
Patrick Venture7a5285d2018-04-17 19:15:05 -070093 auto id = env::getEnv("PWM_TARGET", sensor);
Lei YUa4bba962018-01-31 13:51:05 +080094 if (!id.empty())
95 {
96 targetId = id;
97 }
98 entry = empty;
Patrick Venture9331ab72018-01-29 09:48:47 -080099 }
100
Patrick Venture043d3232018-08-31 10:10:53 -0700101 sysfsFullPath =
102 sysfs::make_sysfs_path(ioAccess.path(), targetName, targetId, entry);
Matthew Barth048ac872017-03-09 14:36:08 -0600103 if (fs::exists(sysfsFullPath))
Matthew Barthbf7b7b12017-03-07 15:46:59 -0600104 {
Matthew Barth28f8e662018-03-26 16:57:36 -0500105 auto useTarget = true;
Patrick Venturea24c8802018-04-17 19:38:06 -0700106 auto tmEnv = env::getEnv("TARGET_MODE");
107 if (!tmEnv.empty())
Matt Spinlerb4e65572017-10-17 10:09:18 -0500108 {
Matthew Barth28f8e662018-03-26 16:57:36 -0500109 std::string mode{tmEnv};
110 std::transform(mode.begin(), mode.end(), mode.begin(), toupper);
Matt Spinlerb4e65572017-10-17 10:09:18 -0500111
Matthew Barth28f8e662018-03-26 16:57:36 -0500112 if (mode == RPM_TARGET)
113 {
114 if (type != InterfaceType::FAN_SPEED)
115 {
116 useTarget = false;
117 }
118 }
119 else if (mode == PWM_TARGET)
120 {
121 if (type != InterfaceType::FAN_PWM)
122 {
123 useTarget = false;
124 }
125 }
126 else
127 {
128 using namespace phosphor::logging;
Patrick Venture043d3232018-08-31 10:10:53 -0700129 log<level::ERR>(
130 "Invalid TARGET_MODE env var found",
131 phosphor::logging::entry("TARGET_MODE=%s", tmEnv.c_str()),
132 phosphor::logging::entry("DEVPATH=%s", devPath.c_str()));
Matthew Barth28f8e662018-03-26 16:57:36 -0500133 }
Matt Spinlerb4e65572017-10-17 10:09:18 -0500134 }
135
Matthew Barth28f8e662018-03-26 16:57:36 -0500136 if (useTarget)
137 {
138 uint32_t targetSpeed = 0;
139
140 try
141 {
Patrick Venture043d3232018-08-31 10:10:53 -0700142 targetSpeed = ioAccess.read(targetName, targetId, entry,
143 hwmonio::retries, hwmonio::delay);
Matthew Barth28f8e662018-03-26 16:57:36 -0500144 }
145 catch (const std::system_error& e)
146 {
147 using namespace phosphor::logging;
Patrick Venture043d3232018-08-31 10:10:53 -0700148 using namespace sdbusplus::xyz::openbmc_project::Sensor::
149 Device::Error;
150 using metadata =
151 xyz::openbmc_project::Sensor::Device::ReadFailure;
Matthew Barth28f8e662018-03-26 16:57:36 -0500152
153 report<ReadFailure>(
Patrick Venture043d3232018-08-31 10:10:53 -0700154 metadata::CALLOUT_ERRNO(e.code().value()),
155 metadata::CALLOUT_DEVICE_PATH(devPath.c_str()));
Matthew Barth28f8e662018-03-26 16:57:36 -0500156
Patrick Venture043d3232018-08-31 10:10:53 -0700157 log<level::INFO>(
158 "Logging failing sysfs file",
159 phosphor::logging::entry("FILE=%s", sysfsFullPath.c_str()));
Matthew Barth28f8e662018-03-26 16:57:36 -0500160 }
161
Patrick Venture50552372018-06-07 10:53:56 -0700162 // ioAccess.path() is a path like: /sys/class/hwmon/hwmon1
163 target = std::make_shared<T>(
Patrick Venture043d3232018-08-31 10:10:53 -0700164 std::move(std::make_unique<hwmonio::HwmonIO>(ioAccess.path())),
165 devPath, targetId, bus, objPath.c_str(), deferSignals,
166 targetSpeed);
Matthew Barth28f8e662018-03-26 16:57:36 -0500167 obj[type] = target;
168 }
Matthew Barthbf7b7b12017-03-07 15:46:59 -0600169 }
Matt Spinler0a8de642017-05-11 10:59:39 -0500170
171 return target;
Matthew Barthbf7b7b12017-03-07 15:46:59 -0600172}