blob: 7f21c4b09c319be00d6d8bf44264ed8941867dd2 [file] [log] [blame]
Matthew Barthbf7b7b12017-03-07 15:46:59 -06001#pragma once
2
3#include <experimental/filesystem>
Matt Spinlerb4e65572017-10-17 10:09:18 -05004#include <phosphor-logging/elog-errors.hpp>
5#include <phosphor-logging/log.hpp>
6#include <xyz/openbmc_project/Sensor/Device/error.hpp>
Patrick Venture7a5285d2018-04-17 19:15:05 -07007#include "env.hpp"
Matthew Barth048ac872017-03-09 14:36:08 -06008#include "fan_speed.hpp"
Patrick Venture9331ab72018-01-29 09:48:47 -08009#include "fan_pwm.hpp"
Patrick Venture75e56c62018-04-20 18:10:15 -070010#include "hwmonio.hpp"
Matthew Barthbf7b7b12017-03-07 15:46:59 -060011
Matt Spinlera7e2c1e2018-02-23 12:18:19 -060012enum class targetType
13{
14 DEFAULT,
15 RPM,
16 PWM
17};
18
19static constexpr auto RPM_TARGET = "RPM";
20static constexpr auto PWM_TARGET = "PWM";
21
Matthew Barthbf7b7b12017-03-07 15:46:59 -060022/** @class Targets
23 * @brief Target type traits.
24 *
25 * @tparam T - The target type.
26 */
27template <typename T>
28struct Targets
29{
30 static void fail()
31 {
32 static_assert(sizeof(Targets) == -1, "Unsupported Target type");
33 }
34};
35
36/**@brief Targets specialization for fan speed. */
37template <>
Matthew Barth048ac872017-03-09 14:36:08 -060038struct Targets<hwmon::FanSpeed>
Matthew Barthbf7b7b12017-03-07 15:46:59 -060039{
40 static constexpr InterfaceType type = InterfaceType::FAN_SPEED;
Matthew Barthbf7b7b12017-03-07 15:46:59 -060041};
42
Patrick Venture9331ab72018-01-29 09:48:47 -080043template <>
44struct Targets<hwmon::FanPwm>
45{
46 static constexpr InterfaceType type = InterfaceType::FAN_PWM;
47};
48
Matthew Barthbf7b7b12017-03-07 15:46:59 -060049/** @brief addTarget
50 *
51 * Creates the target type interface
52 *
53 * @tparam T - The target type
54 *
55 * @param[in] sensor - A sensor type and name
Matt Spinlerb4e65572017-10-17 10:09:18 -050056 * @param[in] ioAccess - hwmon sysfs access object
57 * @param[in] devPath - The /sys/devices sysfs path
Matthew Barthbf7b7b12017-03-07 15:46:59 -060058 * @param[in] info - The sdbusplus server connection and interfaces
Matt Spinler0a8de642017-05-11 10:59:39 -050059 *
60 * @return A shared pointer to the target interface object
61 * Will be empty if no interface was created
Matthew Barthbf7b7b12017-03-07 15:46:59 -060062 */
63template <typename T>
Matt Spinler0a8de642017-05-11 10:59:39 -050064std::shared_ptr<T> addTarget(const SensorSet::key_type& sensor,
Patrick Venture75e56c62018-04-20 18:10:15 -070065 const hwmonio::HwmonIO& ioAccess,
Brad Bishop751043e2017-08-29 11:13:46 -040066 const std::string& devPath,
Matt Spinler0a8de642017-05-11 10:59:39 -050067 ObjectInfo& info)
Matthew Barthbf7b7b12017-03-07 15:46:59 -060068{
Matt Spinler0a8de642017-05-11 10:59:39 -050069 std::shared_ptr<T> target;
Matthew Barthbf7b7b12017-03-07 15:46:59 -060070 namespace fs = std::experimental::filesystem;
71 static constexpr bool deferSignals = true;
72
73 auto& bus = *std::get<sdbusplus::bus::bus*>(info);
74 auto& obj = std::get<Object>(info);
75 auto& objPath = std::get<std::string>(info);
Patrick Venture9331ab72018-01-29 09:48:47 -080076 auto type = Targets<T>::type;
Matthew Barthbf7b7b12017-03-07 15:46:59 -060077
78 // Check if target sysfs file exists
Patrick Venture9331ab72018-01-29 09:48:47 -080079 std::string sysfsFullPath;
Lei YUa4bba962018-01-31 13:51:05 +080080 std::string targetName = sensor.first;
81 std::string targetId = sensor.second;
82 std::string entry = hwmon::entry::target;
Patrick Venture9331ab72018-01-29 09:48:47 -080083
84 using namespace std::literals;
85 const std::string pwm = "pwm"s;
86 const std::string empty = ""s;
87
88 if (InterfaceType::FAN_PWM == type)
89 {
Lei YUa4bba962018-01-31 13:51:05 +080090 targetName = pwm;
91 // If PWM_TARGET is set, use the specified pwm id
Patrick Venture7a5285d2018-04-17 19:15:05 -070092 auto id = env::getEnv("PWM_TARGET", sensor);
Lei YUa4bba962018-01-31 13:51:05 +080093 if (!id.empty())
94 {
95 targetId = id;
96 }
97 entry = empty;
Patrick Venture9331ab72018-01-29 09:48:47 -080098 }
99
Lei YUa4bba962018-01-31 13:51:05 +0800100 sysfsFullPath = sysfs::make_sysfs_path(ioAccess.path(),
101 targetName,
102 targetId,
103 entry);
Matthew Barth048ac872017-03-09 14:36:08 -0600104 if (fs::exists(sysfsFullPath))
Matthew Barthbf7b7b12017-03-07 15:46:59 -0600105 {
Matthew Barth28f8e662018-03-26 16:57:36 -0500106 auto useTarget = true;
Patrick Venturea24c8802018-04-17 19:38:06 -0700107 auto tmEnv = env::getEnv("TARGET_MODE");
108 if (!tmEnv.empty())
Matt Spinlerb4e65572017-10-17 10:09:18 -0500109 {
Matthew Barth28f8e662018-03-26 16:57:36 -0500110 std::string mode{tmEnv};
111 std::transform(mode.begin(), mode.end(), mode.begin(), toupper);
Matt Spinlerb4e65572017-10-17 10:09:18 -0500112
Matthew Barth28f8e662018-03-26 16:57:36 -0500113 if (mode == RPM_TARGET)
114 {
115 if (type != InterfaceType::FAN_SPEED)
116 {
117 useTarget = false;
118 }
119 }
120 else if (mode == PWM_TARGET)
121 {
122 if (type != InterfaceType::FAN_PWM)
123 {
124 useTarget = false;
125 }
126 }
127 else
128 {
129 using namespace phosphor::logging;
130 log<level::ERR>("Invalid TARGET_MODE env var found",
131 phosphor::logging::entry(
132 "TARGET_MODE=%s", tmEnv),
133 phosphor::logging::entry(
134 "DEVPATH=%s", devPath.c_str()));
135 }
Matt Spinlerb4e65572017-10-17 10:09:18 -0500136 }
137
Matthew Barth28f8e662018-03-26 16:57:36 -0500138 if (useTarget)
139 {
140 uint32_t targetSpeed = 0;
141
142 try
143 {
144 targetSpeed = ioAccess.read(
145 targetName,
146 targetId,
147 entry,
Patrick Venture75e56c62018-04-20 18:10:15 -0700148 hwmonio::retries,
149 hwmonio::delay);
Matthew Barth28f8e662018-03-26 16:57:36 -0500150 }
151 catch (const std::system_error& e)
152 {
153 using namespace phosphor::logging;
154 using namespace sdbusplus::xyz::openbmc_project::
155 Sensor::Device::Error;
156 using metadata = xyz::openbmc_project::Sensor::
157 Device::ReadFailure;
158
159 report<ReadFailure>(
160 metadata::CALLOUT_ERRNO(e.code().value()),
161 metadata::CALLOUT_DEVICE_PATH(devPath.c_str()));
162
163 log<level::INFO>("Logging failing sysfs file",
164 phosphor::logging::entry(
165 "FILE=%s", sysfsFullPath.c_str()));
166 }
167
168 target = std::make_shared<T>(ioAccess.path(),
169 devPath,
170 targetId,
171 bus,
172 objPath.c_str(),
173 deferSignals,
174 targetSpeed);
175 obj[type] = target;
176 }
Matthew Barthbf7b7b12017-03-07 15:46:59 -0600177 }
Matt Spinler0a8de642017-05-11 10:59:39 -0500178
179 return target;
Matthew Barthbf7b7b12017-03-07 15:46:59 -0600180}