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