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 "fan_speed.hpp" 8 #include "fan_pwm.hpp" 9 10 /** @class Targets 11 * @brief Target type traits. 12 * 13 * @tparam T - The target type. 14 */ 15 template <typename T> 16 struct Targets 17 { 18 static void fail() 19 { 20 static_assert(sizeof(Targets) == -1, "Unsupported Target type"); 21 } 22 }; 23 24 /**@brief Targets specialization for fan speed. */ 25 template <> 26 struct Targets<hwmon::FanSpeed> 27 { 28 static constexpr InterfaceType type = InterfaceType::FAN_SPEED; 29 }; 30 31 template <> 32 struct Targets<hwmon::FanPwm> 33 { 34 static constexpr InterfaceType type = InterfaceType::FAN_PWM; 35 }; 36 37 /** @brief addTarget 38 * 39 * Creates the target type interface 40 * 41 * @tparam T - The target type 42 * 43 * @param[in] sensor - A sensor type and name 44 * @param[in] ioAccess - hwmon sysfs access object 45 * @param[in] devPath - The /sys/devices sysfs path 46 * @param[in] info - The sdbusplus server connection and interfaces 47 * 48 * @return A shared pointer to the target interface object 49 * Will be empty if no interface was created 50 */ 51 template <typename T> 52 std::shared_ptr<T> addTarget(const SensorSet::key_type& sensor, 53 const sysfs::hwmonio::HwmonIO& ioAccess, 54 const std::string& devPath, 55 ObjectInfo& info) 56 { 57 std::shared_ptr<T> target; 58 namespace fs = std::experimental::filesystem; 59 static constexpr bool deferSignals = true; 60 61 auto& bus = *std::get<sdbusplus::bus::bus*>(info); 62 auto& obj = std::get<Object>(info); 63 auto& objPath = std::get<std::string>(info); 64 auto type = Targets<T>::type; 65 66 // Check if target sysfs file exists 67 std::string sysfsFullPath; 68 69 using namespace std::literals; 70 const std::string pwm = "pwm"s; 71 const std::string empty = ""s; 72 73 if (InterfaceType::FAN_PWM == type) 74 { 75 /* We're leveraging that the sensor ID matches for PWM. 76 * TODO(venture): There's a CL from intel that allows 77 * this to be specified via an environment variable. 78 */ 79 sysfsFullPath = sysfs::make_sysfs_path(ioAccess.path(), 80 pwm, 81 sensor.second, 82 empty); 83 } 84 else 85 { 86 sysfsFullPath = sysfs::make_sysfs_path(ioAccess.path(), 87 sensor.first, 88 sensor.second, 89 hwmon::entry::target); 90 } 91 92 if (fs::exists(sysfsFullPath)) 93 { 94 uint32_t targetSpeed = 0; 95 96 try 97 { 98 if (InterfaceType::FAN_PWM == type) 99 { 100 targetSpeed = ioAccess.read( 101 pwm, 102 sensor.second, 103 empty, 104 sysfs::hwmonio::retries, 105 sysfs::hwmonio::delay); 106 } 107 else 108 { 109 targetSpeed = ioAccess.read( 110 sensor.first, 111 sensor.second, 112 hwmon::entry::target, 113 sysfs::hwmonio::retries, 114 sysfs::hwmonio::delay); 115 } 116 } 117 catch (const std::system_error& e) 118 { 119 using namespace phosphor::logging; 120 using namespace sdbusplus::xyz::openbmc_project:: 121 Sensor::Device::Error; 122 using metadata = xyz::openbmc_project::Sensor:: 123 Device::ReadFailure; 124 125 report<ReadFailure>( 126 metadata::CALLOUT_ERRNO(e.code().value()), 127 metadata::CALLOUT_DEVICE_PATH(devPath.c_str())); 128 129 log<level::INFO>("Logging failing sysfs file", 130 phosphor::logging::entry( 131 "FILE=%s", sysfsFullPath.c_str())); 132 } 133 134 target = std::make_shared<T>(ioAccess.path(), 135 devPath, 136 sensor.second, 137 bus, 138 objPath.c_str(), 139 deferSignals, 140 targetSpeed); 141 auto type = Targets<T>::type; 142 obj[type] = target; 143 } 144 145 return target; 146 } 147