#pragma once #include "env.hpp" #include "fan_pwm.hpp" #include "fan_speed.hpp" #include "hwmonio.hpp" #include #include #include #include #include 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 struct Targets { static void fail() { static_assert(sizeof(Targets) == -1, "Unsupported Target type"); } }; /**@brief Targets specialization for fan speed. */ template <> struct Targets { static constexpr InterfaceType type = InterfaceType::FAN_SPEED; }; template <> struct Targets { 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 std::shared_ptr addTarget(const SensorSet::key_type& sensor, const hwmonio::HwmonIO& ioAccess, const std::string& devPath, ObjectInfo& info) { std::shared_ptr target; namespace fs = std::filesystem; auto& obj = std::get(info); auto& objPath = std::get(info); auto type = Targets::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_SPEED == type) { // If RPM_TARGET is set, use the specified pwm id auto id = env::getEnv("RPM_TARGET", sensor); if (!id.empty()) { targetName = pwm; targetId = id; } entry = empty; } 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( "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( metadata::CALLOUT_ERRNO(e.code().value()), metadata::CALLOUT_DEVICE_PATH(devPath.c_str())); log( "Logging failing sysfs file", phosphor::logging::entry("FILE=%s", sysfsFullPath.c_str())); } static constexpr bool deferSignals = true; auto& bus = *std::get(info); // ioAccess.path() is a path like: /sys/class/hwmon/hwmon1 target = std::make_shared( std::move(std::make_unique(ioAccess.path())), devPath, targetId, bus, objPath.c_str(), deferSignals, targetSpeed); obj[type] = target; } } return target; }