xref: /openbmc/phosphor-hwmon/targets.hpp (revision 02e598ab445833e0ce615f88ac0aed7288a100e0)
1bf7b7b1dSMatthew Barth #pragma once
2bf7b7b1dSMatthew Barth 
3043d3230SPatrick Venture #include "env.hpp"
4043d3230SPatrick Venture #include "fan_pwm.hpp"
5043d3230SPatrick Venture #include "fan_speed.hpp"
6043d3230SPatrick Venture #include "hwmonio.hpp"
7043d3230SPatrick Venture 
8b4e6557fSMatt Spinler #include <phosphor-logging/elog-errors.hpp>
9b4e6557fSMatt Spinler #include <phosphor-logging/log.hpp>
10b4e6557fSMatt Spinler #include <xyz/openbmc_project/Sensor/Device/error.hpp>
11bf7b7b1dSMatthew Barth 
12e8771fd4SPatrick Williams #include <filesystem>
1364129937SPatrick Williams #include <format>
14e8771fd4SPatrick Williams #include <memory>
15e8771fd4SPatrick Williams 
16a7e2c1e5SMatt Spinler enum class targetType
17a7e2c1e5SMatt Spinler {
18a7e2c1e5SMatt Spinler     DEFAULT,
19a7e2c1e5SMatt Spinler     RPM,
20a7e2c1e5SMatt Spinler     PWM
21a7e2c1e5SMatt Spinler };
22a7e2c1e5SMatt Spinler 
23a7e2c1e5SMatt Spinler static constexpr auto RPM_TARGET = "RPM";
24a7e2c1e5SMatt Spinler static constexpr auto PWM_TARGET = "PWM";
25a7e2c1e5SMatt Spinler 
26bf7b7b1dSMatthew Barth /** @class Targets
27bf7b7b1dSMatthew Barth  *  @brief Target type traits.
28bf7b7b1dSMatthew Barth  *
29bf7b7b1dSMatthew Barth  *  @tparam T - The target type.
30bf7b7b1dSMatthew Barth  */
31bf7b7b1dSMatthew Barth template <typename T>
32bf7b7b1dSMatthew Barth struct Targets
33bf7b7b1dSMatthew Barth {
failTargets34bf7b7b1dSMatthew Barth     static void fail()
35bf7b7b1dSMatthew Barth     {
36bf7b7b1dSMatthew Barth         static_assert(sizeof(Targets) == -1, "Unsupported Target type");
37bf7b7b1dSMatthew Barth     }
38bf7b7b1dSMatthew Barth };
39bf7b7b1dSMatthew Barth 
40bf7b7b1dSMatthew Barth /**@brief Targets specialization for fan speed. */
41bf7b7b1dSMatthew Barth template <>
42048ac87fSMatthew Barth struct Targets<hwmon::FanSpeed>
43bf7b7b1dSMatthew Barth {
44bf7b7b1dSMatthew Barth     static constexpr InterfaceType type = InterfaceType::FAN_SPEED;
45bf7b7b1dSMatthew Barth };
46bf7b7b1dSMatthew Barth 
479331ab78SPatrick Venture template <>
489331ab78SPatrick Venture struct Targets<hwmon::FanPwm>
499331ab78SPatrick Venture {
509331ab78SPatrick Venture     static constexpr InterfaceType type = InterfaceType::FAN_PWM;
519331ab78SPatrick Venture };
529331ab78SPatrick Venture 
53bf7b7b1dSMatthew Barth /** @brief addTarget
54bf7b7b1dSMatthew Barth  *
55bf7b7b1dSMatthew Barth  *  Creates the target type interface
56bf7b7b1dSMatthew Barth  *
57bf7b7b1dSMatthew Barth  *  @tparam T - The target type
58bf7b7b1dSMatthew Barth  *
59bf7b7b1dSMatthew Barth  *  @param[in] sensor - A sensor type and name
60b4e6557fSMatt Spinler  *  @param[in] ioAccess - hwmon sysfs access object
61b4e6557fSMatt Spinler  *  @param[in] devPath - The /sys/devices sysfs path
62bf7b7b1dSMatthew Barth  *  @param[in] info - The sdbusplus server connection and interfaces
630a8de645SMatt Spinler  *
640a8de645SMatt Spinler  *  @return A shared pointer to the target interface object
650a8de645SMatt Spinler  *          Will be empty if no interface was created
66bf7b7b1dSMatthew Barth  */
67bf7b7b1dSMatthew Barth template <typename T>
addTarget(const SensorSet::key_type & sensor,const hwmonio::HwmonIOInterface * ioAccess,const std::string & devPath,ObjectInfo & info)680a8de645SMatt Spinler std::shared_ptr<T> addTarget(const SensorSet::key_type& sensor,
6916805a6aSPatrick Venture                              const hwmonio::HwmonIOInterface* ioAccess,
70043d3230SPatrick Venture                              const std::string& devPath, ObjectInfo& info)
71bf7b7b1dSMatthew Barth {
720a8de645SMatt Spinler     std::shared_ptr<T> target;
739e997b4dSPatrick Venture     namespace fs = std::filesystem;
74bf7b7b1dSMatthew Barth 
756206723dSPatrick Venture     auto& obj = std::get<InterfaceMap>(info);
76bf7b7b1dSMatthew Barth     auto& objPath = std::get<std::string>(info);
779331ab78SPatrick Venture     auto type = Targets<T>::type;
78bf7b7b1dSMatthew Barth 
79bf7b7b1dSMatthew Barth     // Check if target sysfs file exists
809331ab78SPatrick Venture     std::string sysfsFullPath;
81a4bba96eSLei YU     std::string targetName = sensor.first;
82a4bba96eSLei YU     std::string targetId = sensor.second;
83a4bba96eSLei YU     std::string entry = hwmon::entry::target;
849331ab78SPatrick Venture 
859331ab78SPatrick Venture     using namespace std::literals;
869331ab78SPatrick Venture     const std::string pwm = "pwm"s;
879331ab78SPatrick Venture     const std::string empty = ""s;
889331ab78SPatrick Venture 
899331ab78SPatrick Venture     if (InterfaceType::FAN_PWM == type)
909331ab78SPatrick Venture     {
91a4bba96eSLei YU         targetName = pwm;
92a4bba96eSLei YU         // If PWM_TARGET is set, use the specified pwm id
937a5285deSPatrick Venture         auto id = env::getEnv("PWM_TARGET", sensor);
94a4bba96eSLei YU         if (!id.empty())
959331ab78SPatrick Venture         {
96a4bba96eSLei YU             targetId = id;
97a4bba96eSLei YU         }
98a4bba96eSLei YU         entry = empty;
999331ab78SPatrick Venture     }
1009331ab78SPatrick Venture 
101*02e598abSPatrick Williams     sysfsFullPath =
102*02e598abSPatrick Williams         sysfs::make_sysfs_path(ioAccess->path(), targetName, targetId, entry);
103048ac87fSMatthew Barth     if (fs::exists(sysfsFullPath))
104bf7b7b1dSMatthew Barth     {
10528f8e66dSMatthew Barth         auto useTarget = true;
106a24c8808SPatrick Venture         auto tmEnv = env::getEnv("TARGET_MODE");
107a24c8808SPatrick Venture         if (!tmEnv.empty())
10828f8e66dSMatthew Barth         {
10928f8e66dSMatthew Barth             std::string mode{tmEnv};
11028f8e66dSMatthew Barth             std::transform(mode.begin(), mode.end(), mode.begin(), toupper);
11128f8e66dSMatthew Barth 
11228f8e66dSMatthew Barth             if (mode == RPM_TARGET)
11328f8e66dSMatthew Barth             {
11428f8e66dSMatthew Barth                 if (type != InterfaceType::FAN_SPEED)
11528f8e66dSMatthew Barth                 {
11628f8e66dSMatthew Barth                     useTarget = false;
11728f8e66dSMatthew Barth                 }
11828f8e66dSMatthew Barth             }
11928f8e66dSMatthew Barth             else if (mode == PWM_TARGET)
12028f8e66dSMatthew Barth             {
12128f8e66dSMatthew Barth                 if (type != InterfaceType::FAN_PWM)
12228f8e66dSMatthew Barth                 {
12328f8e66dSMatthew Barth                     useTarget = false;
12428f8e66dSMatthew Barth                 }
12528f8e66dSMatthew Barth             }
12628f8e66dSMatthew Barth             else
12728f8e66dSMatthew Barth             {
12828f8e66dSMatthew Barth                 using namespace phosphor::logging;
129043d3230SPatrick Venture                 log<level::ERR>(
130043d3230SPatrick Venture                     "Invalid TARGET_MODE env var found",
131043d3230SPatrick Venture                     phosphor::logging::entry("TARGET_MODE=%s", tmEnv.c_str()),
132043d3230SPatrick Venture                     phosphor::logging::entry("DEVPATH=%s", devPath.c_str()));
13328f8e66dSMatthew Barth             }
13428f8e66dSMatthew Barth         }
13528f8e66dSMatthew Barth 
13628f8e66dSMatthew Barth         if (useTarget)
13728f8e66dSMatthew Barth         {
138b4e6557fSMatt Spinler             uint32_t targetSpeed = 0;
139b4e6557fSMatt Spinler 
140b4e6557fSMatt Spinler             try
141b4e6557fSMatt Spinler             {
14216805a6aSPatrick Venture                 targetSpeed = ioAccess->read(targetName, targetId, entry,
143043d3230SPatrick Venture                                              hwmonio::retries, hwmonio::delay);
1449331ab78SPatrick Venture             }
145b4e6557fSMatt Spinler             catch (const std::system_error& e)
146b4e6557fSMatt Spinler             {
147b4e6557fSMatt Spinler                 using namespace phosphor::logging;
148043d3230SPatrick Venture                 using namespace sdbusplus::xyz::openbmc_project::Sensor::
149043d3230SPatrick Venture                     Device::Error;
150043d3230SPatrick Venture                 using metadata =
151043d3230SPatrick Venture                     xyz::openbmc_project::Sensor::Device::ReadFailure;
152b4e6557fSMatt Spinler 
153b4e6557fSMatt Spinler                 report<ReadFailure>(
154b4e6557fSMatt Spinler                     metadata::CALLOUT_ERRNO(e.code().value()),
155b4e6557fSMatt Spinler                     metadata::CALLOUT_DEVICE_PATH(devPath.c_str()));
156b4e6557fSMatt Spinler 
15764129937SPatrick Williams                 log<level::INFO>(std::format("Failing sysfs file: {} errno: {}",
1586a391de4SMatt Spinler                                              sysfsFullPath, e.code().value())
1595e034afcSMatt Spinler                                      .c_str());
160b4e6557fSMatt Spinler             }
161b4e6557fSMatt Spinler 
162685efa16SPatrick Venture             static constexpr bool deferSignals = true;
163ad6043f6SPatrick Williams             auto& bus = *std::get<sdbusplus::bus_t*>(info);
164685efa16SPatrick Venture 
16516805a6aSPatrick Venture             // ioAccess->path() is a path like: /sys/class/hwmon/hwmon1
16616805a6aSPatrick Venture             // NOTE: When unit-testing, the target won't have an inject-ible
16716805a6aSPatrick Venture             // ioAccess: fan_pwm/fan_speed.
16850552377SPatrick Venture             target = std::make_shared<T>(
16916805a6aSPatrick Venture                 std::move(std::make_unique<hwmonio::HwmonIO>(ioAccess->path())),
170043d3230SPatrick Venture                 devPath, targetId, bus, objPath.c_str(), deferSignals,
171b4e6557fSMatt Spinler                 targetSpeed);
1720a8de645SMatt Spinler             obj[type] = target;
173bf7b7b1dSMatthew Barth         }
17428f8e66dSMatthew Barth     }
1750a8de645SMatt Spinler 
1760a8de645SMatt Spinler     return target;
177bf7b7b1dSMatthew Barth }
178