1 #pragma once 2 3 #include <phosphor-logging/log.hpp> 4 #include <sdbusplus/bus.hpp> 5 #include <sdbusplus/bus/match.hpp> 6 #include <sdeventplus/clock.hpp> 7 #include <sdeventplus/event.hpp> 8 #include <sdeventplus/utility/timer.hpp> 9 10 #include <chrono> 11 #include <deque> 12 #include <format> 13 #include <optional> 14 #include <utility> 15 16 namespace phosphor 17 { 18 namespace fan 19 { 20 namespace monitor 21 { 22 23 class Fan; 24 25 constexpr auto FAN_SENSOR_PATH = "/xyz/openbmc_project/sensors/fan_tach/"; 26 27 /** 28 * The mode fan monitor will run in: 29 * - init - only do the initialization steps 30 * - monitor - run normal monitoring algorithm 31 */ 32 enum class Mode 33 { 34 init, 35 monitor 36 }; 37 38 /** 39 * The mode that the timer is running in: 40 * - func - Transition to functional state timer 41 * - nonfunc - Transition to nonfunctional state timer 42 */ 43 enum class TimerMode 44 { 45 func, 46 nonfunc 47 }; 48 49 /** 50 * The mode that the method is running in: 51 * - time - Use a percentage based deviation 52 * - count - Run up/down count fault detection 53 */ 54 enum MethodMode 55 { 56 timebased = 0, 57 count 58 }; 59 60 /** 61 * @class TachSensor 62 * 63 * This class represents the sensor that reads a tach value. 64 * It may also support a Target, which is the property used to 65 * set a speed. Since it doesn't necessarily have a Target, it 66 * won't for sure know if it is running too slow, so it leaves 67 * that determination to other code. 68 * 69 * This class has a parent Fan object that knows about all 70 * sensors for that fan. 71 */ 72 class TachSensor 73 { 74 public: 75 TachSensor() = delete; 76 TachSensor(const TachSensor&) = delete; 77 // TachSensor is not moveable since the this pointer is used as systemd 78 // callback context. 79 TachSensor(TachSensor&&) = delete; 80 TachSensor& operator=(const TachSensor&) = delete; 81 TachSensor& operator=(TachSensor&&) = delete; 82 ~TachSensor() = default; 83 84 /** 85 * @brief Constructor 86 * 87 * @param[in] mode - mode of fan monitor 88 * @param[in] bus - the dbus object 89 * @param[in] fan - the parent fan object 90 * @param[in] id - the id of the sensor 91 * @param[in] hasTarget - if the sensor supports 92 * setting the speed 93 * @param[in] funcDelay - Delay to mark functional 94 * @param[in] interface - the interface of the target 95 * @param[in] path - the object path of the sensor target 96 * @param[in] factor - the factor of the sensor target 97 * @param[in] offset - the offset of the sensor target 98 * @param[in] method - the method of out of range 99 * @param[in] threshold - the threshold of counter method 100 * @param[in] ignoreAboveMax - whether to ignore being above max or not 101 * @param[in] timeout - Normal timeout value to use 102 * @param[in] errorDelay - Delay in seconds before creating an error 103 * or std::nullopt if no errors. 104 * @param[in] countInterval - In count mode interval 105 * 106 * @param[in] event - Event loop reference 107 */ 108 TachSensor(Mode mode, sdbusplus::bus_t& bus, Fan& fan, 109 const std::string& id, bool hasTarget, size_t funcDelay, 110 const std::string& interface, const std::string& path, 111 double factor, int64_t offset, size_t method, size_t threshold, 112 bool ignoreAboveMax, size_t timeout, 113 const std::optional<size_t>& errorDelay, size_t countInterval, 114 const sdeventplus::Event& event); 115 116 /** 117 * @brief Reads a property from the input message and stores it in value. 118 * T is the value type. 119 * 120 * Note: This can only be called once per message. 121 * 122 * @param[in] msg - the dbus message that contains the data 123 * @param[in] interface - the interface the property is on 124 * @param[in] propertName - the name of the property 125 * @param[out] value - the value to store the property value in 126 */ 127 template <typename T> readPropertyFromMessage(sdbusplus::message_t & msg,const std::string & interface,const std::string & propertyName,T & value)128 static void readPropertyFromMessage( 129 sdbusplus::message_t& msg, const std::string& interface, 130 const std::string& propertyName, T& value) 131 { 132 std::string sensor; 133 std::map<std::string, std::variant<T>> data; 134 msg.read(sensor, data); 135 136 if (sensor.compare(interface) == 0) 137 { 138 auto propertyMap = data.find(propertyName); 139 if (propertyMap != data.end()) 140 { 141 value = std::get<T>(propertyMap->second); 142 } 143 } 144 } 145 146 /** 147 * @brief Returns the target speed value 148 */ 149 uint64_t getTarget() const; 150 151 /** 152 * @brief Returns the input speed value 153 */ getInput() const154 inline double getInput() const 155 { 156 return _tachInput; 157 } 158 159 /** 160 * @brief Returns true if sensor has a target 161 */ hasTarget() const162 inline bool hasTarget() const 163 { 164 return _hasTarget; 165 } 166 167 /** 168 * @brief Returns the interface of the sensor target 169 */ getInterface() const170 inline std::string getInterface() const 171 { 172 return _interface; 173 } 174 175 /** 176 * @brief Returns true if sensor has a D-Bus owner 177 */ hasOwner() const178 inline bool hasOwner() const 179 { 180 return _hasOwner; 181 } 182 183 /** 184 * @brief sets D-Bus owner status 185 * 186 * @param[in] val - new owner status 187 */ setOwner(bool val)188 inline void setOwner(bool val) 189 { 190 _hasOwner = val; 191 } 192 193 /** 194 * @brief Returns the factor of the sensor target 195 */ getFactor() const196 inline double getFactor() const 197 { 198 return _factor; 199 } 200 201 /** 202 * @brief Returns a reference to the sensor's Fan object 203 */ getFan() const204 inline Fan& getFan() const 205 { 206 return _fan; 207 } 208 209 /** 210 * @brief Returns the offset of the sensor target 211 */ getOffset() const212 inline int64_t getOffset() const 213 { 214 return _offset; 215 } 216 217 /** 218 * @brief Returns the method of out of range 219 */ getMethod() const220 inline size_t getMethod() const 221 { 222 return _method; 223 } 224 225 /** 226 * @brief Returns the threshold of count method 227 */ getThreshold() const228 inline size_t getThreshold() const 229 { 230 return _threshold; 231 } 232 233 /** 234 * Set the sensor faulted counter 235 */ 236 void setCounter(bool count); 237 238 /** 239 * @brief Returns the sensor faulted count 240 */ getCounter() const241 inline size_t getCounter() const 242 { 243 return _counter; 244 } 245 246 /** 247 * Returns true if the hardware behind this 248 * sensor is considered working OK/functional. 249 */ functional() const250 inline bool functional() const 251 { 252 return _functional; 253 } 254 255 /** 256 * Set the functional status and update inventory to match 257 * 258 * @param[in] functional - The new state 259 * @param[in] skipErrorTimer - If setting the sensor to 260 * nonfunctional, don't start the error timer. 261 */ 262 void setFunctional(bool functional, bool skipErrorTimer = false); 263 264 /** 265 * @brief Says if the timer is running or not 266 * 267 * @return bool - if timer is currently running 268 */ timerRunning()269 inline bool timerRunning() 270 { 271 return _timer.isEnabled(); 272 } 273 274 /** 275 * @brief Stops the timer when the given mode differs and starts 276 * the associated timer for the mode given if not already running 277 * 278 * @param[in] mode - mode of timer to start 279 */ 280 void startTimer(TimerMode mode); 281 282 /** 283 * @brief Stops the timer 284 */ stopTimer()285 inline void stopTimer() 286 { 287 phosphor::logging::log<phosphor::logging::level::DEBUG>( 288 std::format("Stop running timer on tach sensor {}.", _name) 289 .c_str()); 290 _timer.setEnabled(false); 291 } 292 293 /** 294 * @brief Says if the count timer is running 295 * 296 * @return bool - If count timer running 297 */ countTimerRunning() const298 inline bool countTimerRunning() const 299 { 300 return _countTimer && _countTimer->isEnabled(); 301 } 302 303 /** 304 * @brief Stops the count timer 305 */ 306 void stopCountTimer(); 307 308 /** 309 * @brief Starts the count timer 310 */ 311 void startCountTimer(); 312 313 /** 314 * @brief Return the given timer mode's delay time 315 * 316 * @param[in] mode - mode of timer to get delay time for 317 */ 318 std::chrono::microseconds getDelay(TimerMode mode); 319 320 /** 321 * Returns the sensor name 322 */ name() const323 inline const std::string& name() const 324 { 325 return _name; 326 }; 327 328 /** 329 * @brief Says if the error timer is running 330 * 331 * @return bool - If the timer is running 332 */ errorTimerRunning() const333 bool errorTimerRunning() const 334 { 335 if (_errorTimer && _errorTimer->isEnabled()) 336 { 337 return true; 338 } 339 return false; 340 } 341 342 /** 343 * @brief Get the current allowed range of speeds 344 * 345 * @param[in] lowerDeviation - The configured lower deviation(in percent) 346 * allowed 347 * @param[in] upperDeviation - The configured upper deviation(in percent) 348 * allowed 349 * 350 * @return pair - Min/Max(optional) range of speeds allowed 351 */ 352 std::pair<uint64_t, std::optional<uint64_t>> getRange( 353 const size_t lowerDeviation, const size_t upperDeviation) const; 354 355 /** 356 * @brief Processes the current state of the sensor 357 */ 358 void processState(); 359 360 /** 361 * @brief Resets the monitoring method of the sensor 362 */ 363 void resetMethod(); 364 365 /** 366 * @brief Refreshes the tach input and target values by 367 * reading them from D-Bus. 368 */ 369 void updateTachAndTarget(); 370 371 /** 372 * @brief return the previous tach values 373 */ getPrevTach() const374 const std::deque<uint64_t>& getPrevTach() const 375 { 376 return _prevTachs; 377 } 378 379 /** 380 * @brief return the previous target values 381 */ getPrevTarget() const382 const std::deque<uint64_t>& getPrevTarget() const 383 { 384 return _prevTargets; 385 } 386 387 private: 388 /** 389 * @brief Returns the match string to use for matching 390 * on a properties changed signal. 391 */ 392 std::string getMatchString(const std::optional<std::string> path, 393 const std::string& interface); 394 395 /** 396 * @brief Reads the Target property and stores in _tachTarget. 397 * Also calls Fan::tachChanged(). 398 * 399 * @param[in] msg - the dbus message 400 */ 401 void handleTargetChange(sdbusplus::message_t& msg); 402 403 /** 404 * @brief Reads the Value property and stores in _tachInput. 405 * Also calls Fan::tachChanged(). 406 * 407 * @param[in] msg - the dbus message 408 */ 409 void handleTachChange(sdbusplus::message_t& msg); 410 411 /** 412 * @brief Updates the Functional property in the inventory 413 * for this tach sensor based on the value passed in. 414 * 415 * @param[in] functional - If the Functional property should 416 * be set to true or false. 417 */ 418 void updateInventory(bool functional); 419 420 /** 421 * @brief the dbus object 422 */ 423 sdbusplus::bus_t& _bus; 424 425 /** 426 * @brief Reference to the parent Fan object 427 */ 428 Fan& _fan; 429 430 /** 431 * @brief The name of the sensor, including the full path 432 * 433 * For example /xyz/openbmc_project/sensors/fan_tach/fan0 434 */ 435 const std::string _name; 436 437 /** 438 * @brief The inventory name of the sensor, including the full path 439 */ 440 const std::string _invName; 441 442 /** 443 * @brief If functional (not too slow). The parent 444 * fan object sets this. 445 */ 446 bool _functional = true; 447 448 /** 449 * @brief If the sensor has a Target property (can set speed) 450 */ 451 const bool _hasTarget; 452 453 /** 454 * @brief If the sensor has a D-Bus owner 455 */ 456 bool _hasOwner = true; 457 458 /** 459 * @brief Amount of time to delay updating to functional 460 */ 461 const size_t _funcDelay; 462 463 /** 464 * @brief The interface that the target implements 465 */ 466 const std::string _interface; 467 468 /** 469 * @brief The object path to set sensor's target 470 */ 471 const std::string _path; 472 473 /** 474 * @brief The factor of target to get fan rpm 475 */ 476 const double _factor; 477 478 /** 479 * @brief The offset of target to get fan rpm 480 */ 481 const int64_t _offset; 482 483 /** 484 * @brief The method of out of range 485 */ 486 const size_t _method; 487 488 /** 489 * @brief The threshold for count method 490 */ 491 const size_t _threshold; 492 493 /** 494 * @brief Whether to ignore being above the max or not 495 */ 496 const bool _ignoreAboveMax; 497 498 /** 499 * @brief The counter for count method 500 */ 501 size_t _counter = 0; 502 503 /** 504 * @brief The input speed, from the Value dbus property 505 */ 506 double _tachInput = 0; 507 508 /** 509 * @brief The current target speed, from the Target dbus property 510 * (if applicable) 511 */ 512 uint64_t _tachTarget = 0; 513 514 /** 515 * @brief The timeout value to use 516 */ 517 const size_t _timeout; 518 519 /** 520 * @brief Mode that current timer is in 521 */ 522 TimerMode _timerMode; 523 524 /** 525 * The timer object 526 */ 527 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _timer; 528 529 /** 530 * @brief The match object for the Value properties changed signal 531 */ 532 std::unique_ptr<sdbusplus::bus::match_t> tachSignal; 533 534 /** 535 * @brief The match object for the Target properties changed signal 536 */ 537 std::unique_ptr<sdbusplus::bus::match_t> targetSignal; 538 539 /** 540 * @brief The number of seconds to wait between a sensor being set 541 * to nonfunctional and creating an error for it. 542 * 543 * If std::nullopt, no errors will be created. 544 */ 545 const std::optional<size_t> _errorDelay; 546 547 /** 548 * @brief The timer that uses _errorDelay. When it expires an error 549 * will be created for a faulted fan sensor (rotor). 550 * 551 * If _errorDelay is std::nullopt, then this won't be created. 552 */ 553 std::unique_ptr< 554 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>> 555 _errorTimer; 556 557 /** 558 * @brief The interval, in seconds, to use for the timer that runs 559 * the checks when using the 'count' method. 560 */ 561 size_t _countInterval; 562 563 /** 564 * @brief The timer used by the 'count' method for determining 565 * functional status. 566 */ 567 std::unique_ptr< 568 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>> 569 _countTimer; 570 571 /** 572 * @brief record of previous targets 573 */ 574 std::deque<uint64_t> _prevTargets; 575 576 /** 577 * @brief record of previous tach readings 578 */ 579 std::deque<uint64_t> _prevTachs; 580 }; 581 582 } // namespace monitor 583 } // namespace fan 584 } // namespace phosphor 585