| #include "tlbmc/sensors/fan_controller.h" |
| |
| #include <sys/types.h> |
| |
| #include <algorithm> |
| #include <array> |
| #include <cstdint> |
| #include <memory> |
| #include <string> |
| #include <string_view> |
| #include <unordered_map> |
| #include <utility> |
| |
| #include "absl/log/log.h" |
| #include "absl/status/status.h" |
| #include "absl/status/statusor.h" |
| #include "absl/strings/match.h" |
| #include "absl/strings/numbers.h" |
| #include "absl/strings/str_cat.h" |
| #include "absl/strings/substitute.h" |
| #include "g3/macros.h" |
| #include "tlbmc/central_config/config.h" |
| #include "fan_controller_config.pb.h" |
| #include "tlbmc/hal/sysfs/i2c.h" |
| #include "tlbmc/sensors/i2c_hwmon_based_sensor.h" |
| #include "re2/re2.h" |
| |
| namespace milotic_tlbmc { |
| |
| template <class TypeName> |
| struct TypeComparator { |
| // Compared by the first element which is the type name. |
| bool operator()(const std::pair<FanControllerType, TypeName>& lhs, |
| const std::pair<FanControllerType, TypeName>& rhs) const { |
| return lhs.first < rhs.first; |
| } |
| }; |
| |
| constexpr std::array<std::pair<FanControllerType, std::string_view>, 1> |
| kSupportedFanControllerTypes = { |
| // go/keep-sorted start |
| {{FAN_CONTROLLER_TYPE_MAX31790, "max31790"}} |
| // go/keep-sorted end |
| }; |
| |
| FanController::FanController( |
| Token token, const FanControllerConfig& config, |
| const std::unordered_map<uint32_t, Tachometers>& tachs, |
| const std::unordered_map<uint32_t, Pwm>& pwms) |
| : config_(config), index_to_tachs_(tachs), index_to_pwms_(pwms) {} |
| |
| absl::StatusOr<std::string_view> FanController::GetDriverName( |
| FanControllerType type) { |
| const auto* it = std::lower_bound( |
| kSupportedFanControllerTypes.begin(), kSupportedFanControllerTypes.end(), |
| std::pair<FanControllerType, std::string_view>{type, ""}, |
| TypeComparator<std::string_view>()); |
| if (it == kSupportedFanControllerTypes.end() || it->first != type) { |
| return absl::InvalidArgumentError( |
| absl::Substitute("Unsupported fan controller type: $0", type)); |
| } |
| return it->second; |
| } |
| |
| absl::StatusOr<std::shared_ptr<FanController>> FanController::Create( |
| const FanControllerConfig& config, const I2cSysfs& i2c_sysfs) { |
| DLOG(INFO) << "Creating FanController for device: " << absl::StrCat(config); |
| const I2cCommonConfig& i2c_common_config = config.i2c_common_config(); |
| ECCLESIA_ASSIGN_OR_RETURN(std::string_view driver_name, |
| GetDriverName(config.type())); |
| |
| // E.g., /sys/bus/i2c/devices/i2c-19/19-002c/hwmon/hwmon9/ |
| absl::StatusOr<boost::filesystem::path> hwmon_path = |
| I2cHwmonBasedSensor::CreateDeviceAndReturnsHwmonPath( |
| i2c_common_config, driver_name, i2c_sysfs); |
| if (!hwmon_path.ok()) { |
| if (!GetTlbmcConfig().allow_sensor_creation_failure) { |
| return hwmon_path.status(); |
| } |
| |
| LOG(ERROR) << "Failed to create FanController (NONFATAL): " |
| << hwmon_path.status(); |
| return std::make_shared<FanController>( |
| Token(), config, std::unordered_map<uint32_t, Tachometers>(), |
| std::unordered_map<uint32_t, Pwm>()); |
| } |
| |
| std::unordered_map<uint32_t, Tachometers> tachs; |
| std::unordered_map<uint32_t, Pwm> pwms; |
| |
| for (const auto& entry : boost::filesystem::directory_iterator(*hwmon_path)) { |
| std::string entry_path_str = entry.path().filename().string(); |
| std::string_view entry_path = entry_path_str; |
| constexpr std::string_view kFanTachPrefix = "fan"; |
| constexpr std::string_view kFanTachSuffix = "_input"; |
| if (absl::StartsWith(entry_path, kFanTachPrefix) && |
| absl::EndsWith(entry_path, kFanTachSuffix)) { |
| std::string_view index = entry_path.substr( |
| kFanTachPrefix.size(), |
| entry_path.size() - kFanTachPrefix.size() - kFanTachSuffix.size()); |
| uint32_t index_int; |
| if (!absl::SimpleAtoi(index, &index_int)) { |
| return absl::InternalError(absl::Substitute( |
| "Failed to convert fan tach index to int: $0", index)); |
| } |
| tachs[index_int].tach_input = entry; |
| } |
| |
| constexpr std::string_view kPwmPrefix = "pwm"; |
| constexpr std::string_view kPwmEnableSuffix = "_enable"; |
| uint32_t index_int; |
| if (RE2::FullMatch(entry_path, absl::StrCat(kPwmPrefix, "(\\d+)"), |
| &index_int)) { |
| pwms[index_int].pwm = entry; |
| } |
| if (absl::StartsWith(entry_path, kPwmPrefix) && |
| absl::EndsWith(entry_path, kPwmEnableSuffix)) { |
| std::string_view index = entry_path.substr( |
| kPwmPrefix.size(), |
| entry_path.size() - kPwmPrefix.size() - kPwmEnableSuffix.size()); |
| if (!absl::SimpleAtoi(index, &index_int)) { |
| return absl::InternalError(absl::Substitute( |
| "Failed to convert pwm enable index to int: $0", index)); |
| } |
| pwms[index_int].pwm_enable = entry; |
| } |
| } |
| |
| return std::make_shared<FanController>(Token(), config, std::move(tachs), |
| std::move(pwms)); |
| } |
| |
| } // namespace milotic_tlbmc |