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