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