xref: /openbmc/phosphor-hwmon/targets.hpp (revision 75e56c67a10e9f4c617f9c72a87deb695322e212)
1 #pragma once
2 
3 #include <experimental/filesystem>
4 #include <phosphor-logging/elog-errors.hpp>
5 #include <phosphor-logging/log.hpp>
6 #include <xyz/openbmc_project/Sensor/Device/error.hpp>
7 #include "env.hpp"
8 #include "fan_speed.hpp"
9 #include "fan_pwm.hpp"
10 #include "hwmonio.hpp"
11 
12 enum class targetType
13 {
14     DEFAULT,
15     RPM,
16     PWM
17 };
18 
19 static constexpr auto RPM_TARGET = "RPM";
20 static constexpr auto PWM_TARGET = "PWM";
21 
22 /** @class Targets
23  *  @brief Target type traits.
24  *
25  *  @tparam T - The target type.
26  */
27 template <typename T>
28 struct 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. */
37 template <>
38 struct Targets<hwmon::FanSpeed>
39 {
40     static constexpr InterfaceType type = InterfaceType::FAN_SPEED;
41 };
42 
43 template <>
44 struct Targets<hwmon::FanPwm>
45 {
46     static constexpr InterfaceType type = InterfaceType::FAN_PWM;
47 };
48 
49 /** @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
56  *  @param[in] ioAccess - hwmon sysfs access object
57  *  @param[in] devPath - The /sys/devices sysfs path
58  *  @param[in] info - The sdbusplus server connection and interfaces
59  *
60  *  @return A shared pointer to the target interface object
61  *          Will be empty if no interface was created
62  */
63 template <typename T>
64 std::shared_ptr<T> addTarget(const SensorSet::key_type& sensor,
65                              const hwmonio::HwmonIO& ioAccess,
66                              const std::string& devPath,
67                              ObjectInfo& info)
68 {
69     std::shared_ptr<T> target;
70     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);
76     auto type = Targets<T>::type;
77 
78     // Check if target sysfs file exists
79     std::string sysfsFullPath;
80     std::string targetName = sensor.first;
81     std::string targetId = sensor.second;
82     std::string entry = hwmon::entry::target;
83 
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     {
90         targetName = pwm;
91         // If PWM_TARGET is set, use the specified pwm id
92         auto id = env::getEnv("PWM_TARGET", sensor);
93         if (!id.empty())
94         {
95             targetId = id;
96         }
97         entry = empty;
98     }
99 
100     sysfsFullPath = sysfs::make_sysfs_path(ioAccess.path(),
101                                            targetName,
102                                            targetId,
103                                            entry);
104     if (fs::exists(sysfsFullPath))
105     {
106         auto useTarget = true;
107         auto tmEnv = env::getEnv("TARGET_MODE");
108         if (!tmEnv.empty())
109         {
110             std::string mode{tmEnv};
111             std::transform(mode.begin(), mode.end(), mode.begin(), toupper);
112 
113             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             }
136         }
137 
138         if (useTarget)
139         {
140             uint32_t targetSpeed = 0;
141 
142             try
143             {
144                 targetSpeed = ioAccess.read(
145                     targetName,
146                     targetId,
147                     entry,
148                     hwmonio::retries,
149                     hwmonio::delay);
150             }
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         }
177     }
178 
179     return target;
180 }
181