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