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 * Sets all fans in the zone to the speed 68 * passed in when the zone is active 69 * 70 * @param[in] speed - the fan speed 71 */ 72 void setSpeed(uint64_t speed); 73 74 /** 75 * Sets the zone to full speed regardless of zone's active state 76 */ 77 void setFullSpeed(); 78 79 /** 80 * @brief Sets the automatic fan control allowed active state 81 * 82 * @param[in] group - A group that affects the active state 83 * @param[in] isActiveAllow - Active state according to group 84 */ 85 void setActiveAllow(const Group* group, bool isActiveAllow); 86 87 /** 88 * @brief Sets the floor change allowed state 89 * 90 * @param[in] group - A group that affects floor changes 91 * @param[in] isAllow - Allow state according to group 92 */ 93 inline void setFloorChangeAllow(const Group* group, bool isAllow) 94 { 95 _floorChange[*(group)] = isAllow; 96 } 97 98 /** 99 * @brief Sets the decrease allowed state of a group 100 * 101 * @param[in] group - A group that affects speed decreases 102 * @param[in] isAllow - Allow state according to group 103 */ 104 inline void setDecreaseAllow(const Group* group, bool isAllow) 105 { 106 _decAllowed[*(group)] = isAllow; 107 } 108 109 /** 110 * @brief Sets a given object's property value 111 * 112 * @param[in] object - Name of the object containing the property 113 * @param[in] interface - Interface name containing the property 114 * @param[in] property - Property name 115 * @param[in] value - Property value 116 */ 117 template <typename T> 118 void setPropertyValue(const char* object, 119 const char* interface, 120 const char* property, 121 T value) 122 { 123 _properties[object][interface][property] = value; 124 }; 125 126 /** 127 * @brief Get the value of an object's property 128 * 129 * @param[in] object - Name of the object containing the property 130 * @param[in] interface - Interface name containing the property 131 * @param[in] property - Property name 132 * 133 * @return - The property value 134 */ 135 template <typename T> 136 inline auto getPropertyValue(const std::string& object, 137 const std::string& interface, 138 const std::string& property) 139 { 140 return sdbusplus::message::variant_ns::get<T>( 141 _properties.at(object).at(interface).at(property)); 142 }; 143 144 /** 145 * @brief Get the object's property variant 146 * 147 * @param[in] object - Name of the object containing the property 148 * @param[in] interface - Interface name containing the property 149 * @param[in] property - Property name 150 * 151 * @return - The property variant 152 */ 153 inline auto getPropValueVariant(const std::string& object, 154 const std::string& interface, 155 const std::string& property) 156 { 157 return _properties.at(object).at(interface).at(property); 158 }; 159 160 /** 161 * @brief Remove an object's interface 162 * 163 * @param[in] object - Name of the object with the interface 164 * @param[in] interface - Interface name to remove 165 */ 166 inline void removeObjectInterface(const char* object, 167 const char* interface) 168 { 169 auto it = _properties.find(object); 170 if (it != std::end(_properties)) 171 { 172 _properties[object].erase(interface); 173 } 174 } 175 176 /** 177 * @brief Remove a service associated to a group 178 * 179 * @param[in] group - Group associated with service 180 * @param[in] name - Service name to remove 181 */ 182 void removeService(const Group* group, 183 const std::string& name); 184 185 /** 186 * @brief Set or update a service name owner in use 187 * 188 * @param[in] group - Group associated with service 189 * @param[in] name - Service name 190 * @param[in] hasOwner - Whether the service is owned or not 191 */ 192 void setServiceOwner(const Group* group, 193 const std::string& name, 194 const bool hasOwner); 195 196 /** 197 * @brief Set or update all services for a group 198 * 199 * @param[in] group - Group to get service names for 200 */ 201 void setServices(const Group* group); 202 203 /** 204 * @brief Get the group's list of service names 205 * 206 * @param[in] group - Group to get service names for 207 * 208 * @return - The list of service names 209 */ 210 inline auto getGroupServices(const Group* group) 211 { 212 return _services.at(*group); 213 } 214 215 /** 216 * @brief Initialize a set speed event properties and actions 217 * 218 * @param[in] event - Set speed event 219 */ 220 void initEvent(const SetSpeedEvent& event); 221 222 /** 223 * @brief Removes all the set speed event properties and actions 224 * 225 * @param[in] event - Set speed event 226 */ 227 void removeEvent(const SetSpeedEvent& event); 228 229 /** 230 * @brief Get the default floor speed 231 * 232 * @return - The defined default floor speed 233 */ 234 inline auto getDefFloor() 235 { 236 return _defFloorSpeed; 237 }; 238 239 /** 240 * @brief Get the ceiling speed 241 * 242 * @return - The current ceiling speed 243 */ 244 inline auto& getCeiling() const 245 { 246 return _ceilingSpeed; 247 }; 248 249 /** 250 * @brief Set the ceiling speed to the given speed 251 * 252 * @param[in] speed - Speed to set the ceiling to 253 */ 254 inline void setCeiling(uint64_t speed) 255 { 256 _ceilingSpeed = speed; 257 }; 258 259 /** 260 * @brief Swaps the ceiling key value with what's given and 261 * returns the value that was swapped. 262 * 263 * @param[in] keyValue - New ceiling key value 264 * 265 * @return - Ceiling key value prior to swapping 266 */ 267 inline auto swapCeilingKeyValue(int64_t keyValue) 268 { 269 std::swap(_ceilingKeyValue, keyValue); 270 return keyValue; 271 }; 272 273 /** 274 * @brief Get the increase speed delta 275 * 276 * @return - The current increase speed delta 277 */ 278 inline auto& getIncSpeedDelta() const 279 { 280 return _incSpeedDelta; 281 }; 282 283 /** 284 * @brief Get the decrease speed delta 285 * 286 * @return - The current decrease speed delta 287 */ 288 inline auto& getDecSpeedDelta() const 289 { 290 return _decSpeedDelta; 291 }; 292 293 /** 294 * @brief Set the floor speed to the given speed and increase target 295 * speed to the floor when target is below floor where floor changes 296 * are allowed. 297 * 298 * @param[in] speed - Speed to set the floor to 299 */ 300 void setFloor(uint64_t speed); 301 302 /** 303 * @brief Set the requested speed base to be used as the speed to 304 * base a new requested speed target from 305 * 306 * @param[in] speedBase - Base speed value to use 307 */ 308 inline void setRequestSpeedBase(uint64_t speedBase) 309 { 310 _requestSpeedBase = speedBase; 311 }; 312 313 /** 314 * @brief Calculate the requested target speed from the given delta 315 * and increase the fan speeds, not going above the ceiling. 316 * 317 * @param[in] targetDelta - The delta to increase the target speed by 318 */ 319 void requestSpeedIncrease(uint64_t targetDelta); 320 321 /** 322 * @brief Calculate the requested target speed from the given delta 323 * and increase the fan speeds, not going above the ceiling. 324 * 325 * @param[in] targetDelta - The delta to increase the target speed by 326 */ 327 void requestSpeedDecrease(uint64_t targetDelta); 328 329 /** 330 * @brief Callback function for the increase timer that delays 331 * processing of requested speed increases while fans are increasing 332 */ 333 void incTimerExpired(); 334 335 /** 336 * @brief Callback function for the decrease timer that processes any 337 * requested speed decreases if allowed 338 */ 339 void decTimerExpired(); 340 341 /** 342 * @brief Get the event loop used with this zone's timers 343 * 344 * @return - The event loop for timers 345 */ 346 inline auto& getEventLoop() 347 { 348 return _eventLoop; 349 } 350 351 /** 352 * @brief Get the list of signal events 353 * 354 * @return - List of signal events 355 */ 356 inline auto& getSignalEvents() 357 { 358 return _signalEvents; 359 } 360 361 /** 362 * @brief Find the first instance of a signal event 363 * 364 * @param[in] signal - Event signal to find 365 * @param[in] eGroup - Group associated with the signal 366 * @param[in] eActions - List of actions associated with the signal 367 * 368 * @return - Iterator to the stored signal event 369 */ 370 std::vector<SignalEvent>::iterator findSignal( 371 const Signal& signal, 372 const Group& eGroup, 373 const std::vector<Action>& eActions); 374 375 /** 376 * @brief Remove the given signal event 377 * 378 * @param[in] seIter - Iterator pointing to the signal event to remove 379 */ 380 inline void removeSignal(std::vector<SignalEvent>::iterator& seIter) 381 { 382 assert(seIter != std::end(_signalEvents)); 383 std::get<signalEventDataPos>(*seIter).reset(); 384 if (std::get<signalMatchPos>(*seIter) != nullptr) 385 { 386 std::get<signalMatchPos>(*seIter).reset(); 387 } 388 _signalEvents.erase(seIter); 389 } 390 391 /** 392 * @brief Get the list of timer events 393 * 394 * @return - List of timer events 395 */ 396 inline auto& getTimerEvents() 397 { 398 return _timerEvents; 399 } 400 401 /** 402 * @brief Find the first instance of a timer event 403 * 404 * @param[in] eventGroup - Group associated with a timer 405 * @param[in] eventActions - List of actions associated with a timer 406 * 407 * @return - Iterator to the timer event 408 */ 409 std::vector<TimerEvent>::iterator findTimer( 410 const Group& eventGroup, 411 const std::vector<Action>& eventActions); 412 413 /** 414 * @brief Add a timer to the list of timer based events 415 * 416 * @param[in] group - Group associated with a timer 417 * @param[in] actions - List of actions associated with a timer 418 * @param[in] tConf - Configuration for the new timer 419 */ 420 void addTimer(const Group& group, 421 const std::vector<Action>& actions, 422 const TimerConf& tConf); 423 424 /** 425 * @brief Remove the given timer event 426 * 427 * @param[in] teIter - Iterator pointing to the timer event to remove 428 */ 429 inline void removeTimer(std::vector<TimerEvent>::iterator& teIter) 430 { 431 _timerEvents.erase(teIter); 432 } 433 434 /** 435 * @brief Callback function for event timers that processes the given 436 * actions for a group 437 * 438 * @param[in] eventGroup - Group to process actions on 439 * @param[in] eventActions - List of event actions to run 440 */ 441 void timerExpired(const Group& eventGroup, 442 const std::vector<Action>& eventActions); 443 444 /** 445 * @brief Get the service for a given path and interface from cached 446 * dataset and add a service that's not found 447 * 448 * @param[in] path - Path to get service for 449 * @param[in] intf - Interface to get service for 450 * 451 * @return - The service name 452 */ 453 const std::string& getService(const std::string& path, 454 const std::string& intf); 455 456 /** 457 * @brief Add a set of services for a path and interface 458 * by retrieving all the path subtrees to the given depth 459 * from root for the interface 460 * 461 * @param[in] path - Path to add services for 462 * @param[in] intf - Interface to add services for 463 * @param[in] depth - Depth of tree traversal from root path 464 * 465 * @return - The associated service to the given path and interface 466 * or empty string for no service found 467 */ 468 const std::string& addServices(const std::string& path, 469 const std::string& intf, 470 int32_t depth); 471 472 /** 473 * @brief Set a property to be persisted 474 * 475 * @param[in] intf - Interface containing property 476 * @param[in] prop - Property to be persisted 477 */ 478 inline void setPersisted(const std::string& intf, 479 const std::string& prop) 480 { 481 _persisted[intf].emplace_back(prop); 482 } 483 484 /** 485 * @brief Get persisted property 486 * 487 * @param[in] intf - Interface containing property 488 * @param[in] prop - Property persisted 489 * 490 * @return - True if property is to be persisted, false otherwise 491 */ 492 auto getPersisted(const std::string& intf, 493 const std::string& prop); 494 495 /** 496 * @brief Get a property value from the zone object or the bus when 497 * the property requested is not on the zone object 498 * 499 * @param[in] path - Path of object 500 * @param[in] intf - Object interface 501 * @param[in] prop - Object property 502 * 503 * @return - Property's value 504 */ 505 template <typename T> 506 auto getPropertyByName(const std::string& path, 507 const std::string& intf, 508 const std::string& prop) 509 { 510 T value; 511 auto pathIter = _objects.find(path); 512 if (pathIter != _objects.end()) 513 { 514 auto intfIter = pathIter->second.find(intf); 515 if (intfIter != pathIter->second.end()) 516 { 517 if (intf == "xyz.openbmc_project.Control.ThermalMode") 518 { 519 auto var = ThermalMode::getPropertyByName(prop); 520 // Use visitor to determine if requested property 521 // type(T) is available on this interface and read it 522 std::visit([&value](auto&& val) 523 { 524 using V = std::decay_t<decltype(val)>; 525 if constexpr(std::is_same_v<T, V>) 526 { 527 value = val; 528 } 529 }, var); 530 531 return value; 532 } 533 } 534 } 535 536 auto service = getService(path, intf); 537 value = util::SDBusPlus::getProperty<T>(_bus, 538 service, 539 path, 540 intf, 541 prop); 542 543 return value; 544 }; 545 546 /** 547 * @brief Overridden thermal object's set 'Current' property function 548 * 549 * @param[in] value - Value to set 'Current' to 550 * 551 * @return - The updated value of the 'Current' property 552 */ 553 virtual std::string current(std::string value); 554 555 private: 556 557 /** 558 * The dbus object 559 */ 560 sdbusplus::bus::bus& _bus; 561 562 /** 563 * Zone object path 564 */ 565 const std::string _path; 566 567 /** 568 * Zone supported interfaces 569 */ 570 const std::vector<std::string> _ifaces; 571 572 /** 573 * Full speed for the zone 574 */ 575 const uint64_t _fullSpeed; 576 577 /** 578 * The zone number 579 */ 580 const size_t _zoneNum; 581 582 /** 583 * The default floor speed for the zone 584 */ 585 const uint64_t _defFloorSpeed; 586 587 /** 588 * The default ceiling speed for the zone 589 */ 590 const uint64_t _defCeilingSpeed; 591 592 /** 593 * The floor speed to not go below 594 */ 595 uint64_t _floorSpeed = _defFloorSpeed; 596 597 /** 598 * The ceiling speed to not go above 599 */ 600 uint64_t _ceilingSpeed = _defCeilingSpeed; 601 602 /** 603 * The previous sensor value for calculating the ceiling 604 */ 605 int64_t _ceilingKeyValue = 0; 606 607 /** 608 * Automatic fan control active state 609 */ 610 bool _isActive = true; 611 612 /** 613 * Target speed for this zone 614 */ 615 uint64_t _targetSpeed = _fullSpeed; 616 617 /** 618 * Speed increase delta 619 */ 620 uint64_t _incSpeedDelta = 0; 621 622 /** 623 * Speed decrease delta 624 */ 625 uint64_t _decSpeedDelta = 0; 626 627 /** 628 * Requested speed base 629 */ 630 uint64_t _requestSpeedBase = 0; 631 632 /** 633 * Speed increase delay in seconds 634 */ 635 std::chrono::seconds _incDelay; 636 637 /** 638 * Speed decrease interval in seconds 639 */ 640 std::chrono::seconds _decInterval; 641 642 /** 643 * The increase timer object 644 */ 645 Timer _incTimer; 646 647 /** 648 * The decrease timer object 649 */ 650 Timer _decTimer; 651 652 /** 653 * Event loop used on set speed event timers 654 */ 655 sdeventplus::Event _eventLoop; 656 657 /** 658 * The vector of fans in this zone 659 */ 660 std::vector<std::unique_ptr<Fan>> _fans; 661 662 /** 663 * @brief Map of object property values 664 */ 665 std::map<std::string, 666 std::map<std::string, 667 std::map<std::string, 668 PropertyVariantType>>> _properties; 669 670 /** 671 * @brief Map of zone objects 672 */ 673 std::map<std::string, 674 std::map<std::string, 675 std::map<std::string, 676 EventData*>>> _objects; 677 678 /** 679 * @brief Map of interfaces to persisted properties 680 */ 681 std::map<std::string, std::vector<std::string>> _persisted; 682 683 /** 684 * @brief Map of active fan control allowed by groups 685 */ 686 std::map<const Group, bool> _active; 687 688 /** 689 * @brief Map of floor change allowed by groups 690 */ 691 std::map<const Group, bool> _floorChange; 692 693 /** 694 * @brief Map of groups controlling decreases allowed 695 */ 696 std::map<const Group, bool> _decAllowed; 697 698 /** 699 * @brief Map of group service names 700 */ 701 std::map<const Group, std::vector<Service>> _services; 702 703 /** 704 * @brief Map tree of paths to services of interfaces 705 */ 706 std::map<std::string, 707 std::map<std::string, 708 std::vector<std::string>>> _servTree; 709 710 /** 711 * @brief List of signal event arguments and Dbus matches for callbacks 712 */ 713 std::vector<SignalEvent> _signalEvents; 714 715 /** 716 * @brief List of timers for events 717 */ 718 std::vector<TimerEvent> _timerEvents; 719 720 /** 721 * @brief Save the thermal control current mode property 722 * to persisted storage 723 */ 724 void saveCurrentMode(); 725 726 /** 727 * @brief Restore persisted thermal control current mode property 728 * value, setting the mode to "Default" otherwise 729 */ 730 void restoreCurrentMode(); 731 732 /** 733 * @brief Get the request speed base if defined, otherwise the 734 * the current target speed is returned 735 * 736 * @return - The request speed base or current target speed 737 */ 738 inline auto getRequestSpeedBase() const 739 { 740 return (_requestSpeedBase != 0) ? _requestSpeedBase : _targetSpeed; 741 }; 742 743 /** 744 * @brief Dbus signal change callback handler 745 * 746 * @param[in] msg - Expanded sdbusplus message data 747 * @param[in] eventData - The single event's data 748 */ 749 void handleEvent(sdbusplus::message::message& msg, 750 const EventData* eventData); 751 }; 752 753 } 754 } 755 } 756