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 Get a property value from the zone object or the bus when 474 * the property requested is not on the zone object 475 * 476 * @param[in] path - Path of object 477 * @param[in] intf - Object interface 478 * @param[in] prop - Object property 479 * 480 * @return - Property's value 481 */ 482 template <typename T> 483 auto getPropertyByName(const std::string& path, 484 const std::string& intf, 485 const std::string& prop) 486 { 487 T value; 488 auto pathIter = _objects.find(path); 489 if (pathIter != _objects.end()) 490 { 491 auto intfIter = pathIter->second.find(intf); 492 if (intfIter != pathIter->second.end()) 493 { 494 if (intf == "xyz.openbmc_project.Control.ThermalMode") 495 { 496 auto var = ThermalMode::getPropertyByName(prop); 497 // Use visitor to determine if requested property 498 // type(T) is available on this interface and read it 499 std::visit([&value](auto&& val) 500 { 501 using V = std::decay_t<decltype(val)>; 502 if constexpr(std::is_same_v<T, V>) 503 { 504 value = val; 505 } 506 }, var); 507 508 return value; 509 } 510 } 511 } 512 513 auto service = getService(path, intf); 514 value = util::SDBusPlus::getProperty<T>(_bus, 515 service, 516 path, 517 intf, 518 prop); 519 520 return value; 521 }; 522 523 /** 524 * @brief Overridden thermal object's set 'Current' property function 525 * 526 * @param[in] value - Value to set 'Current' to 527 * 528 * @return - The updated value of the 'Current' property 529 */ 530 virtual std::string current(std::string value); 531 532 private: 533 534 /** 535 * The dbus object 536 */ 537 sdbusplus::bus::bus& _bus; 538 539 /** 540 * Zone object path 541 */ 542 const std::string _path; 543 544 /** 545 * Zone supported interfaces 546 */ 547 const std::vector<std::string> _ifaces; 548 549 /** 550 * Full speed for the zone 551 */ 552 const uint64_t _fullSpeed; 553 554 /** 555 * The zone number 556 */ 557 const size_t _zoneNum; 558 559 /** 560 * The default floor speed for the zone 561 */ 562 const uint64_t _defFloorSpeed; 563 564 /** 565 * The default ceiling speed for the zone 566 */ 567 const uint64_t _defCeilingSpeed; 568 569 /** 570 * The floor speed to not go below 571 */ 572 uint64_t _floorSpeed = _defFloorSpeed; 573 574 /** 575 * The ceiling speed to not go above 576 */ 577 uint64_t _ceilingSpeed = _defCeilingSpeed; 578 579 /** 580 * The previous sensor value for calculating the ceiling 581 */ 582 int64_t _ceilingKeyValue = 0; 583 584 /** 585 * Automatic fan control active state 586 */ 587 bool _isActive = true; 588 589 /** 590 * Target speed for this zone 591 */ 592 uint64_t _targetSpeed = _fullSpeed; 593 594 /** 595 * Speed increase delta 596 */ 597 uint64_t _incSpeedDelta = 0; 598 599 /** 600 * Speed decrease delta 601 */ 602 uint64_t _decSpeedDelta = 0; 603 604 /** 605 * Requested speed base 606 */ 607 uint64_t _requestSpeedBase = 0; 608 609 /** 610 * Speed increase delay in seconds 611 */ 612 std::chrono::seconds _incDelay; 613 614 /** 615 * Speed decrease interval in seconds 616 */ 617 std::chrono::seconds _decInterval; 618 619 /** 620 * The increase timer object 621 */ 622 Timer _incTimer; 623 624 /** 625 * The decrease timer object 626 */ 627 Timer _decTimer; 628 629 /** 630 * Event loop used on set speed event timers 631 */ 632 sdeventplus::Event _eventLoop; 633 634 /** 635 * The vector of fans in this zone 636 */ 637 std::vector<std::unique_ptr<Fan>> _fans; 638 639 /** 640 * @brief Map of object property values 641 */ 642 std::map<std::string, 643 std::map<std::string, 644 std::map<std::string, 645 PropertyVariantType>>> _properties; 646 647 /** 648 * @brief Map of zone objects 649 */ 650 std::map<std::string, 651 std::map<std::string, 652 std::map<std::string, 653 EventData*>>> _objects; 654 655 /** 656 * @brief Map of active fan control allowed by groups 657 */ 658 std::map<const Group, bool> _active; 659 660 /** 661 * @brief Map of floor change allowed by groups 662 */ 663 std::map<const Group, bool> _floorChange; 664 665 /** 666 * @brief Map of groups controlling decreases allowed 667 */ 668 std::map<const Group, bool> _decAllowed; 669 670 /** 671 * @brief Map of group service names 672 */ 673 std::map<const Group, std::vector<Service>> _services; 674 675 /** 676 * @brief Map tree of paths to services of interfaces 677 */ 678 std::map<std::string, 679 std::map<std::string, 680 std::vector<std::string>>> _servTree; 681 682 /** 683 * @brief List of signal event arguments and Dbus matches for callbacks 684 */ 685 std::vector<SignalEvent> _signalEvents; 686 687 /** 688 * @brief List of timers for events 689 */ 690 std::vector<TimerEvent> _timerEvents; 691 692 /** 693 * @brief Save the thermal control current mode property 694 * to persisted storage 695 */ 696 void saveCurrentMode(); 697 698 /** 699 * @brief Restore persisted thermal control current mode property 700 * value, setting the mode to "Default" otherwise 701 */ 702 void restoreCurrentMode(); 703 704 /** 705 * @brief Get the request speed base if defined, otherwise the 706 * the current target speed is returned 707 * 708 * @return - The request speed base or current target speed 709 */ 710 inline auto getRequestSpeedBase() const 711 { 712 return (_requestSpeedBase != 0) ? _requestSpeedBase : _targetSpeed; 713 }; 714 715 /** 716 * @brief Dbus signal change callback handler 717 * 718 * @param[in] msg - Expanded sdbusplus message data 719 * @param[in] eventData - The single event's data 720 */ 721 void handleEvent(sdbusplus::message::message& msg, 722 const EventData* eventData); 723 }; 724 725 } 726 } 727 } 728