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 Set the default floor 304 * 305 * @param[in] speed - Speed to set the default floor to 306 */ 307 inline void setDefFloor(uint64_t speed) 308 { 309 _defFloorSpeed = speed; 310 }; 311 312 /** 313 * @brief Get the ceiling speed 314 * 315 * @return - The current ceiling speed 316 */ 317 inline auto& getCeiling() const 318 { 319 return _ceilingSpeed; 320 }; 321 322 /** 323 * @brief Set the ceiling speed to the given speed 324 * 325 * @param[in] speed - Speed to set the ceiling to 326 */ 327 inline void setCeiling(uint64_t speed) 328 { 329 _ceilingSpeed = speed; 330 }; 331 332 /** 333 * @brief Swaps the ceiling key value with what's given and 334 * returns the value that was swapped. 335 * 336 * @param[in] keyValue - New ceiling key value 337 * 338 * @return - Ceiling key value prior to swapping 339 */ 340 inline auto swapCeilingKeyValue(int64_t keyValue) 341 { 342 std::swap(_ceilingKeyValue, keyValue); 343 return keyValue; 344 }; 345 346 /** 347 * @brief Get the increase speed delta 348 * 349 * @return - The current increase speed delta 350 */ 351 inline auto& getIncSpeedDelta() const 352 { 353 return _incSpeedDelta; 354 }; 355 356 /** 357 * @brief Get the decrease speed delta 358 * 359 * @return - The current decrease speed delta 360 */ 361 inline auto& getDecSpeedDelta() const 362 { 363 return _decSpeedDelta; 364 }; 365 366 /** 367 * @brief Set the floor speed to the given speed and increase target 368 * speed to the floor when target is below floor where floor changes 369 * are allowed. 370 * 371 * @param[in] speed - Speed to set the floor to 372 */ 373 void setFloor(uint64_t speed); 374 375 /** 376 * @brief Set the requested speed base to be used as the speed to 377 * base a new requested speed target from 378 * 379 * @param[in] speedBase - Base speed value to use 380 */ 381 inline void setRequestSpeedBase(uint64_t speedBase) 382 { 383 _requestSpeedBase = speedBase; 384 }; 385 386 /** 387 * @brief Calculate the requested target speed from the given delta 388 * and increase the fan speeds, not going above the ceiling. 389 * 390 * @param[in] targetDelta - The delta to increase the target speed by 391 */ 392 void requestSpeedIncrease(uint64_t targetDelta); 393 394 /** 395 * @brief Calculate the requested target speed from the given delta 396 * and increase the fan speeds, not going above the ceiling. 397 * 398 * @param[in] targetDelta - The delta to increase the target speed by 399 */ 400 void requestSpeedDecrease(uint64_t targetDelta); 401 402 /** 403 * @brief Callback function for the increase timer that delays 404 * processing of requested speed increases while fans are increasing 405 */ 406 void incTimerExpired(); 407 408 /** 409 * @brief Callback function for the decrease timer that processes any 410 * requested speed decreases if allowed 411 */ 412 void decTimerExpired(); 413 414 /** 415 * @brief Get the event loop used with this zone's timers 416 * 417 * @return - The event loop for timers 418 */ 419 inline auto& getEventLoop() 420 { 421 return _eventLoop; 422 } 423 424 /** 425 * @brief Remove the given signal event 426 * 427 * @param[in] seIter - Iterator pointing to the signal event to remove 428 */ 429 inline void removeSignal(std::vector<SignalEvent>::iterator& seIter) 430 { 431 std::get<signalEventDataPos>(*seIter).reset(); 432 if (std::get<signalMatchPos>(*seIter) != nullptr) 433 { 434 std::get<signalMatchPos>(*seIter).reset(); 435 } 436 } 437 438 /** 439 * @brief Get the list of timer events 440 * 441 * @return - List of timer events 442 */ 443 inline auto& getTimerEvents() 444 { 445 return _timerEvents; 446 } 447 448 /** 449 * @brief Find the first instance of a timer event 450 * 451 * @param[in] eventGroup - Group associated with a timer 452 * @param[in] eventActions - List of actions associated with a timer 453 * @param[in] eventTimers - List of timers to find the timer in 454 * 455 * @return - Iterator to the timer event 456 */ 457 std::vector<TimerEvent>::iterator findTimer( 458 const Group& eventGroup, 459 const std::vector<Action>& eventActions, 460 std::vector<TimerEvent>& eventTimers); 461 462 /** 463 * @brief Add a timer to the list of timer based events 464 * 465 * @param[in] name - Event name associated with timer 466 * @param[in] group - Group associated with a timer 467 * @param[in] actions - List of actions associated with a timer 468 * @param[in] tConf - Configuration for the new timer 469 */ 470 void addTimer(const std::string& name, 471 const Group& group, 472 const std::vector<Action>& actions, 473 const TimerConf& tConf); 474 475 /** 476 * @brief Callback function for event timers that processes the given 477 * actions for a group 478 * 479 * @param[in] eventGroup - Group to process actions on 480 * @param[in] eventActions - List of event actions to run 481 */ 482 void timerExpired(const Group& eventGroup, 483 const std::vector<Action>& eventActions); 484 485 /** 486 * @brief Get the service for a given path and interface from cached 487 * dataset and add a service that's not found 488 * 489 * @param[in] path - Path to get service for 490 * @param[in] intf - Interface to get service for 491 * 492 * @return - The service name 493 */ 494 const std::string& getService(const std::string& path, 495 const std::string& intf); 496 497 /** 498 * @brief Add a set of services for a path and interface 499 * by retrieving all the path subtrees to the given depth 500 * from root for the interface 501 * 502 * @param[in] path - Path to add services for 503 * @param[in] intf - Interface to add services for 504 * @param[in] depth - Depth of tree traversal from root path 505 * 506 * @return - The associated service to the given path and interface 507 * or empty string for no service found 508 */ 509 const std::string& addServices(const std::string& path, 510 const std::string& intf, 511 int32_t depth); 512 513 /** 514 * @brief Dbus signal change callback handler 515 * 516 * @param[in] msg - Expanded sdbusplus message data 517 * @param[in] eventData - The single event's data 518 */ 519 void handleEvent(sdbusplus::message::message& msg, 520 const EventData* eventData); 521 522 /** 523 * @brief Add a signal to the list of signal based events 524 * 525 * @param[in] name - Event name 526 * @param[in] data - Event data for signal 527 * @param[in] match - Subscribed signal match 528 */ 529 inline void addSignal( 530 const std::string& name, 531 std::unique_ptr<EventData>&& data, 532 std::unique_ptr<sdbusplus::server::match::match>&& match) 533 { 534 _signalEvents[name].emplace_back(std::move(data), std::move(match)); 535 } 536 537 /** 538 * @brief Set a property to be persisted 539 * 540 * @param[in] intf - Interface containing property 541 * @param[in] prop - Property to be persisted 542 */ 543 inline void setPersisted(const std::string& intf, 544 const std::string& prop) 545 { 546 _persisted[intf].emplace_back(prop); 547 } 548 549 /** 550 * @brief Get persisted property 551 * 552 * @param[in] intf - Interface containing property 553 * @param[in] prop - Property persisted 554 * 555 * @return - True if property is to be persisted, false otherwise 556 */ 557 auto getPersisted(const std::string& intf, 558 const std::string& prop); 559 560 /** 561 * @brief Get a property value from the zone object or the bus when 562 * the property requested is not on the zone object 563 * 564 * @param[in] path - Path of object 565 * @param[in] intf - Object interface 566 * @param[in] prop - Object property 567 * 568 * @return - Property's value 569 */ 570 template <typename T> 571 auto getPropertyByName(const std::string& path, 572 const std::string& intf, 573 const std::string& prop) 574 { 575 T value; 576 auto pathIter = _objects.find(path); 577 if (pathIter != _objects.end()) 578 { 579 auto intfIter = pathIter->second.find(intf); 580 if (intfIter != pathIter->second.end()) 581 { 582 if (intf == "xyz.openbmc_project.Control.ThermalMode") 583 { 584 auto var = ThermalMode::getPropertyByName(prop); 585 // Use visitor to determine if requested property 586 // type(T) is available on this interface and read it 587 std::visit([&value](auto&& val) 588 { 589 using V = std::decay_t<decltype(val)>; 590 if constexpr(std::is_same_v<T, V>) 591 { 592 value = val; 593 } 594 }, var); 595 596 return value; 597 } 598 } 599 } 600 601 auto service = getService(path, intf); 602 value = util::SDBusPlus::getProperty<T>(_bus, 603 service, 604 path, 605 intf, 606 prop); 607 608 return value; 609 }; 610 611 /** 612 * @brief Overridden thermal object's set 'Current' property function 613 * 614 * @param[in] value - Value to set 'Current' to 615 * 616 * @return - The updated value of the 'Current' property 617 */ 618 virtual std::string current(std::string value); 619 620 private: 621 622 /** 623 * The dbus object 624 */ 625 sdbusplus::bus::bus& _bus; 626 627 /** 628 * Zone object path 629 */ 630 const std::string _path; 631 632 /** 633 * Zone supported interfaces 634 */ 635 const std::vector<std::string> _ifaces; 636 637 /** 638 * Full speed for the zone 639 */ 640 const uint64_t _fullSpeed; 641 642 /** 643 * The zone number 644 */ 645 const size_t _zoneNum; 646 647 /** 648 * The default floor speed for the zone 649 */ 650 uint64_t _defFloorSpeed; 651 652 /** 653 * The default ceiling speed for the zone 654 */ 655 const uint64_t _defCeilingSpeed; 656 657 /** 658 * The floor speed to not go below 659 */ 660 uint64_t _floorSpeed = _defFloorSpeed; 661 662 /** 663 * The ceiling speed to not go above 664 */ 665 uint64_t _ceilingSpeed = _defCeilingSpeed; 666 667 /** 668 * The previous sensor value for calculating the ceiling 669 */ 670 int64_t _ceilingKeyValue = 0; 671 672 /** 673 * Automatic fan control active state 674 */ 675 bool _isActive = true; 676 677 /** 678 * Target speed for this zone 679 */ 680 uint64_t _targetSpeed = _fullSpeed; 681 682 /** 683 * Speed increase delta 684 */ 685 uint64_t _incSpeedDelta = 0; 686 687 /** 688 * Speed decrease delta 689 */ 690 uint64_t _decSpeedDelta = 0; 691 692 /** 693 * Requested speed base 694 */ 695 uint64_t _requestSpeedBase = 0; 696 697 /** 698 * Speed increase delay in seconds 699 */ 700 std::chrono::seconds _incDelay; 701 702 /** 703 * Speed decrease interval in seconds 704 */ 705 std::chrono::seconds _decInterval; 706 707 /** 708 * The increase timer object 709 */ 710 Timer _incTimer; 711 712 /** 713 * The decrease timer object 714 */ 715 Timer _decTimer; 716 717 /** 718 * Event loop used on set speed event timers 719 */ 720 sdeventplus::Event _eventLoop; 721 722 /** 723 * The vector of fans in this zone 724 */ 725 std::vector<std::unique_ptr<Fan>> _fans; 726 727 /** 728 * @brief Map of object property values 729 */ 730 std::map<std::string, 731 std::map<std::string, 732 std::map<std::string, 733 PropertyVariantType>>> _properties; 734 735 /** 736 * @brief Map of zone objects 737 */ 738 std::map<std::string, 739 std::map<std::string, 740 std::map<std::string, 741 EventData*>>> _objects; 742 743 /** 744 * @brief Map of interfaces to persisted properties 745 */ 746 std::map<std::string, std::vector<std::string>> _persisted; 747 748 /** 749 * @brief Map of active fan control allowed by groups 750 */ 751 std::map<const Group, bool> _active; 752 753 /** 754 * @brief Map of floor change allowed by groups 755 */ 756 std::map<const Group, bool> _floorChange; 757 758 /** 759 * @brief Map of groups controlling decreases allowed 760 */ 761 std::map<const Group, bool> _decAllowed; 762 763 /** 764 * @brief Map of group service names 765 */ 766 std::map<const Group, std::vector<Service>> _services; 767 768 /** 769 * @brief Map tree of paths to services of interfaces 770 */ 771 std::map<std::string, 772 std::map<std::string, 773 std::vector<std::string>>> _servTree; 774 775 /** 776 * @brief List of signal event arguments and Dbus matches 777 * for callbacks per event name 778 */ 779 std::map<std::string, std::vector<SignalEvent>> _signalEvents; 780 781 /** 782 * @brief List of timers per event name 783 */ 784 std::map<std::string, std::vector<TimerEvent>> _timerEvents; 785 786 /** 787 * @brief Save the thermal control current mode property 788 * to persisted storage 789 */ 790 void saveCurrentMode(); 791 792 /** 793 * @brief Restore persisted thermal control current mode property 794 * value, setting the mode to "Default" otherwise 795 */ 796 void restoreCurrentMode(); 797 798 /** 799 * @brief Get the request speed base if defined, otherwise the 800 * the current target speed is returned 801 * 802 * @return - The request speed base or current target speed 803 */ 804 inline auto getRequestSpeedBase() const 805 { 806 return (_requestSpeedBase != 0) ? _requestSpeedBase : _targetSpeed; 807 }; 808 }; 809 810 } 811 } 812 } 813