1 #pragma once 2 3 #include "env.hpp" 4 #include "fan_pwm.hpp" 5 #include "fan_speed.hpp" 6 #include "hwmonio.hpp" 7 8 #include <filesystem> 9 #include <memory> 10 #include <phosphor-logging/elog-errors.hpp> 11 #include <phosphor-logging/log.hpp> 12 #include <xyz/openbmc_project/Sensor/Device/error.hpp> 13 14 enum class targetType 15 { 16 DEFAULT, 17 RPM, 18 PWM 19 }; 20 21 static constexpr auto RPM_TARGET = "RPM"; 22 static constexpr auto PWM_TARGET = "PWM"; 23 24 /** @class Targets 25 * @brief Target type traits. 26 * 27 * @tparam T - The target type. 28 */ 29 template <typename T> 30 struct Targets 31 { 32 static void fail() 33 { 34 static_assert(sizeof(Targets) == -1, "Unsupported Target type"); 35 } 36 }; 37 38 /**@brief Targets specialization for fan speed. */ 39 template <> 40 struct Targets<hwmon::FanSpeed> 41 { 42 static constexpr InterfaceType type = InterfaceType::FAN_SPEED; 43 }; 44 45 template <> 46 struct Targets<hwmon::FanPwm> 47 { 48 static constexpr InterfaceType type = InterfaceType::FAN_PWM; 49 }; 50 51 /** @brief addTarget 52 * 53 * Creates the target type interface 54 * 55 * @tparam T - The target type 56 * 57 * @param[in] sensor - A sensor type and name 58 * @param[in] ioAccess - hwmon sysfs access object 59 * @param[in] devPath - The /sys/devices sysfs path 60 * @param[in] info - The sdbusplus server connection and interfaces 61 * 62 * @return A shared pointer to the target interface object 63 * Will be empty if no interface was created 64 */ 65 template <typename T> 66 std::shared_ptr<T> addTarget(const SensorSet::key_type& sensor, 67 const hwmonio::HwmonIOInterface* ioAccess, 68 const std::string& devPath, ObjectInfo& info) 69 { 70 std::shared_ptr<T> target; 71 namespace fs = std::filesystem; 72 73 auto& obj = std::get<InterfaceMap>(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 = 100 sysfs::make_sysfs_path(ioAccess->path(), targetName, targetId, entry); 101 if (fs::exists(sysfsFullPath)) 102 { 103 auto useTarget = true; 104 auto tmEnv = env::getEnv("TARGET_MODE"); 105 if (!tmEnv.empty()) 106 { 107 std::string mode{tmEnv}; 108 std::transform(mode.begin(), mode.end(), mode.begin(), toupper); 109 110 if (mode == RPM_TARGET) 111 { 112 if (type != InterfaceType::FAN_SPEED) 113 { 114 useTarget = false; 115 } 116 } 117 else if (mode == PWM_TARGET) 118 { 119 if (type != InterfaceType::FAN_PWM) 120 { 121 useTarget = false; 122 } 123 } 124 else 125 { 126 using namespace phosphor::logging; 127 log<level::ERR>( 128 "Invalid TARGET_MODE env var found", 129 phosphor::logging::entry("TARGET_MODE=%s", tmEnv.c_str()), 130 phosphor::logging::entry("DEVPATH=%s", devPath.c_str())); 131 } 132 } 133 134 if (useTarget) 135 { 136 uint32_t targetSpeed = 0; 137 138 try 139 { 140 targetSpeed = ioAccess->read(targetName, targetId, entry, 141 hwmonio::retries, hwmonio::delay); 142 } 143 catch (const std::system_error& e) 144 { 145 using namespace phosphor::logging; 146 using namespace sdbusplus::xyz::openbmc_project::Sensor:: 147 Device::Error; 148 using metadata = 149 xyz::openbmc_project::Sensor::Device::ReadFailure; 150 151 report<ReadFailure>( 152 metadata::CALLOUT_ERRNO(e.code().value()), 153 metadata::CALLOUT_DEVICE_PATH(devPath.c_str())); 154 155 log<level::INFO>( 156 "Logging failing sysfs file", 157 phosphor::logging::entry("FILE=%s", sysfsFullPath.c_str())); 158 } 159 160 static constexpr bool deferSignals = true; 161 auto& bus = *std::get<sdbusplus::bus::bus*>(info); 162 163 // ioAccess->path() is a path like: /sys/class/hwmon/hwmon1 164 // NOTE: When unit-testing, the target won't have an inject-ible 165 // ioAccess: fan_pwm/fan_speed. 166 target = std::make_shared<T>( 167 std::move(std::make_unique<hwmonio::HwmonIO>(ioAccess->path())), 168 devPath, targetId, bus, objPath.c_str(), deferSignals, 169 targetSpeed); 170 obj[type] = target; 171 } 172 } 173 174 return target; 175 } 176