xref: /openbmc/phosphor-hwmon/targets.hpp (revision 9331ab7846750a05b90efd845935bfd3275e694c)
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 "fan_speed.hpp"
8 #include "fan_pwm.hpp"
9 
10 /** @class Targets
11  *  @brief Target type traits.
12  *
13  *  @tparam T - The target type.
14  */
15 template <typename T>
16 struct Targets
17 {
18     static void fail()
19     {
20         static_assert(sizeof(Targets) == -1, "Unsupported Target type");
21     }
22 };
23 
24 /**@brief Targets specialization for fan speed. */
25 template <>
26 struct Targets<hwmon::FanSpeed>
27 {
28     static constexpr InterfaceType type = InterfaceType::FAN_SPEED;
29 };
30 
31 template <>
32 struct Targets<hwmon::FanPwm>
33 {
34     static constexpr InterfaceType type = InterfaceType::FAN_PWM;
35 };
36 
37 /** @brief addTarget
38  *
39  *  Creates the target type interface
40  *
41  *  @tparam T - The target type
42  *
43  *  @param[in] sensor - A sensor type and name
44  *  @param[in] ioAccess - hwmon sysfs access object
45  *  @param[in] devPath - The /sys/devices sysfs path
46  *  @param[in] info - The sdbusplus server connection and interfaces
47  *
48  *  @return A shared pointer to the target interface object
49  *          Will be empty if no interface was created
50  */
51 template <typename T>
52 std::shared_ptr<T> addTarget(const SensorSet::key_type& sensor,
53                              const sysfs::hwmonio::HwmonIO& ioAccess,
54                              const std::string& devPath,
55                              ObjectInfo& info)
56 {
57     std::shared_ptr<T> target;
58     namespace fs = std::experimental::filesystem;
59     static constexpr bool deferSignals = true;
60 
61     auto& bus = *std::get<sdbusplus::bus::bus*>(info);
62     auto& obj = std::get<Object>(info);
63     auto& objPath = std::get<std::string>(info);
64     auto type = Targets<T>::type;
65 
66     // Check if target sysfs file exists
67     std::string sysfsFullPath;
68 
69     using namespace std::literals;
70     const std::string pwm = "pwm"s;
71     const std::string empty = ""s;
72 
73     if (InterfaceType::FAN_PWM == type)
74     {
75         /* We're leveraging that the sensor ID matches for PWM.
76          * TODO(venture): There's a CL from intel that allows
77          * this to be specified via an environment variable.
78          */
79         sysfsFullPath = sysfs::make_sysfs_path(ioAccess.path(),
80                                                pwm,
81                                                sensor.second,
82                                                empty);
83     }
84     else
85     {
86         sysfsFullPath = sysfs::make_sysfs_path(ioAccess.path(),
87                                                sensor.first,
88                                                sensor.second,
89                                                hwmon::entry::target);
90     }
91 
92     if (fs::exists(sysfsFullPath))
93     {
94         uint32_t targetSpeed = 0;
95 
96         try
97         {
98             if (InterfaceType::FAN_PWM == type)
99             {
100                 targetSpeed = ioAccess.read(
101                         pwm,
102                         sensor.second,
103                         empty,
104                         sysfs::hwmonio::retries,
105                         sysfs::hwmonio::delay);
106             }
107             else
108             {
109                 targetSpeed = ioAccess.read(
110                         sensor.first,
111                         sensor.second,
112                         hwmon::entry::target,
113                         sysfs::hwmonio::retries,
114                         sysfs::hwmonio::delay);
115             }
116         }
117         catch (const std::system_error& e)
118         {
119             using namespace phosphor::logging;
120             using namespace sdbusplus::xyz::openbmc_project::
121                 Sensor::Device::Error;
122             using metadata = xyz::openbmc_project::Sensor::
123                 Device::ReadFailure;
124 
125             report<ReadFailure>(
126                     metadata::CALLOUT_ERRNO(e.code().value()),
127                     metadata::CALLOUT_DEVICE_PATH(devPath.c_str()));
128 
129             log<level::INFO>("Logging failing sysfs file",
130                     phosphor::logging::entry(
131                             "FILE=%s", sysfsFullPath.c_str()));
132         }
133 
134         target = std::make_shared<T>(ioAccess.path(),
135                                      devPath,
136                                      sensor.second,
137                                      bus,
138                                      objPath.c_str(),
139                                      deferSignals,
140                                      targetSpeed);
141         auto type = Targets<T>::type;
142         obj[type] = target;
143     }
144 
145     return target;
146 }
147