blob: 515bf2eaed7994d97a778f1dda8ddb3b4c75ed97 [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
Matt Spinler5e034af2020-06-24 15:21:53 -05008#include <fmt/format.h>
9
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
Patrick Williamse8771fd2023-05-10 07:51:06 -050014#include <filesystem>
15#include <memory>
16
Matt Spinlera7e2c1e2018-02-23 12:18:19 -060017enum class targetType
18{
19 DEFAULT,
20 RPM,
21 PWM
22};
23
24static constexpr auto RPM_TARGET = "RPM";
25static constexpr auto PWM_TARGET = "PWM";
26
Matthew Barthbf7b7b12017-03-07 15:46:59 -060027/** @class Targets
28 * @brief Target type traits.
29 *
30 * @tparam T - The target type.
31 */
32template <typename T>
33struct Targets
34{
35 static void fail()
36 {
37 static_assert(sizeof(Targets) == -1, "Unsupported Target type");
38 }
39};
40
41/**@brief Targets specialization for fan speed. */
42template <>
Matthew Barth048ac872017-03-09 14:36:08 -060043struct Targets<hwmon::FanSpeed>
Matthew Barthbf7b7b12017-03-07 15:46:59 -060044{
45 static constexpr InterfaceType type = InterfaceType::FAN_SPEED;
Matthew Barthbf7b7b12017-03-07 15:46:59 -060046};
47
Patrick Venture9331ab72018-01-29 09:48:47 -080048template <>
49struct Targets<hwmon::FanPwm>
50{
51 static constexpr InterfaceType type = InterfaceType::FAN_PWM;
52};
53
Matthew Barthbf7b7b12017-03-07 15:46:59 -060054/** @brief addTarget
55 *
56 * Creates the target type interface
57 *
58 * @tparam T - The target type
59 *
60 * @param[in] sensor - A sensor type and name
Matt Spinlerb4e65572017-10-17 10:09:18 -050061 * @param[in] ioAccess - hwmon sysfs access object
62 * @param[in] devPath - The /sys/devices sysfs path
Matthew Barthbf7b7b12017-03-07 15:46:59 -060063 * @param[in] info - The sdbusplus server connection and interfaces
Matt Spinler0a8de642017-05-11 10:59:39 -050064 *
65 * @return A shared pointer to the target interface object
66 * Will be empty if no interface was created
Matthew Barthbf7b7b12017-03-07 15:46:59 -060067 */
68template <typename T>
Matt Spinler0a8de642017-05-11 10:59:39 -050069std::shared_ptr<T> addTarget(const SensorSet::key_type& sensor,
Patrick Venture16805a62019-06-21 14:19:33 -070070 const hwmonio::HwmonIOInterface* ioAccess,
Patrick Venture043d3232018-08-31 10:10:53 -070071 const std::string& devPath, ObjectInfo& info)
Matthew Barthbf7b7b12017-03-07 15:46:59 -060072{
Matt Spinler0a8de642017-05-11 10:59:39 -050073 std::shared_ptr<T> target;
Patrick Venture9e997b42019-03-08 13:42:10 -080074 namespace fs = std::filesystem;
Matthew Barthbf7b7b12017-03-07 15:46:59 -060075
Patrick Venture62067232019-06-19 17:39:33 -070076 auto& obj = std::get<InterfaceMap>(info);
Matthew Barthbf7b7b12017-03-07 15:46:59 -060077 auto& objPath = std::get<std::string>(info);
Patrick Venture9331ab72018-01-29 09:48:47 -080078 auto type = Targets<T>::type;
Matthew Barthbf7b7b12017-03-07 15:46:59 -060079
80 // Check if target sysfs file exists
Patrick Venture9331ab72018-01-29 09:48:47 -080081 std::string sysfsFullPath;
Lei YUa4bba962018-01-31 13:51:05 +080082 std::string targetName = sensor.first;
83 std::string targetId = sensor.second;
84 std::string entry = hwmon::entry::target;
Patrick Venture9331ab72018-01-29 09:48:47 -080085
86 using namespace std::literals;
87 const std::string pwm = "pwm"s;
88 const std::string empty = ""s;
89
90 if (InterfaceType::FAN_PWM == type)
91 {
Lei YUa4bba962018-01-31 13:51:05 +080092 targetName = pwm;
93 // If PWM_TARGET is set, use the specified pwm id
Patrick Venture7a5285d2018-04-17 19:15:05 -070094 auto id = env::getEnv("PWM_TARGET", sensor);
Lei YUa4bba962018-01-31 13:51:05 +080095 if (!id.empty())
96 {
97 targetId = id;
98 }
99 entry = empty;
Patrick Venture9331ab72018-01-29 09:48:47 -0800100 }
101
Patrick Williamse8771fd2023-05-10 07:51:06 -0500102 sysfsFullPath = sysfs::make_sysfs_path(ioAccess->path(), targetName,
103 targetId, 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;
Patrick Venture043d3232018-08-31 10:10:53 -0700130 log<level::ERR>(
131 "Invalid TARGET_MODE env var found",
132 phosphor::logging::entry("TARGET_MODE=%s", tmEnv.c_str()),
133 phosphor::logging::entry("DEVPATH=%s", devPath.c_str()));
Matthew Barth28f8e662018-03-26 16:57:36 -0500134 }
Matt Spinlerb4e65572017-10-17 10:09:18 -0500135 }
136
Matthew Barth28f8e662018-03-26 16:57:36 -0500137 if (useTarget)
138 {
139 uint32_t targetSpeed = 0;
140
141 try
142 {
Patrick Venture16805a62019-06-21 14:19:33 -0700143 targetSpeed = ioAccess->read(targetName, targetId, entry,
144 hwmonio::retries, hwmonio::delay);
Matthew Barth28f8e662018-03-26 16:57:36 -0500145 }
146 catch (const std::system_error& e)
147 {
148 using namespace phosphor::logging;
Patrick Venture043d3232018-08-31 10:10:53 -0700149 using namespace sdbusplus::xyz::openbmc_project::Sensor::
150 Device::Error;
151 using metadata =
152 xyz::openbmc_project::Sensor::Device::ReadFailure;
Matthew Barth28f8e662018-03-26 16:57:36 -0500153
154 report<ReadFailure>(
Patrick Venture043d3232018-08-31 10:10:53 -0700155 metadata::CALLOUT_ERRNO(e.code().value()),
156 metadata::CALLOUT_DEVICE_PATH(devPath.c_str()));
Matthew Barth28f8e662018-03-26 16:57:36 -0500157
Matt Spinler6a391de2020-07-08 13:03:10 -0500158 log<level::INFO>(fmt::format("Failing sysfs file: {} errno: {}",
159 sysfsFullPath, e.code().value())
160 .c_str());
Matthew Barth28f8e662018-03-26 16:57:36 -0500161 }
162
Patrick Venture685efa12018-10-12 18:00:13 -0700163 static constexpr bool deferSignals = true;
Patrick Williamsad6043f2022-07-22 19:26:56 -0500164 auto& bus = *std::get<sdbusplus::bus_t*>(info);
Patrick Venture685efa12018-10-12 18:00:13 -0700165
Patrick Venture16805a62019-06-21 14:19:33 -0700166 // ioAccess->path() is a path like: /sys/class/hwmon/hwmon1
167 // NOTE: When unit-testing, the target won't have an inject-ible
168 // ioAccess: fan_pwm/fan_speed.
Patrick Venture50552372018-06-07 10:53:56 -0700169 target = std::make_shared<T>(
Patrick Venture16805a62019-06-21 14:19:33 -0700170 std::move(std::make_unique<hwmonio::HwmonIO>(ioAccess->path())),
Patrick Venture043d3232018-08-31 10:10:53 -0700171 devPath, targetId, bus, objPath.c_str(), deferSignals,
172 targetSpeed);
Matthew Barth28f8e662018-03-26 16:57:36 -0500173 obj[type] = target;
174 }
Matthew Barthbf7b7b12017-03-07 15:46:59 -0600175 }
Matt Spinler0a8de642017-05-11 10:59:39 -0500176
177 return target;
Matthew Barthbf7b7b12017-03-07 15:46:59 -0600178}