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