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