| #pragma once |
| |
| #include "env.hpp" |
| #include "fan_pwm.hpp" |
| #include "fan_speed.hpp" |
| #include "hwmonio.hpp" |
| |
| #include <phosphor-logging/elog-errors.hpp> |
| #include <phosphor-logging/log.hpp> |
| #include <xyz/openbmc_project/Sensor/Device/error.hpp> |
| |
| #include <filesystem> |
| #include <format> |
| #include <memory> |
| |
| enum class targetType |
| { |
| DEFAULT, |
| RPM, |
| PWM |
| }; |
| |
| static constexpr auto RPM_TARGET = "RPM"; |
| static constexpr auto PWM_TARGET = "PWM"; |
| |
| /** @class Targets |
| * @brief Target type traits. |
| * |
| * @tparam T - The target type. |
| */ |
| template <typename T> |
| struct Targets |
| { |
| static void fail() |
| { |
| static_assert(sizeof(Targets) == -1, "Unsupported Target type"); |
| } |
| }; |
| |
| /**@brief Targets specialization for fan speed. */ |
| template <> |
| struct Targets<hwmon::FanSpeed> |
| { |
| static constexpr InterfaceType type = InterfaceType::FAN_SPEED; |
| }; |
| |
| template <> |
| struct Targets<hwmon::FanPwm> |
| { |
| static constexpr InterfaceType type = InterfaceType::FAN_PWM; |
| }; |
| |
| /** @brief addTarget |
| * |
| * Creates the target type interface |
| * |
| * @tparam T - The target type |
| * |
| * @param[in] sensor - A sensor type and name |
| * @param[in] ioAccess - hwmon sysfs access object |
| * @param[in] devPath - The /sys/devices sysfs path |
| * @param[in] info - The sdbusplus server connection and interfaces |
| * |
| * @return A shared pointer to the target interface object |
| * Will be empty if no interface was created |
| */ |
| template <typename T> |
| std::shared_ptr<T> addTarget(const SensorSet::key_type& sensor, |
| const hwmonio::HwmonIOInterface* ioAccess, |
| const std::string& devPath, ObjectInfo& info) |
| { |
| std::shared_ptr<T> target; |
| namespace fs = std::filesystem; |
| |
| auto& obj = std::get<InterfaceMap>(info); |
| auto& objPath = std::get<std::string>(info); |
| auto type = Targets<T>::type; |
| |
| // Check if target sysfs file exists |
| std::string sysfsFullPath; |
| std::string targetName = sensor.first; |
| std::string targetId = sensor.second; |
| std::string entry = hwmon::entry::target; |
| |
| using namespace std::literals; |
| const std::string pwm = "pwm"s; |
| const std::string empty = ""s; |
| |
| if (InterfaceType::FAN_PWM == type) |
| { |
| targetName = pwm; |
| // If PWM_TARGET is set, use the specified pwm id |
| auto id = env::getEnv("PWM_TARGET", sensor); |
| if (!id.empty()) |
| { |
| targetId = id; |
| } |
| entry = empty; |
| } |
| |
| sysfsFullPath = sysfs::make_sysfs_path(ioAccess->path(), targetName, |
| targetId, entry); |
| if (fs::exists(sysfsFullPath)) |
| { |
| auto useTarget = true; |
| auto tmEnv = env::getEnv("TARGET_MODE"); |
| if (!tmEnv.empty()) |
| { |
| std::string mode{tmEnv}; |
| std::transform(mode.begin(), mode.end(), mode.begin(), toupper); |
| |
| if (mode == RPM_TARGET) |
| { |
| if (type != InterfaceType::FAN_SPEED) |
| { |
| useTarget = false; |
| } |
| } |
| else if (mode == PWM_TARGET) |
| { |
| if (type != InterfaceType::FAN_PWM) |
| { |
| useTarget = false; |
| } |
| } |
| else |
| { |
| using namespace phosphor::logging; |
| log<level::ERR>( |
| "Invalid TARGET_MODE env var found", |
| phosphor::logging::entry("TARGET_MODE=%s", tmEnv.c_str()), |
| phosphor::logging::entry("DEVPATH=%s", devPath.c_str())); |
| } |
| } |
| |
| if (useTarget) |
| { |
| uint32_t targetSpeed = 0; |
| |
| try |
| { |
| targetSpeed = ioAccess->read(targetName, targetId, entry, |
| hwmonio::retries, hwmonio::delay); |
| } |
| catch (const std::system_error& e) |
| { |
| using namespace phosphor::logging; |
| using namespace sdbusplus::xyz::openbmc_project::Sensor:: |
| Device::Error; |
| using metadata = |
| xyz::openbmc_project::Sensor::Device::ReadFailure; |
| |
| report<ReadFailure>( |
| metadata::CALLOUT_ERRNO(e.code().value()), |
| metadata::CALLOUT_DEVICE_PATH(devPath.c_str())); |
| |
| log<level::INFO>(std::format("Failing sysfs file: {} errno: {}", |
| sysfsFullPath, e.code().value()) |
| .c_str()); |
| } |
| |
| static constexpr bool deferSignals = true; |
| auto& bus = *std::get<sdbusplus::bus_t*>(info); |
| |
| // ioAccess->path() is a path like: /sys/class/hwmon/hwmon1 |
| // NOTE: When unit-testing, the target won't have an inject-ible |
| // ioAccess: fan_pwm/fan_speed. |
| target = std::make_shared<T>( |
| std::move(std::make_unique<hwmonio::HwmonIO>(ioAccess->path())), |
| devPath, targetId, bus, objPath.c_str(), deferSignals, |
| targetSpeed); |
| obj[type] = target; |
| } |
| } |
| |
| return target; |
| } |