1 #pragma once 2 #include <algorithm> 3 #include <cassert> 4 #include <chrono> 5 #include <sdbusplus/bus.hpp> 6 #include <sdeventplus/event.hpp> 7 #include <vector> 8 #include "fan.hpp" 9 #include "types.hpp" 10 #include "xyz/openbmc_project/Control/ThermalMode/server.hpp" 11 12 namespace phosphor 13 { 14 namespace fan 15 { 16 namespace control 17 { 18 19 using ThermalObject = sdbusplus::server::object::object< 20 sdbusplus::xyz::openbmc_project::Control::server::ThermalMode>; 21 22 /** 23 * The mode fan control will run in: 24 * - init - only do the initialization steps 25 * - control - run normal control algorithms 26 */ 27 enum class Mode 28 { 29 init, 30 control 31 }; 32 33 /** 34 * @class Represents a fan control zone, which is a group of fans 35 * that behave the same. 36 */ 37 class Zone : public ThermalObject 38 { 39 public: 40 41 Zone() = delete; 42 Zone(const Zone&) = delete; 43 Zone(Zone&&) = delete; 44 Zone& operator=(const Zone&) = delete; 45 Zone& operator=(Zone&&) = delete; 46 ~Zone() = default; 47 48 /** 49 * Constructor 50 * Creates the appropriate fan objects based on 51 * the zone definition data passed in. 52 * 53 * @param[in] mode - mode of fan control 54 * @param[in] bus - the dbus object 55 * @param[in] path - object instance path 56 * @param[in] event - Event loop reference 57 * @param[in] def - the fan zone definition data 58 */ 59 Zone(Mode mode, 60 sdbusplus::bus::bus& bus, 61 const std::string& path, 62 const sdeventplus::Event& event, 63 const ZoneDefinition& def); 64 65 /** 66 * Sets all fans in the zone to the speed 67 * passed in when the zone is active 68 * 69 * @param[in] speed - the fan speed 70 */ 71 void setSpeed(uint64_t speed); 72 73 /** 74 * Sets the zone to full speed regardless of zone's active state 75 */ 76 void setFullSpeed(); 77 78 /** 79 * @brief Sets the automatic fan control allowed active state 80 * 81 * @param[in] group - A group that affects the active state 82 * @param[in] isActiveAllow - Active state according to group 83 */ 84 void setActiveAllow(const Group* group, bool isActiveAllow); 85 86 /** 87 * @brief Sets the floor change allowed state 88 * 89 * @param[in] group - A group that affects floor changes 90 * @param[in] isAllow - Allow state according to group 91 */ 92 inline void setFloorChangeAllow(const Group* group, bool isAllow) 93 { 94 _floorChange[*(group)] = isAllow; 95 } 96 97 /** 98 * @brief Sets the decrease allowed state of a group 99 * 100 * @param[in] group - A group that affects speed decreases 101 * @param[in] isAllow - Allow state according to group 102 */ 103 inline void setDecreaseAllow(const Group* group, bool isAllow) 104 { 105 _decAllowed[*(group)] = isAllow; 106 } 107 108 /** 109 * @brief Sets a given object's property value 110 * 111 * @param[in] object - Name of the object containing the property 112 * @param[in] interface - Interface name containing the property 113 * @param[in] property - Property name 114 * @param[in] value - Property value 115 */ 116 template <typename T> 117 void setPropertyValue(const char* object, 118 const char* interface, 119 const char* property, 120 T value) 121 { 122 _properties[object][interface][property] = value; 123 }; 124 125 /** 126 * @brief Get the value of an object's property 127 * 128 * @param[in] object - Name of the object containing the property 129 * @param[in] interface - Interface name containing the property 130 * @param[in] property - Property name 131 * 132 * @return - The property value 133 */ 134 template <typename T> 135 inline auto getPropertyValue(const std::string& object, 136 const std::string& interface, 137 const std::string& property) 138 { 139 return sdbusplus::message::variant_ns::get<T>( 140 _properties.at(object).at(interface).at(property)); 141 }; 142 143 /** 144 * @brief Get the object's property variant 145 * 146 * @param[in] object - Name of the object containing the property 147 * @param[in] interface - Interface name containing the property 148 * @param[in] property - Property name 149 * 150 * @return - The property variant 151 */ 152 inline auto getPropValueVariant(const std::string& object, 153 const std::string& interface, 154 const std::string& property) 155 { 156 return _properties.at(object).at(interface).at(property); 157 }; 158 159 /** 160 * @brief Remove an object's interface 161 * 162 * @param[in] object - Name of the object with the interface 163 * @param[in] interface - Interface name to remove 164 */ 165 inline void removeObjectInterface(const char* object, 166 const char* interface) 167 { 168 auto it = _properties.find(object); 169 if (it != std::end(_properties)) 170 { 171 _properties[object].erase(interface); 172 } 173 } 174 175 /** 176 * @brief Remove a service associated to a group 177 * 178 * @param[in] group - Group associated with service 179 * @param[in] name - Service name to remove 180 */ 181 void removeService(const Group* group, 182 const std::string& name); 183 184 /** 185 * @brief Set or update a service name owner in use 186 * 187 * @param[in] group - Group associated with service 188 * @param[in] name - Service name 189 * @param[in] hasOwner - Whether the service is owned or not 190 */ 191 void setServiceOwner(const Group* group, 192 const std::string& name, 193 const bool hasOwner); 194 195 /** 196 * @brief Set or update all services for a group 197 * 198 * @param[in] group - Group to get service names for 199 */ 200 void setServices(const Group* group); 201 202 /** 203 * @brief Get the group's list of service names 204 * 205 * @param[in] group - Group to get service names for 206 * 207 * @return - The list of service names 208 */ 209 inline auto getGroupServices(const Group* group) 210 { 211 return _services.at(*group); 212 } 213 214 /** 215 * @brief Initialize a set speed event properties and actions 216 * 217 * @param[in] event - Set speed event 218 */ 219 void initEvent(const SetSpeedEvent& event); 220 221 /** 222 * @brief Removes all the set speed event properties and actions 223 * 224 * @param[in] event - Set speed event 225 */ 226 void removeEvent(const SetSpeedEvent& event); 227 228 /** 229 * @brief Get the default floor speed 230 * 231 * @return - The defined default floor speed 232 */ 233 inline auto getDefFloor() 234 { 235 return _defFloorSpeed; 236 }; 237 238 /** 239 * @brief Get the ceiling speed 240 * 241 * @return - The current ceiling speed 242 */ 243 inline auto& getCeiling() const 244 { 245 return _ceilingSpeed; 246 }; 247 248 /** 249 * @brief Set the ceiling speed to the given speed 250 * 251 * @param[in] speed - Speed to set the ceiling to 252 */ 253 inline void setCeiling(uint64_t speed) 254 { 255 _ceilingSpeed = speed; 256 }; 257 258 /** 259 * @brief Swaps the ceiling key value with what's given and 260 * returns the value that was swapped. 261 * 262 * @param[in] keyValue - New ceiling key value 263 * 264 * @return - Ceiling key value prior to swapping 265 */ 266 inline auto swapCeilingKeyValue(int64_t keyValue) 267 { 268 std::swap(_ceilingKeyValue, keyValue); 269 return keyValue; 270 }; 271 272 /** 273 * @brief Get the increase speed delta 274 * 275 * @return - The current increase speed delta 276 */ 277 inline auto& getIncSpeedDelta() const 278 { 279 return _incSpeedDelta; 280 }; 281 282 /** 283 * @brief Get the decrease speed delta 284 * 285 * @return - The current decrease speed delta 286 */ 287 inline auto& getDecSpeedDelta() const 288 { 289 return _decSpeedDelta; 290 }; 291 292 /** 293 * @brief Set the floor speed to the given speed and increase target 294 * speed to the floor when target is below floor where floor changes 295 * are allowed. 296 * 297 * @param[in] speed - Speed to set the floor to 298 */ 299 void setFloor(uint64_t speed); 300 301 /** 302 * @brief Set the requested speed base to be used as the speed to 303 * base a new requested speed target from 304 * 305 * @param[in] speedBase - Base speed value to use 306 */ 307 inline void setRequestSpeedBase(uint64_t speedBase) 308 { 309 _requestSpeedBase = speedBase; 310 }; 311 312 /** 313 * @brief Calculate the requested target speed from the given delta 314 * and increase the fan speeds, not going above the ceiling. 315 * 316 * @param[in] targetDelta - The delta to increase the target speed by 317 */ 318 void requestSpeedIncrease(uint64_t targetDelta); 319 320 /** 321 * @brief Calculate the requested target speed from the given delta 322 * and increase the fan speeds, not going above the ceiling. 323 * 324 * @param[in] targetDelta - The delta to increase the target speed by 325 */ 326 void requestSpeedDecrease(uint64_t targetDelta); 327 328 /** 329 * @brief Callback function for the increase timer that delays 330 * processing of requested speed increases while fans are increasing 331 */ 332 void incTimerExpired(); 333 334 /** 335 * @brief Callback function for the decrease timer that processes any 336 * requested speed decreases if allowed 337 */ 338 void decTimerExpired(); 339 340 /** 341 * @brief Get the event loop used with this zone's timers 342 * 343 * @return - The event loop for timers 344 */ 345 inline auto& getEventLoop() 346 { 347 return _eventLoop; 348 } 349 350 /** 351 * @brief Get the list of signal events 352 * 353 * @return - List of signal events 354 */ 355 inline auto& getSignalEvents() 356 { 357 return _signalEvents; 358 } 359 360 /** 361 * @brief Find the first instance of a signal event 362 * 363 * @param[in] signal - Event signal to find 364 * @param[in] eGroup - Group associated with the signal 365 * @param[in] eActions - List of actions associated with the signal 366 * 367 * @return - Iterator to the stored signal event 368 */ 369 std::vector<SignalEvent>::iterator findSignal( 370 const Signal& signal, 371 const Group& eGroup, 372 const std::vector<Action>& eActions); 373 374 /** 375 * @brief Remove the given signal event 376 * 377 * @param[in] seIter - Iterator pointing to the signal event to remove 378 */ 379 inline void removeSignal(std::vector<SignalEvent>::iterator& seIter) 380 { 381 assert(seIter != std::end(_signalEvents)); 382 std::get<signalEventDataPos>(*seIter).reset(); 383 if (std::get<signalMatchPos>(*seIter) != nullptr) 384 { 385 std::get<signalMatchPos>(*seIter).reset(); 386 } 387 _signalEvents.erase(seIter); 388 } 389 390 /** 391 * @brief Get the list of timer events 392 * 393 * @return - List of timer events 394 */ 395 inline auto& getTimerEvents() 396 { 397 return _timerEvents; 398 } 399 400 /** 401 * @brief Find the first instance of a timer event 402 * 403 * @param[in] eventGroup - Group associated with a timer 404 * @param[in] eventActions - List of actions associated with a timer 405 * 406 * @return - Iterator to the timer event 407 */ 408 std::vector<TimerEvent>::iterator findTimer( 409 const Group& eventGroup, 410 const std::vector<Action>& eventActions); 411 412 /** 413 * @brief Add a timer to the list of timer based events 414 * 415 * @param[in] group - Group associated with a timer 416 * @param[in] actions - List of actions associated with a timer 417 * @param[in] tConf - Configuration for the new timer 418 */ 419 void addTimer(const Group& group, 420 const std::vector<Action>& actions, 421 const TimerConf& tConf); 422 423 /** 424 * @brief Remove the given timer event 425 * 426 * @param[in] teIter - Iterator pointing to the timer event to remove 427 */ 428 inline void removeTimer(std::vector<TimerEvent>::iterator& teIter) 429 { 430 _timerEvents.erase(teIter); 431 } 432 433 /** 434 * @brief Callback function for event timers that processes the given 435 * actions for a group 436 * 437 * @param[in] eventGroup - Group to process actions on 438 * @param[in] eventActions - List of event actions to run 439 */ 440 void timerExpired(const Group& eventGroup, 441 const std::vector<Action>& eventActions); 442 443 /** 444 * @brief Get the service for a given path and interface from cached 445 * dataset and add a service that's not found 446 * 447 * @param[in] path - Path to get service for 448 * @param[in] intf - Interface to get service for 449 * 450 * @return - The service name 451 */ 452 const std::string& getService(const std::string& path, 453 const std::string& intf); 454 455 /** 456 * @brief Add a set of services for a path and interface 457 * by retrieving all the path subtrees to the given depth 458 * from root for the interface 459 * 460 * @param[in] path - Path to add services for 461 * @param[in] intf - Interface to add services for 462 * @param[in] depth - Depth of tree traversal from root path 463 * 464 * @return - The associated service to the given path and interface 465 * or empty string for no service found 466 */ 467 const std::string& addServices(const std::string& path, 468 const std::string& intf, 469 int32_t depth); 470 471 /** 472 * @brief Overridden thermal object's set 'Current' property function 473 * 474 * @param[in] value - Value to set 'Current' to 475 * 476 * @return - The updated value of the 'Current' property 477 */ 478 virtual std::string current(std::string value); 479 480 private: 481 482 /** 483 * The dbus object 484 */ 485 sdbusplus::bus::bus& _bus; 486 487 /** 488 * Zone object path 489 */ 490 const std::string _path; 491 492 /** 493 * Full speed for the zone 494 */ 495 const uint64_t _fullSpeed; 496 497 /** 498 * The zone number 499 */ 500 const size_t _zoneNum; 501 502 /** 503 * The default floor speed for the zone 504 */ 505 const uint64_t _defFloorSpeed; 506 507 /** 508 * The default ceiling speed for the zone 509 */ 510 const uint64_t _defCeilingSpeed; 511 512 /** 513 * The floor speed to not go below 514 */ 515 uint64_t _floorSpeed = _defFloorSpeed; 516 517 /** 518 * The ceiling speed to not go above 519 */ 520 uint64_t _ceilingSpeed = _defCeilingSpeed; 521 522 /** 523 * The previous sensor value for calculating the ceiling 524 */ 525 int64_t _ceilingKeyValue = 0; 526 527 /** 528 * Automatic fan control active state 529 */ 530 bool _isActive = true; 531 532 /** 533 * Target speed for this zone 534 */ 535 uint64_t _targetSpeed = _fullSpeed; 536 537 /** 538 * Speed increase delta 539 */ 540 uint64_t _incSpeedDelta = 0; 541 542 /** 543 * Speed decrease delta 544 */ 545 uint64_t _decSpeedDelta = 0; 546 547 /** 548 * Requested speed base 549 */ 550 uint64_t _requestSpeedBase = 0; 551 552 /** 553 * Speed increase delay in seconds 554 */ 555 std::chrono::seconds _incDelay; 556 557 /** 558 * Speed decrease interval in seconds 559 */ 560 std::chrono::seconds _decInterval; 561 562 /** 563 * The increase timer object 564 */ 565 Timer _incTimer; 566 567 /** 568 * The decrease timer object 569 */ 570 Timer _decTimer; 571 572 /** 573 * Event loop used on set speed event timers 574 */ 575 sdeventplus::Event _eventLoop; 576 577 /** 578 * The vector of fans in this zone 579 */ 580 std::vector<std::unique_ptr<Fan>> _fans; 581 582 /** 583 * @brief Map of object property values 584 */ 585 std::map<std::string, 586 std::map<std::string, 587 std::map<std::string, 588 PropertyVariantType>>> _properties; 589 590 /** 591 * @brief Map of active fan control allowed by groups 592 */ 593 std::map<const Group, bool> _active; 594 595 /** 596 * @brief Map of floor change allowed by groups 597 */ 598 std::map<const Group, bool> _floorChange; 599 600 /** 601 * @brief Map of groups controlling decreases allowed 602 */ 603 std::map<const Group, bool> _decAllowed; 604 605 /** 606 * @brief Map of group service names 607 */ 608 std::map<const Group, std::vector<Service>> _services; 609 610 /** 611 * @brief Map tree of paths to services of interfaces 612 */ 613 std::map<std::string, 614 std::map<std::string, 615 std::vector<std::string>>> _servTree; 616 617 /** 618 * @brief List of signal event arguments and Dbus matches for callbacks 619 */ 620 std::vector<SignalEvent> _signalEvents; 621 622 /** 623 * @brief List of timers for events 624 */ 625 std::vector<TimerEvent> _timerEvents; 626 627 /** 628 * @brief Save the thermal control current mode property 629 * to persisted storage 630 */ 631 void saveCurrentMode(); 632 633 /** 634 * @brief Restore persisted thermal control current mode property 635 * value, setting the mode to "Default" otherwise 636 */ 637 void restoreCurrentMode(); 638 639 /** 640 * @brief Get the request speed base if defined, otherwise the 641 * the current target speed is returned 642 * 643 * @return - The request speed base or current target speed 644 */ 645 inline auto getRequestSpeedBase() const 646 { 647 return (_requestSpeedBase != 0) ? _requestSpeedBase : _targetSpeed; 648 }; 649 650 /** 651 * @brief Dbus signal change callback handler 652 * 653 * @param[in] msg - Expanded sdbusplus message data 654 * @param[in] eventData - The single event's data 655 */ 656 void handleEvent(sdbusplus::message::message& msg, 657 const EventData* eventData); 658 }; 659 660 } 661 } 662 } 663