blob: 4c2786f0b98a3e01606554c3cb4c662cad924e09 [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 Spinlerb4e65572017-10-17 10:09:18 -05008#include <phosphor-logging/elog-errors.hpp>
9#include <phosphor-logging/log.hpp>
10#include <xyz/openbmc_project/Sensor/Device/error.hpp>
Matthew Barthbf7b7b12017-03-07 15:46:59 -060011
Patrick Williamse8771fd2023-05-10 07:51:06 -050012#include <filesystem>
Patrick Williams64129932024-02-13 21:10:17 -060013#include <format>
Patrick Williamse8771fd2023-05-10 07:51:06 -050014#include <memory>
15
Matt Spinlera7e2c1e2018-02-23 12:18:19 -060016enum class targetType
17{
18 DEFAULT,
19 RPM,
20 PWM
21};
22
23static constexpr auto RPM_TARGET = "RPM";
24static constexpr auto PWM_TARGET = "PWM";
25
Matthew Barthbf7b7b12017-03-07 15:46:59 -060026/** @class Targets
27 * @brief Target type traits.
28 *
29 * @tparam T - The target type.
30 */
31template <typename T>
32struct Targets
33{
34 static void fail()
35 {
36 static_assert(sizeof(Targets) == -1, "Unsupported Target type");
37 }
38};
39
40/**@brief Targets specialization for fan speed. */
41template <>
Matthew Barth048ac872017-03-09 14:36:08 -060042struct Targets<hwmon::FanSpeed>
Matthew Barthbf7b7b12017-03-07 15:46:59 -060043{
44 static constexpr InterfaceType type = InterfaceType::FAN_SPEED;
Matthew Barthbf7b7b12017-03-07 15:46:59 -060045};
46
Patrick Venture9331ab72018-01-29 09:48:47 -080047template <>
48struct Targets<hwmon::FanPwm>
49{
50 static constexpr InterfaceType type = InterfaceType::FAN_PWM;
51};
52
Matthew Barthbf7b7b12017-03-07 15:46:59 -060053/** @brief addTarget
54 *
55 * Creates the target type interface
56 *
57 * @tparam T - The target type
58 *
59 * @param[in] sensor - A sensor type and name
Matt Spinlerb4e65572017-10-17 10:09:18 -050060 * @param[in] ioAccess - hwmon sysfs access object
61 * @param[in] devPath - The /sys/devices sysfs path
Matthew Barthbf7b7b12017-03-07 15:46:59 -060062 * @param[in] info - The sdbusplus server connection and interfaces
Matt Spinler0a8de642017-05-11 10:59:39 -050063 *
64 * @return A shared pointer to the target interface object
65 * Will be empty if no interface was created
Matthew Barthbf7b7b12017-03-07 15:46:59 -060066 */
67template <typename T>
Matt Spinler0a8de642017-05-11 10:59:39 -050068std::shared_ptr<T> addTarget(const SensorSet::key_type& sensor,
Patrick Venture16805a62019-06-21 14:19:33 -070069 const hwmonio::HwmonIOInterface* ioAccess,
Patrick Venture043d3232018-08-31 10:10:53 -070070 const std::string& devPath, ObjectInfo& info)
Matthew Barthbf7b7b12017-03-07 15:46:59 -060071{
Matt Spinler0a8de642017-05-11 10:59:39 -050072 std::shared_ptr<T> target;
Patrick Venture9e997b42019-03-08 13:42:10 -080073 namespace fs = std::filesystem;
Matthew Barthbf7b7b12017-03-07 15:46:59 -060074
Patrick Venture62067232019-06-19 17:39:33 -070075 auto& obj = std::get<InterfaceMap>(info);
Matthew Barthbf7b7b12017-03-07 15:46:59 -060076 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 Williams02e598a2024-08-16 15:21:23 -0400101 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 Venture16805a62019-06-21 14:19:33 -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 Williams64129932024-02-13 21:10:17 -0600157 log<level::INFO>(std::format("Failing sysfs file: {} errno: {}",
Matt Spinler6a391de2020-07-08 13:03:10 -0500158 sysfsFullPath, e.code().value())
159 .c_str());
Matthew Barth28f8e662018-03-26 16:57:36 -0500160 }
161
Patrick Venture685efa12018-10-12 18:00:13 -0700162 static constexpr bool deferSignals = true;
Patrick Williamsad6043f2022-07-22 19:26:56 -0500163 auto& bus = *std::get<sdbusplus::bus_t*>(info);
Patrick Venture685efa12018-10-12 18:00:13 -0700164
Patrick Venture16805a62019-06-21 14:19:33 -0700165 // ioAccess->path() is a path like: /sys/class/hwmon/hwmon1
166 // NOTE: When unit-testing, the target won't have an inject-ible
167 // ioAccess: fan_pwm/fan_speed.
Patrick Venture50552372018-06-07 10:53:56 -0700168 target = std::make_shared<T>(
Patrick Venture16805a62019-06-21 14:19:33 -0700169 std::move(std::make_unique<hwmonio::HwmonIO>(ioAccess->path())),
Patrick Venture043d3232018-08-31 10:10:53 -0700170 devPath, targetId, bus, objPath.c_str(), deferSignals,
171 targetSpeed);
Matthew Barth28f8e662018-03-26 16:57:36 -0500172 obj[type] = target;
173 }
Matthew Barthbf7b7b12017-03-07 15:46:59 -0600174 }
Matt Spinler0a8de642017-05-11 10:59:39 -0500175
176 return target;
Matthew Barthbf7b7b12017-03-07 15:46:59 -0600177}