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