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