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