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::object< 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::bus& 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::message& msg, 567 const EventData* eventData); 568 569 /** 570 * @brief Add a signal to the list of signal based events 571 * 572 * @param[in] name - Event name 573 * @param[in] data - Event data for signal 574 * @param[in] match - Subscribed signal match 575 */ 576 inline void 577 addSignal(const std::string& name, std::unique_ptr<EventData>&& data, 578 std::unique_ptr<sdbusplus::server::match::match>&& match) 579 { 580 _signalEvents[name].emplace_back(std::move(data), std::move(match)); 581 } 582 583 /** 584 * @brief Set a property to be persisted 585 * 586 * @param[in] intf - Interface containing property 587 * @param[in] prop - Property to be persisted 588 */ 589 inline void setPersisted(const std::string& intf, const std::string& prop) 590 { 591 _persisted[intf].emplace_back(prop); 592 } 593 594 /** 595 * @brief Get persisted property 596 * 597 * @param[in] intf - Interface containing property 598 * @param[in] prop - Property persisted 599 * 600 * @return - True if property is to be persisted, false otherwise 601 */ 602 auto getPersisted(const std::string& intf, const std::string& prop); 603 604 /** 605 * @brief Get a property value from the zone object or the bus when 606 * the property requested is not on the zone object 607 * 608 * @param[in] path - Path of object 609 * @param[in] intf - Object interface 610 * @param[in] prop - Object property 611 * 612 * @return - Property's value 613 */ 614 template <typename T> 615 auto getPropertyByName(const std::string& path, const std::string& intf, 616 const std::string& prop) 617 { 618 T value; 619 auto pathIter = _objects.find(path); 620 if (pathIter != _objects.end()) 621 { 622 auto intfIter = pathIter->second.find(intf); 623 if (intfIter != pathIter->second.end()) 624 { 625 if (intf == "xyz.openbmc_project.Control.ThermalMode") 626 { 627 auto var = ThermalMode::getPropertyByName(prop); 628 // Use visitor to determine if requested property 629 // type(T) is available on this interface and read it 630 std::visit( 631 [&value](auto&& val) { 632 using V = std::decay_t<decltype(val)>; 633 if constexpr (std::is_same_v<T, V>) 634 { 635 value = val; 636 } 637 }, 638 var); 639 640 return value; 641 } 642 } 643 } 644 645 // Retrieve the property's value applying any visitors necessary 646 auto service = getService(path, intf); 647 auto variant = util::SDBusPlus::getPropertyVariant<PropertyVariantType>( 648 _bus, service, path, intf, prop); 649 value = getPropertyValueVisitor<T>(intf.c_str(), prop.c_str(), variant); 650 651 return value; 652 }; 653 654 /** 655 * @brief Overridden thermal object's set 'Current' property function 656 * 657 * @param[in] value - Value to set 'Current' to 658 * 659 * @return - The updated value of the 'Current' property 660 */ 661 virtual std::string current(std::string value); 662 663 private: 664 /** 665 * The dbus object 666 */ 667 sdbusplus::bus::bus& _bus; 668 669 /** 670 * Zone object path 671 */ 672 const std::string _path; 673 674 /** 675 * Zone supported interfaces 676 */ 677 const std::vector<std::string> _ifaces; 678 679 /** 680 * Full speed for the zone 681 */ 682 const uint64_t _fullSpeed; 683 684 /** 685 * The zone number 686 */ 687 const size_t _zoneNum; 688 689 /** 690 * The default floor speed for the zone 691 */ 692 uint64_t _defFloorSpeed; 693 694 /** 695 * The default ceiling speed for the zone 696 */ 697 const uint64_t _defCeilingSpeed; 698 699 /** 700 * The floor speed to not go below 701 */ 702 uint64_t _floorSpeed = _defFloorSpeed; 703 704 /** 705 * The ceiling speed to not go above 706 */ 707 uint64_t _ceilingSpeed = _defCeilingSpeed; 708 709 /** 710 * The previous sensor value for calculating the ceiling 711 */ 712 int64_t _ceilingKeyValue = 0; 713 714 /** 715 * Automatic fan control active state 716 */ 717 bool _isActive = true; 718 719 /** 720 * Target speed for this zone 721 */ 722 uint64_t _targetSpeed = _fullSpeed; 723 724 /** 725 * Speed increase delta 726 */ 727 uint64_t _incSpeedDelta = 0; 728 729 /** 730 * Speed decrease delta 731 */ 732 uint64_t _decSpeedDelta = 0; 733 734 /** 735 * Requested speed base 736 */ 737 uint64_t _requestSpeedBase = 0; 738 739 /** 740 * Speed increase delay in seconds 741 */ 742 std::chrono::seconds _incDelay; 743 744 /** 745 * Speed decrease interval in seconds 746 */ 747 std::chrono::seconds _decInterval; 748 749 /** 750 * The increase timer object 751 */ 752 Timer _incTimer; 753 754 /** 755 * The decrease timer object 756 */ 757 Timer _decTimer; 758 759 /** 760 * Event loop used on set speed event timers 761 */ 762 sdeventplus::Event _eventLoop; 763 764 /** 765 * The vector of fans in this zone 766 */ 767 std::vector<std::unique_ptr<Fan>> _fans; 768 769 /** 770 * @brief Map of object property values 771 */ 772 std::map<std::string, 773 std::map<std::string, std::map<std::string, PropertyVariantType>>> 774 _properties; 775 776 /** 777 * @brief Map of zone objects 778 */ 779 std::map<std::string, 780 std::map<std::string, std::map<std::string, EventData*>>> 781 _objects; 782 783 /** 784 * @brief Map of interfaces to persisted properties 785 */ 786 std::map<std::string, std::vector<std::string>> _persisted; 787 788 /** 789 * @brief Map of active fan control allowed by groups 790 */ 791 std::map<const Group, bool> _active; 792 793 /** 794 * @brief Map of floor change allowed by groups 795 */ 796 std::map<const Group, bool> _floorChange; 797 798 /** 799 * @brief Map of groups controlling decreases allowed 800 */ 801 std::map<const Group, bool> _decAllowed; 802 803 /** 804 * @brief Map of group service names 805 */ 806 std::map<const Group, std::vector<Service>> _services; 807 808 /** 809 * @brief Map tree of paths to services of interfaces 810 */ 811 std::map<std::string, std::map<std::string, std::vector<std::string>>> 812 _servTree; 813 814 /** 815 * @brief List of signal event arguments and Dbus matches 816 * for callbacks per event name 817 */ 818 std::map<std::string, std::vector<SignalEvent>> _signalEvents; 819 820 /** 821 * @brief List of timers per event name 822 */ 823 std::map<std::string, std::vector<TimerEvent>> _timerEvents; 824 825 /** 826 * @brief Save the thermal control current mode property 827 * to persisted storage 828 */ 829 void saveCurrentMode(); 830 831 /** 832 * @brief Restore persisted thermal control current mode property 833 * value, setting the mode to "Default" otherwise 834 */ 835 void restoreCurrentMode(); 836 837 /** 838 * @brief Get the request speed base if defined, otherwise the 839 * the current target speed is returned 840 * 841 * @return - The request speed base or current target speed 842 */ 843 inline auto getRequestSpeedBase() const 844 { 845 return (_requestSpeedBase != 0) ? _requestSpeedBase : _targetSpeed; 846 }; 847 }; 848 849 } // namespace control 850 } // namespace fan 851 } // namespace phosphor 852