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