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 Get the list of signal events 416 * 417 * @return - List of signal events 418 */ 419 inline auto& getSignalEvents() 420 { 421 return _signalEvents; 422 } 423 424 /** 425 * @brief Find the first instance of a signal event 426 * 427 * @param[in] signal - Event signal to find 428 * @param[in] eGroup - Group associated with the signal 429 * @param[in] eActions - List of actions associated with the signal 430 * 431 * @return - Iterator to the stored signal event 432 */ 433 std::vector<SignalEvent>::iterator findSignal( 434 const Trigger& signal, 435 const Group& eGroup, 436 const std::vector<Action>& eActions); 437 438 /** 439 * @brief Remove the given signal event 440 * 441 * @param[in] seIter - Iterator pointing to the signal event to remove 442 */ 443 inline void removeSignal(std::vector<SignalEvent>::iterator& seIter) 444 { 445 assert(seIter != std::end(_signalEvents)); 446 std::get<signalEventDataPos>(*seIter).reset(); 447 if (std::get<signalMatchPos>(*seIter) != nullptr) 448 { 449 std::get<signalMatchPos>(*seIter).reset(); 450 } 451 _signalEvents.erase(seIter); 452 } 453 454 /** 455 * @brief Get the list of timer events 456 * 457 * @return - List of timer events 458 */ 459 inline auto& getTimerEvents() 460 { 461 return _timerEvents; 462 } 463 464 /** 465 * @brief Find the first instance of a timer event 466 * 467 * @param[in] eventGroup - Group associated with a timer 468 * @param[in] eventActions - List of actions associated with a timer 469 * 470 * @return - Iterator to the timer event 471 */ 472 std::vector<TimerEvent>::iterator findTimer( 473 const Group& eventGroup, 474 const std::vector<Action>& eventActions); 475 476 /** 477 * @brief Add a timer to the list of timer based events 478 * 479 * @param[in] group - Group associated with a timer 480 * @param[in] actions - List of actions associated with a timer 481 * @param[in] tConf - Configuration for the new timer 482 */ 483 void addTimer(const Group& group, 484 const std::vector<Action>& actions, 485 const TimerConf& tConf); 486 487 /** 488 * @brief Remove the given timer event 489 * 490 * @param[in] teIter - Iterator pointing to the timer event to remove 491 */ 492 inline void removeTimer(std::vector<TimerEvent>::iterator& teIter) 493 { 494 _timerEvents.erase(teIter); 495 } 496 497 /** 498 * @brief Callback function for event timers that processes the given 499 * actions for a group 500 * 501 * @param[in] eventGroup - Group to process actions on 502 * @param[in] eventActions - List of event actions to run 503 */ 504 void timerExpired(const Group& eventGroup, 505 const std::vector<Action>& eventActions); 506 507 /** 508 * @brief Get the service for a given path and interface from cached 509 * dataset and add a service that's not found 510 * 511 * @param[in] path - Path to get service for 512 * @param[in] intf - Interface to get service for 513 * 514 * @return - The service name 515 */ 516 const std::string& getService(const std::string& path, 517 const std::string& intf); 518 519 /** 520 * @brief Add a set of services for a path and interface 521 * by retrieving all the path subtrees to the given depth 522 * from root for the interface 523 * 524 * @param[in] path - Path to add services for 525 * @param[in] intf - Interface to add services for 526 * @param[in] depth - Depth of tree traversal from root path 527 * 528 * @return - The associated service to the given path and interface 529 * or empty string for no service found 530 */ 531 const std::string& addServices(const std::string& path, 532 const std::string& intf, 533 int32_t depth); 534 535 /** 536 * @brief Dbus signal change callback handler 537 * 538 * @param[in] msg - Expanded sdbusplus message data 539 * @param[in] eventData - The single event's data 540 */ 541 void handleEvent(sdbusplus::message::message& msg, 542 const EventData* eventData); 543 544 /** 545 * @brief Add a signal to the list of signal based events 546 * 547 * @param[in] data - Event data for signal 548 * @param[in] match - Subscribed signal match 549 */ 550 inline void addSignal( 551 std::unique_ptr<EventData>&& data, 552 std::unique_ptr<sdbusplus::server::match::match>&& match) 553 { 554 _signalEvents.emplace_back(std::move(data), std::move(match)); 555 } 556 557 /** 558 * @brief Set a property to be persisted 559 * 560 * @param[in] intf - Interface containing property 561 * @param[in] prop - Property to be persisted 562 */ 563 inline void setPersisted(const std::string& intf, 564 const std::string& prop) 565 { 566 _persisted[intf].emplace_back(prop); 567 } 568 569 /** 570 * @brief Get persisted property 571 * 572 * @param[in] intf - Interface containing property 573 * @param[in] prop - Property persisted 574 * 575 * @return - True if property is to be persisted, false otherwise 576 */ 577 auto getPersisted(const std::string& intf, 578 const std::string& prop); 579 580 /** 581 * @brief Get a property value from the zone object or the bus when 582 * the property requested is not on the zone object 583 * 584 * @param[in] path - Path of object 585 * @param[in] intf - Object interface 586 * @param[in] prop - Object property 587 * 588 * @return - Property's value 589 */ 590 template <typename T> 591 auto getPropertyByName(const std::string& path, 592 const std::string& intf, 593 const std::string& prop) 594 { 595 T value; 596 auto pathIter = _objects.find(path); 597 if (pathIter != _objects.end()) 598 { 599 auto intfIter = pathIter->second.find(intf); 600 if (intfIter != pathIter->second.end()) 601 { 602 if (intf == "xyz.openbmc_project.Control.ThermalMode") 603 { 604 auto var = ThermalMode::getPropertyByName(prop); 605 // Use visitor to determine if requested property 606 // type(T) is available on this interface and read it 607 std::visit([&value](auto&& val) 608 { 609 using V = std::decay_t<decltype(val)>; 610 if constexpr(std::is_same_v<T, V>) 611 { 612 value = val; 613 } 614 }, var); 615 616 return value; 617 } 618 } 619 } 620 621 auto service = getService(path, intf); 622 value = util::SDBusPlus::getProperty<T>(_bus, 623 service, 624 path, 625 intf, 626 prop); 627 628 return value; 629 }; 630 631 /** 632 * @brief Overridden thermal object's set 'Current' property function 633 * 634 * @param[in] value - Value to set 'Current' to 635 * 636 * @return - The updated value of the 'Current' property 637 */ 638 virtual std::string current(std::string value); 639 640 private: 641 642 /** 643 * The dbus object 644 */ 645 sdbusplus::bus::bus& _bus; 646 647 /** 648 * Zone object path 649 */ 650 const std::string _path; 651 652 /** 653 * Zone supported interfaces 654 */ 655 const std::vector<std::string> _ifaces; 656 657 /** 658 * Full speed for the zone 659 */ 660 const uint64_t _fullSpeed; 661 662 /** 663 * The zone number 664 */ 665 const size_t _zoneNum; 666 667 /** 668 * The default floor speed for the zone 669 */ 670 const uint64_t _defFloorSpeed; 671 672 /** 673 * The default ceiling speed for the zone 674 */ 675 const uint64_t _defCeilingSpeed; 676 677 /** 678 * The floor speed to not go below 679 */ 680 uint64_t _floorSpeed = _defFloorSpeed; 681 682 /** 683 * The ceiling speed to not go above 684 */ 685 uint64_t _ceilingSpeed = _defCeilingSpeed; 686 687 /** 688 * The previous sensor value for calculating the ceiling 689 */ 690 int64_t _ceilingKeyValue = 0; 691 692 /** 693 * Automatic fan control active state 694 */ 695 bool _isActive = true; 696 697 /** 698 * Target speed for this zone 699 */ 700 uint64_t _targetSpeed = _fullSpeed; 701 702 /** 703 * Speed increase delta 704 */ 705 uint64_t _incSpeedDelta = 0; 706 707 /** 708 * Speed decrease delta 709 */ 710 uint64_t _decSpeedDelta = 0; 711 712 /** 713 * Requested speed base 714 */ 715 uint64_t _requestSpeedBase = 0; 716 717 /** 718 * Speed increase delay in seconds 719 */ 720 std::chrono::seconds _incDelay; 721 722 /** 723 * Speed decrease interval in seconds 724 */ 725 std::chrono::seconds _decInterval; 726 727 /** 728 * The increase timer object 729 */ 730 Timer _incTimer; 731 732 /** 733 * The decrease timer object 734 */ 735 Timer _decTimer; 736 737 /** 738 * Event loop used on set speed event timers 739 */ 740 sdeventplus::Event _eventLoop; 741 742 /** 743 * The vector of fans in this zone 744 */ 745 std::vector<std::unique_ptr<Fan>> _fans; 746 747 /** 748 * @brief Map of object property values 749 */ 750 std::map<std::string, 751 std::map<std::string, 752 std::map<std::string, 753 PropertyVariantType>>> _properties; 754 755 /** 756 * @brief Map of zone objects 757 */ 758 std::map<std::string, 759 std::map<std::string, 760 std::map<std::string, 761 EventData*>>> _objects; 762 763 /** 764 * @brief Map of interfaces to persisted properties 765 */ 766 std::map<std::string, std::vector<std::string>> _persisted; 767 768 /** 769 * @brief Map of active fan control allowed by groups 770 */ 771 std::map<const Group, bool> _active; 772 773 /** 774 * @brief Map of floor change allowed by groups 775 */ 776 std::map<const Group, bool> _floorChange; 777 778 /** 779 * @brief Map of groups controlling decreases allowed 780 */ 781 std::map<const Group, bool> _decAllowed; 782 783 /** 784 * @brief Map of group service names 785 */ 786 std::map<const Group, std::vector<Service>> _services; 787 788 /** 789 * @brief Map tree of paths to services of interfaces 790 */ 791 std::map<std::string, 792 std::map<std::string, 793 std::vector<std::string>>> _servTree; 794 795 /** 796 * @brief List of signal event arguments and Dbus matches for callbacks 797 */ 798 std::vector<SignalEvent> _signalEvents; 799 800 /** 801 * @brief List of timers for events 802 */ 803 std::vector<TimerEvent> _timerEvents; 804 805 /** 806 * @brief Save the thermal control current mode property 807 * to persisted storage 808 */ 809 void saveCurrentMode(); 810 811 /** 812 * @brief Restore persisted thermal control current mode property 813 * value, setting the mode to "Default" otherwise 814 */ 815 void restoreCurrentMode(); 816 817 /** 818 * @brief Get the request speed base if defined, otherwise the 819 * the current target speed is returned 820 * 821 * @return - The request speed base or current target speed 822 */ 823 inline auto getRequestSpeedBase() const 824 { 825 return (_requestSpeedBase != 0) ? _requestSpeedBase : _targetSpeed; 826 }; 827 }; 828 829 } 830 } 831 } 832