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 "xyz/openbmc_project/Control/ThermalMode/server.hpp" 11 12 namespace phosphor 13 { 14 namespace fan 15 { 16 namespace control 17 { 18 19 using ThermalObject = sdbusplus::server::object::object< 20 sdbusplus::xyz::openbmc_project::Control::server::ThermalMode>; 21 22 /** 23 * The mode fan control will run in: 24 * - init - only do the initialization steps 25 * - control - run normal control algorithms 26 */ 27 enum class Mode 28 { 29 init, 30 control 31 }; 32 33 /** 34 * @class Represents a fan control zone, which is a group of fans 35 * that behave the same. 36 */ 37 class Zone : public ThermalObject 38 { 39 public: 40 41 Zone() = delete; 42 Zone(const Zone&) = delete; 43 Zone(Zone&&) = delete; 44 Zone& operator=(const Zone&) = delete; 45 Zone& operator=(Zone&&) = delete; 46 ~Zone() = default; 47 48 /** 49 * Constructor 50 * Creates the appropriate fan objects based on 51 * the zone definition data passed in. 52 * 53 * @param[in] mode - mode of fan control 54 * @param[in] bus - the dbus object 55 * @param[in] path - object instance path 56 * @param[in] event - Event loop reference 57 * @param[in] def - the fan zone definition data 58 */ 59 Zone(Mode mode, 60 sdbusplus::bus::bus& bus, 61 const std::string& path, 62 const sdeventplus::Event& event, 63 const ZoneDefinition& def); 64 65 /** 66 * Sets all fans in the zone to the speed 67 * passed in when the zone is active 68 * 69 * @param[in] speed - the fan speed 70 */ 71 void setSpeed(uint64_t speed); 72 73 /** 74 * Sets the zone to full speed regardless of zone's active state 75 */ 76 void setFullSpeed(); 77 78 /** 79 * @brief Sets the automatic fan control allowed active state 80 * 81 * @param[in] group - A group that affects the active state 82 * @param[in] isActiveAllow - Active state according to group 83 */ 84 void setActiveAllow(const Group* group, bool isActiveAllow); 85 86 /** 87 * @brief Sets the floor change allowed state 88 * 89 * @param[in] group - A group that affects floor changes 90 * @param[in] isAllow - Allow state according to group 91 */ 92 inline void setFloorChangeAllow(const Group* group, bool isAllow) 93 { 94 _floorChange[*(group)] = isAllow; 95 } 96 97 /** 98 * @brief Sets the decrease allowed state of a group 99 * 100 * @param[in] group - A group that affects speed decreases 101 * @param[in] isAllow - Allow state according to group 102 */ 103 inline void setDecreaseAllow(const Group* group, bool isAllow) 104 { 105 _decAllowed[*(group)] = isAllow; 106 } 107 108 /** 109 * @brief Sets a given object's property value 110 * 111 * @param[in] object - Name of the object containing the property 112 * @param[in] interface - Interface name containing the property 113 * @param[in] property - Property name 114 * @param[in] value - Property value 115 */ 116 template <typename T> 117 void setPropertyValue(const char* object, 118 const char* interface, 119 const char* property, 120 T value) 121 { 122 _properties[object][interface][property] = value; 123 }; 124 125 /** 126 * @brief Get the value of an object's property 127 * 128 * @param[in] object - Name of the object containing the property 129 * @param[in] interface - Interface name containing the property 130 * @param[in] property - Property name 131 * 132 * @return - The property value 133 */ 134 template <typename T> 135 inline auto getPropertyValue(const std::string& object, 136 const std::string& interface, 137 const std::string& property) 138 { 139 return sdbusplus::message::variant_ns::get<T>( 140 _properties.at(object).at(interface).at(property)); 141 }; 142 143 /** 144 * @brief Get the object's property variant 145 * 146 * @param[in] object - Name of the object containing the property 147 * @param[in] interface - Interface name containing the property 148 * @param[in] property - Property name 149 * 150 * @return - The property variant 151 */ 152 inline auto getPropValueVariant(const std::string& object, 153 const std::string& interface, 154 const std::string& property) 155 { 156 return _properties.at(object).at(interface).at(property); 157 }; 158 159 /** 160 * @brief Remove an object's interface 161 * 162 * @param[in] object - Name of the object with the interface 163 * @param[in] interface - Interface name to remove 164 */ 165 inline void removeObjectInterface(const char* object, 166 const char* interface) 167 { 168 auto it = _properties.find(object); 169 if (it != std::end(_properties)) 170 { 171 _properties[object].erase(interface); 172 } 173 } 174 175 /** 176 * @brief Remove a service associated to a group 177 * 178 * @param[in] group - Group associated with service 179 * @param[in] name - Service name to remove 180 */ 181 void removeService(const Group* group, 182 const std::string& name); 183 184 /** 185 * @brief Set or update a service name owner in use 186 * 187 * @param[in] group - Group associated with service 188 * @param[in] name - Service name 189 * @param[in] hasOwner - Whether the service is owned or not 190 */ 191 void setServiceOwner(const Group* group, 192 const std::string& name, 193 const bool hasOwner); 194 195 /** 196 * @brief Set or update all services for a group 197 * 198 * @param[in] group - Group to get service names for 199 */ 200 void setServices(const Group* group); 201 202 /** 203 * @brief Get the group's list of service names 204 * 205 * @param[in] group - Group to get service names for 206 * 207 * @return - The list of service names 208 */ 209 inline auto getGroupServices(const Group* group) 210 { 211 return _services.at(*group); 212 } 213 214 /** 215 * @brief Initialize a set speed event properties and actions 216 * 217 * @param[in] event - Set speed event 218 */ 219 void initEvent(const SetSpeedEvent& event); 220 221 /** 222 * @brief Removes all the set speed event properties and actions 223 * 224 * @param[in] event - Set speed event 225 */ 226 void removeEvent(const SetSpeedEvent& event); 227 228 /** 229 * @brief Get the default floor speed 230 * 231 * @return - The defined default floor speed 232 */ 233 inline auto getDefFloor() 234 { 235 return _defFloorSpeed; 236 }; 237 238 /** 239 * @brief Get the ceiling speed 240 * 241 * @return - The current ceiling speed 242 */ 243 inline auto& getCeiling() const 244 { 245 return _ceilingSpeed; 246 }; 247 248 /** 249 * @brief Set the ceiling speed to the given speed 250 * 251 * @param[in] speed - Speed to set the ceiling to 252 */ 253 inline void setCeiling(uint64_t speed) 254 { 255 _ceilingSpeed = speed; 256 }; 257 258 /** 259 * @brief Swaps the ceiling key value with what's given and 260 * returns the value that was swapped. 261 * 262 * @param[in] keyValue - New ceiling key value 263 * 264 * @return - Ceiling key value prior to swapping 265 */ 266 inline auto swapCeilingKeyValue(int64_t keyValue) 267 { 268 std::swap(_ceilingKeyValue, keyValue); 269 return keyValue; 270 }; 271 272 /** 273 * @brief Get the increase speed delta 274 * 275 * @return - The current increase speed delta 276 */ 277 inline auto& getIncSpeedDelta() const 278 { 279 return _incSpeedDelta; 280 }; 281 282 /** 283 * @brief Get the decrease speed delta 284 * 285 * @return - The current decrease speed delta 286 */ 287 inline auto& getDecSpeedDelta() const 288 { 289 return _decSpeedDelta; 290 }; 291 292 /** 293 * @brief Set the floor speed to the given speed and increase target 294 * speed to the floor when target is below floor where floor changes 295 * are allowed. 296 * 297 * @param[in] speed - Speed to set the floor to 298 */ 299 void setFloor(uint64_t speed); 300 301 /** 302 * @brief Set the requested speed base to be used as the speed to 303 * base a new requested speed target from 304 * 305 * @param[in] speedBase - Base speed value to use 306 */ 307 inline void setRequestSpeedBase(uint64_t speedBase) 308 { 309 _requestSpeedBase = speedBase; 310 }; 311 312 /** 313 * @brief Calculate the requested target speed from the given delta 314 * and increase the fan speeds, not going above the ceiling. 315 * 316 * @param[in] targetDelta - The delta to increase the target speed by 317 */ 318 void requestSpeedIncrease(uint64_t targetDelta); 319 320 /** 321 * @brief Calculate the requested target speed from the given delta 322 * and increase the fan speeds, not going above the ceiling. 323 * 324 * @param[in] targetDelta - The delta to increase the target speed by 325 */ 326 void requestSpeedDecrease(uint64_t targetDelta); 327 328 /** 329 * @brief Callback function for the increase timer that delays 330 * processing of requested speed increases while fans are increasing 331 */ 332 void incTimerExpired(); 333 334 /** 335 * @brief Callback function for the decrease timer that processes any 336 * requested speed decreases if allowed 337 */ 338 void decTimerExpired(); 339 340 /** 341 * @brief Get the event loop used with this zone's timers 342 * 343 * @return - The event loop for timers 344 */ 345 inline auto& getEventLoop() 346 { 347 return _eventLoop; 348 } 349 350 /** 351 * @brief Get the list of signal events 352 * 353 * @return - List of signal events 354 */ 355 inline auto& getSignalEvents() 356 { 357 return _signalEvents; 358 } 359 360 /** 361 * @brief Find the first instance of a signal event 362 * 363 * @param[in] signal - Event signal to find 364 * @param[in] eGroup - Group associated with the signal 365 * @param[in] eActions - List of actions associated with the signal 366 * 367 * @return - Iterator to the stored signal event 368 */ 369 std::vector<SignalEvent>::iterator findSignal( 370 const Signal& signal, 371 const Group& eGroup, 372 const std::vector<Action>& eActions); 373 374 /** 375 * @brief Remove the given signal event 376 * 377 * @param[in] seIter - Iterator pointing to the signal event to remove 378 */ 379 inline void removeSignal(std::vector<SignalEvent>::iterator& seIter) 380 { 381 assert(seIter != std::end(_signalEvents)); 382 std::get<signalEventDataPos>(*seIter).reset(); 383 if (std::get<signalMatchPos>(*seIter) != nullptr) 384 { 385 std::get<signalMatchPos>(*seIter).reset(); 386 } 387 _signalEvents.erase(seIter); 388 } 389 390 /** 391 * @brief Get the list of timer events 392 * 393 * @return - List of timer events 394 */ 395 inline auto& getTimerEvents() 396 { 397 return _timerEvents; 398 } 399 400 /** 401 * @brief Find the first instance of a timer event 402 * 403 * @param[in] eventGroup - Group associated with a timer 404 * @param[in] eventActions - List of actions associated with a timer 405 * 406 * @return - Iterator to the timer event 407 */ 408 std::vector<TimerEvent>::iterator findTimer( 409 const Group& eventGroup, 410 const std::vector<Action>& eventActions); 411 412 /** 413 * @brief Add a timer to the list of timer based events 414 * 415 * @param[in] group - Group associated with a timer 416 * @param[in] actions - List of actions associated with a timer 417 * @param[in] tConf - Configuration for the new timer 418 */ 419 void addTimer(const Group& group, 420 const std::vector<Action>& actions, 421 const TimerConf& tConf); 422 423 /** 424 * @brief Remove the given timer event 425 * 426 * @param[in] teIter - Iterator pointing to the timer event to remove 427 */ 428 inline void removeTimer(std::vector<TimerEvent>::iterator& teIter) 429 { 430 _timerEvents.erase(teIter); 431 } 432 433 /** 434 * @brief Callback function for event timers that processes the given 435 * actions for a group 436 * 437 * @param[in] eventGroup - Group to process actions on 438 * @param[in] eventActions - List of event actions to run 439 */ 440 void timerExpired(const Group& eventGroup, 441 const std::vector<Action>& eventActions); 442 443 /** 444 * @brief Get the service for a given path and interface from cached 445 * dataset and add a service that's not found 446 * 447 * @param[in] path - Path to get service for 448 * @param[in] intf - Interface to get service for 449 * 450 * @return - The service name 451 */ 452 const std::string& getService(const std::string& path, 453 const std::string& intf); 454 455 /** 456 * @brief Add a set of services for a path and interface 457 * by retrieving all the path subtrees to the given depth 458 * from root for the interface 459 * 460 * @param[in] path - Path to add services for 461 * @param[in] intf - Interface to add services for 462 * @param[in] depth - Depth of tree traversal from root path 463 * 464 * @return - The associated service to the given path and interface 465 * or empty string for no service found 466 */ 467 const std::string& addServices(const std::string& path, 468 const std::string& intf, 469 int32_t depth); 470 471 private: 472 473 /** 474 * The dbus object 475 */ 476 sdbusplus::bus::bus& _bus; 477 478 /** 479 * Zone object path 480 */ 481 const std::string _path; 482 483 /** 484 * Full speed for the zone 485 */ 486 const uint64_t _fullSpeed; 487 488 /** 489 * The zone number 490 */ 491 const size_t _zoneNum; 492 493 /** 494 * The default floor speed for the zone 495 */ 496 const uint64_t _defFloorSpeed; 497 498 /** 499 * The default ceiling speed for the zone 500 */ 501 const uint64_t _defCeilingSpeed; 502 503 /** 504 * The floor speed to not go below 505 */ 506 uint64_t _floorSpeed = _defFloorSpeed; 507 508 /** 509 * The ceiling speed to not go above 510 */ 511 uint64_t _ceilingSpeed = _defCeilingSpeed; 512 513 /** 514 * The previous sensor value for calculating the ceiling 515 */ 516 int64_t _ceilingKeyValue = 0; 517 518 /** 519 * Automatic fan control active state 520 */ 521 bool _isActive = true; 522 523 /** 524 * Target speed for this zone 525 */ 526 uint64_t _targetSpeed = _fullSpeed; 527 528 /** 529 * Speed increase delta 530 */ 531 uint64_t _incSpeedDelta = 0; 532 533 /** 534 * Speed decrease delta 535 */ 536 uint64_t _decSpeedDelta = 0; 537 538 /** 539 * Requested speed base 540 */ 541 uint64_t _requestSpeedBase = 0; 542 543 /** 544 * Speed increase delay in seconds 545 */ 546 std::chrono::seconds _incDelay; 547 548 /** 549 * Speed decrease interval in seconds 550 */ 551 std::chrono::seconds _decInterval; 552 553 /** 554 * The increase timer object 555 */ 556 Timer _incTimer; 557 558 /** 559 * The decrease timer object 560 */ 561 Timer _decTimer; 562 563 /** 564 * Event loop used on set speed event timers 565 */ 566 sdeventplus::Event _eventLoop; 567 568 /** 569 * The vector of fans in this zone 570 */ 571 std::vector<std::unique_ptr<Fan>> _fans; 572 573 /** 574 * @brief Map of object property values 575 */ 576 std::map<std::string, 577 std::map<std::string, 578 std::map<std::string, 579 PropertyVariantType>>> _properties; 580 581 /** 582 * @brief Map of active fan control allowed by groups 583 */ 584 std::map<const Group, bool> _active; 585 586 /** 587 * @brief Map of floor change allowed by groups 588 */ 589 std::map<const Group, bool> _floorChange; 590 591 /** 592 * @brief Map of groups controlling decreases allowed 593 */ 594 std::map<const Group, bool> _decAllowed; 595 596 /** 597 * @brief Map of group service names 598 */ 599 std::map<const Group, std::vector<Service>> _services; 600 601 /** 602 * @brief Map tree of paths to services of interfaces 603 */ 604 std::map<std::string, 605 std::map<std::string, 606 std::vector<std::string>>> _servTree; 607 608 /** 609 * @brief List of signal event arguments and Dbus matches for callbacks 610 */ 611 std::vector<SignalEvent> _signalEvents; 612 613 /** 614 * @brief List of timers for events 615 */ 616 std::vector<TimerEvent> _timerEvents; 617 618 /** 619 * @brief Save the thermal control current mode property 620 * to persisted storage 621 */ 622 void saveCurrentMode(); 623 624 /** 625 * @brief Get the request speed base if defined, otherwise the 626 * the current target speed is returned 627 * 628 * @return - The request speed base or current target speed 629 */ 630 inline auto getRequestSpeedBase() const 631 { 632 return (_requestSpeedBase != 0) ? _requestSpeedBase : _targetSpeed; 633 }; 634 635 /** 636 * @brief Dbus signal change callback handler 637 * 638 * @param[in] msg - Expanded sdbusplus message data 639 * @param[in] eventData - The single event's data 640 */ 641 void handleEvent(sdbusplus::message::message& msg, 642 const EventData* eventData); 643 }; 644 645 } 646 } 647 } 648