blob: 9867ba97906445d84f01ba7935a684bc746eb033 [file] [log] [blame]
Matthew Barthbf7b7b12017-03-07 15:46:59 -06001#pragma once
2
3#include <experimental/filesystem>
Patrick Venture50552372018-06-07 10:53:56 -07004#include <memory>
Matt Spinlerb4e65572017-10-17 10:09:18 -05005#include <phosphor-logging/elog-errors.hpp>
6#include <phosphor-logging/log.hpp>
7#include <xyz/openbmc_project/Sensor/Device/error.hpp>
Patrick Venture7a5285d2018-04-17 19:15:05 -07008#include "env.hpp"
Matthew Barth048ac872017-03-09 14:36:08 -06009#include "fan_speed.hpp"
Patrick Venture9331ab72018-01-29 09:48:47 -080010#include "fan_pwm.hpp"
Patrick Venture75e56c62018-04-20 18:10:15 -070011#include "hwmonio.hpp"
Matthew Barthbf7b7b12017-03-07 15:46:59 -060012
Matt Spinlera7e2c1e2018-02-23 12:18:19 -060013enum class targetType
14{
15 DEFAULT,
16 RPM,
17 PWM
18};
19
20static constexpr auto RPM_TARGET = "RPM";
21static constexpr auto PWM_TARGET = "PWM";
22
Matthew Barthbf7b7b12017-03-07 15:46:59 -060023/** @class Targets
24 * @brief Target type traits.
25 *
26 * @tparam T - The target type.
27 */
28template <typename T>
29struct Targets
30{
31 static void fail()
32 {
33 static_assert(sizeof(Targets) == -1, "Unsupported Target type");
34 }
35};
36
37/**@brief Targets specialization for fan speed. */
38template <>
Matthew Barth048ac872017-03-09 14:36:08 -060039struct Targets<hwmon::FanSpeed>
Matthew Barthbf7b7b12017-03-07 15:46:59 -060040{
41 static constexpr InterfaceType type = InterfaceType::FAN_SPEED;
Matthew Barthbf7b7b12017-03-07 15:46:59 -060042};
43
Patrick Venture9331ab72018-01-29 09:48:47 -080044template <>
45struct Targets<hwmon::FanPwm>
46{
47 static constexpr InterfaceType type = InterfaceType::FAN_PWM;
48};
49
Matthew Barthbf7b7b12017-03-07 15:46:59 -060050/** @brief addTarget
51 *
52 * Creates the target type interface
53 *
54 * @tparam T - The target type
55 *
56 * @param[in] sensor - A sensor type and name
Matt Spinlerb4e65572017-10-17 10:09:18 -050057 * @param[in] ioAccess - hwmon sysfs access object
58 * @param[in] devPath - The /sys/devices sysfs path
Matthew Barthbf7b7b12017-03-07 15:46:59 -060059 * @param[in] info - The sdbusplus server connection and interfaces
Matt Spinler0a8de642017-05-11 10:59:39 -050060 *
61 * @return A shared pointer to the target interface object
62 * Will be empty if no interface was created
Matthew Barthbf7b7b12017-03-07 15:46:59 -060063 */
64template <typename T>
Matt Spinler0a8de642017-05-11 10:59:39 -050065std::shared_ptr<T> addTarget(const SensorSet::key_type& sensor,
Patrick Venture75e56c62018-04-20 18:10:15 -070066 const hwmonio::HwmonIO& ioAccess,
Brad Bishop751043e2017-08-29 11:13:46 -040067 const std::string& devPath,
Matt Spinler0a8de642017-05-11 10:59:39 -050068 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
Lei YUa4bba962018-01-31 13:51:05 +0800101 sysfsFullPath = sysfs::make_sysfs_path(ioAccess.path(),
102 targetName,
103 targetId,
104 entry);
Matthew Barth048ac872017-03-09 14:36:08 -0600105 if (fs::exists(sysfsFullPath))
Matthew Barthbf7b7b12017-03-07 15:46:59 -0600106 {
Matthew Barth28f8e662018-03-26 16:57:36 -0500107 auto useTarget = true;
Patrick Venturea24c8802018-04-17 19:38:06 -0700108 auto tmEnv = env::getEnv("TARGET_MODE");
109 if (!tmEnv.empty())
Matt Spinlerb4e65572017-10-17 10:09:18 -0500110 {
Matthew Barth28f8e662018-03-26 16:57:36 -0500111 std::string mode{tmEnv};
112 std::transform(mode.begin(), mode.end(), mode.begin(), toupper);
Matt Spinlerb4e65572017-10-17 10:09:18 -0500113
Matthew Barth28f8e662018-03-26 16:57:36 -0500114 if (mode == RPM_TARGET)
115 {
116 if (type != InterfaceType::FAN_SPEED)
117 {
118 useTarget = false;
119 }
120 }
121 else if (mode == PWM_TARGET)
122 {
123 if (type != InterfaceType::FAN_PWM)
124 {
125 useTarget = false;
126 }
127 }
128 else
129 {
130 using namespace phosphor::logging;
131 log<level::ERR>("Invalid TARGET_MODE env var found",
132 phosphor::logging::entry(
Joseph Reynolds5dc6fe72018-05-10 15:54:54 -0500133 "TARGET_MODE=%s", tmEnv.c_str()),
Matthew Barth28f8e662018-03-26 16:57:36 -0500134 phosphor::logging::entry(
135 "DEVPATH=%s", devPath.c_str()));
136 }
Matt Spinlerb4e65572017-10-17 10:09:18 -0500137 }
138
Matthew Barth28f8e662018-03-26 16:57:36 -0500139 if (useTarget)
140 {
141 uint32_t targetSpeed = 0;
142
143 try
144 {
145 targetSpeed = ioAccess.read(
146 targetName,
147 targetId,
148 entry,
Patrick Venture75e56c62018-04-20 18:10:15 -0700149 hwmonio::retries,
150 hwmonio::delay);
Matthew Barth28f8e662018-03-26 16:57:36 -0500151 }
152 catch (const std::system_error& e)
153 {
154 using namespace phosphor::logging;
155 using namespace sdbusplus::xyz::openbmc_project::
156 Sensor::Device::Error;
157 using metadata = xyz::openbmc_project::Sensor::
158 Device::ReadFailure;
159
160 report<ReadFailure>(
161 metadata::CALLOUT_ERRNO(e.code().value()),
162 metadata::CALLOUT_DEVICE_PATH(devPath.c_str()));
163
164 log<level::INFO>("Logging failing sysfs file",
165 phosphor::logging::entry(
166 "FILE=%s", sysfsFullPath.c_str()));
167 }
168
Patrick Venture50552372018-06-07 10:53:56 -0700169 // ioAccess.path() is a path like: /sys/class/hwmon/hwmon1
170 target = std::make_shared<T>(
171 std::move(std::make_unique<hwmonio::HwmonIO>(
172 ioAccess.path())),
173 devPath,
174 targetId,
175 bus,
176 objPath.c_str(),
177 deferSignals,
178 targetSpeed);
Matthew Barth28f8e662018-03-26 16:57:36 -0500179 obj[type] = target;
180 }
Matthew Barthbf7b7b12017-03-07 15:46:59 -0600181 }
Matt Spinler0a8de642017-05-11 10:59:39 -0500182
183 return target;
Matthew Barthbf7b7b12017-03-07 15:46:59 -0600184}