xref: /openbmc/phosphor-hwmon/targets.hpp (revision c635e860)
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 
11 enum class targetType
12 {
13     DEFAULT,
14     RPM,
15     PWM
16 };
17 
18 static constexpr auto RPM_TARGET = "RPM";
19 static constexpr auto PWM_TARGET = "PWM";
20 
21 /** @class Targets
22  *  @brief Target type traits.
23  *
24  *  @tparam T - The target type.
25  */
26 template <typename T>
27 struct Targets
28 {
29     static void fail()
30     {
31         static_assert(sizeof(Targets) == -1, "Unsupported Target type");
32     }
33 };
34 
35 /**@brief Targets specialization for fan speed. */
36 template <>
37 struct Targets<hwmon::FanSpeed>
38 {
39     static constexpr InterfaceType type = InterfaceType::FAN_SPEED;
40 };
41 
42 template <>
43 struct Targets<hwmon::FanPwm>
44 {
45     static constexpr InterfaceType type = InterfaceType::FAN_PWM;
46 };
47 
48 /** @brief addTarget
49  *
50  *  Creates the target type interface
51  *
52  *  @tparam T - The target type
53  *
54  *  @param[in] sensor - A sensor type and name
55  *  @param[in] ioAccess - hwmon sysfs access object
56  *  @param[in] devPath - The /sys/devices sysfs path
57  *  @param[in] info - The sdbusplus server connection and interfaces
58  *
59  *  @return A shared pointer to the target interface object
60  *          Will be empty if no interface was created
61  */
62 template <typename T>
63 std::shared_ptr<T> addTarget(const SensorSet::key_type& sensor,
64                              const sysfs::hwmonio::HwmonIO& ioAccess,
65                              const std::string& devPath,
66                              ObjectInfo& info)
67 {
68     std::shared_ptr<T> target;
69     namespace fs = std::experimental::filesystem;
70     static constexpr bool deferSignals = true;
71 
72     auto& bus = *std::get<sdbusplus::bus::bus*>(info);
73     auto& obj = std::get<Object>(info);
74     auto& objPath = std::get<std::string>(info);
75     auto type = Targets<T>::type;
76 
77     // Check if target sysfs file exists
78     std::string sysfsFullPath;
79     std::string targetName = sensor.first;
80     std::string targetId = sensor.second;
81     std::string entry = hwmon::entry::target;
82 
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     {
89         targetName = pwm;
90         // If PWM_TARGET is set, use the specified pwm id
91         auto id = env::getEnv("PWM_TARGET", sensor);
92         if (!id.empty())
93         {
94             targetId = id;
95         }
96         entry = empty;
97     }
98 
99     sysfsFullPath = sysfs::make_sysfs_path(ioAccess.path(),
100                                            targetName,
101                                            targetId,
102                                            entry);
103     if (fs::exists(sysfsFullPath))
104     {
105         auto useTarget = true;
106         auto tmEnv = env::getEnv("TARGET_MODE");
107         if (!tmEnv.empty())
108         {
109             std::string mode{tmEnv};
110             std::transform(mode.begin(), mode.end(), mode.begin(), toupper);
111 
112             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;
129                 log<level::ERR>("Invalid TARGET_MODE env var found",
130                         phosphor::logging::entry(
131                                 "TARGET_MODE=%s", tmEnv),
132                         phosphor::logging::entry(
133                                 "DEVPATH=%s", devPath.c_str()));
134             }
135         }
136 
137         if (useTarget)
138         {
139             uint32_t targetSpeed = 0;
140 
141             try
142             {
143                 targetSpeed = ioAccess.read(
144                     targetName,
145                     targetId,
146                     entry,
147                     sysfs::hwmonio::retries,
148                     sysfs::hwmonio::delay);
149             }
150             catch (const std::system_error& e)
151             {
152                 using namespace phosphor::logging;
153                 using namespace sdbusplus::xyz::openbmc_project::
154                     Sensor::Device::Error;
155                 using metadata = xyz::openbmc_project::Sensor::
156                     Device::ReadFailure;
157 
158                 report<ReadFailure>(
159                         metadata::CALLOUT_ERRNO(e.code().value()),
160                         metadata::CALLOUT_DEVICE_PATH(devPath.c_str()));
161 
162                 log<level::INFO>("Logging failing sysfs file",
163                         phosphor::logging::entry(
164                                 "FILE=%s", sysfsFullPath.c_str()));
165             }
166 
167             target = std::make_shared<T>(ioAccess.path(),
168                                          devPath,
169                                          targetId,
170                                          bus,
171                                          objPath.c_str(),
172                                          deferSignals,
173                                          targetSpeed);
174             obj[type] = target;
175         }
176     }
177 
178     return target;
179 }
180