blob: 9e63351ce4f616801d01398ada2439887b666b94 [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;
Matthew Barthbf7b7b12017-03-07 15:46:59 -060072
Matthew Barthbf7b7b12017-03-07 15:46:59 -060073 auto& obj = std::get<Object>(info);
74 auto& objPath = std::get<std::string>(info);
Patrick Venture9331ab72018-01-29 09:48:47 -080075 auto type = Targets<T>::type;
Matthew Barthbf7b7b12017-03-07 15:46:59 -060076
77 // Check if target sysfs file exists
Patrick Venture9331ab72018-01-29 09:48:47 -080078 std::string sysfsFullPath;
Lei YUa4bba962018-01-31 13:51:05 +080079 std::string targetName = sensor.first;
80 std::string targetId = sensor.second;
81 std::string entry = hwmon::entry::target;
Patrick Venture9331ab72018-01-29 09:48:47 -080082
83 using namespace std::literals;
84 const std::string pwm = "pwm"s;
85 const std::string empty = ""s;
86
87 if (InterfaceType::FAN_PWM == type)
88 {
Lei YUa4bba962018-01-31 13:51:05 +080089 targetName = pwm;
90 // If PWM_TARGET is set, use the specified pwm id
Patrick Venture7a5285d2018-04-17 19:15:05 -070091 auto id = env::getEnv("PWM_TARGET", sensor);
Lei YUa4bba962018-01-31 13:51:05 +080092 if (!id.empty())
93 {
94 targetId = id;
95 }
96 entry = empty;
Patrick Venture9331ab72018-01-29 09:48:47 -080097 }
98
Patrick Venture043d3232018-08-31 10:10:53 -070099 sysfsFullPath =
100 sysfs::make_sysfs_path(ioAccess.path(), targetName, targetId, entry);
Matthew Barth048ac872017-03-09 14:36:08 -0600101 if (fs::exists(sysfsFullPath))
Matthew Barthbf7b7b12017-03-07 15:46:59 -0600102 {
Matthew Barth28f8e662018-03-26 16:57:36 -0500103 auto useTarget = true;
Patrick Venturea24c8802018-04-17 19:38:06 -0700104 auto tmEnv = env::getEnv("TARGET_MODE");
105 if (!tmEnv.empty())
Matt Spinlerb4e65572017-10-17 10:09:18 -0500106 {
Matthew Barth28f8e662018-03-26 16:57:36 -0500107 std::string mode{tmEnv};
108 std::transform(mode.begin(), mode.end(), mode.begin(), toupper);
Matt Spinlerb4e65572017-10-17 10:09:18 -0500109
Matthew Barth28f8e662018-03-26 16:57:36 -0500110 if (mode == RPM_TARGET)
111 {
112 if (type != InterfaceType::FAN_SPEED)
113 {
114 useTarget = false;
115 }
116 }
117 else if (mode == PWM_TARGET)
118 {
119 if (type != InterfaceType::FAN_PWM)
120 {
121 useTarget = false;
122 }
123 }
124 else
125 {
126 using namespace phosphor::logging;
Patrick Venture043d3232018-08-31 10:10:53 -0700127 log<level::ERR>(
128 "Invalid TARGET_MODE env var found",
129 phosphor::logging::entry("TARGET_MODE=%s", tmEnv.c_str()),
130 phosphor::logging::entry("DEVPATH=%s", devPath.c_str()));
Matthew Barth28f8e662018-03-26 16:57:36 -0500131 }
Matt Spinlerb4e65572017-10-17 10:09:18 -0500132 }
133
Matthew Barth28f8e662018-03-26 16:57:36 -0500134 if (useTarget)
135 {
136 uint32_t targetSpeed = 0;
137
138 try
139 {
Patrick Venture043d3232018-08-31 10:10:53 -0700140 targetSpeed = ioAccess.read(targetName, targetId, entry,
141 hwmonio::retries, hwmonio::delay);
Matthew Barth28f8e662018-03-26 16:57:36 -0500142 }
143 catch (const std::system_error& e)
144 {
145 using namespace phosphor::logging;
Patrick Venture043d3232018-08-31 10:10:53 -0700146 using namespace sdbusplus::xyz::openbmc_project::Sensor::
147 Device::Error;
148 using metadata =
149 xyz::openbmc_project::Sensor::Device::ReadFailure;
Matthew Barth28f8e662018-03-26 16:57:36 -0500150
151 report<ReadFailure>(
Patrick Venture043d3232018-08-31 10:10:53 -0700152 metadata::CALLOUT_ERRNO(e.code().value()),
153 metadata::CALLOUT_DEVICE_PATH(devPath.c_str()));
Matthew Barth28f8e662018-03-26 16:57:36 -0500154
Patrick Venture043d3232018-08-31 10:10:53 -0700155 log<level::INFO>(
156 "Logging failing sysfs file",
157 phosphor::logging::entry("FILE=%s", sysfsFullPath.c_str()));
Matthew Barth28f8e662018-03-26 16:57:36 -0500158 }
159
Patrick Venture685efa12018-10-12 18:00:13 -0700160 static constexpr bool deferSignals = true;
161 auto& bus = *std::get<sdbusplus::bus::bus*>(info);
162
Patrick Venture50552372018-06-07 10:53:56 -0700163 // ioAccess.path() is a path like: /sys/class/hwmon/hwmon1
164 target = std::make_shared<T>(
Patrick Venture043d3232018-08-31 10:10:53 -0700165 std::move(std::make_unique<hwmonio::HwmonIO>(ioAccess.path())),
166 devPath, targetId, bus, objPath.c_str(), deferSignals,
167 targetSpeed);
Matthew Barth28f8e662018-03-26 16:57:36 -0500168 obj[type] = target;
169 }
Matthew Barthbf7b7b12017-03-07 15:46:59 -0600170 }
Matt Spinler0a8de642017-05-11 10:59:39 -0500171
172 return target;
Matthew Barthbf7b7b12017-03-07 15:46:59 -0600173}