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