xref: /openbmc/phosphor-fan-presence/control/zone.hpp (revision cc8912e93eb55e938b5cdb189a70d1f342fb49ea)
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