xref: /openbmc/phosphor-fan-presence/control/zone.hpp (revision 79cb83120b2b4f23968d281905796ff2559cde8c)
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          *
444          * @return - Iterator to the timer event
445          */
446         std::vector<TimerEvent>::iterator findTimer(
447                 const Group& eventGroup,
448                 const std::vector<Action>& eventActions);
449 
450         /**
451          * @brief Add a timer to the list of timer based events
452          *
453          * @param[in] group - Group associated with a timer
454          * @param[in] actions - List of actions associated with a timer
455          * @param[in] tConf - Configuration for the new timer
456          */
457         void addTimer(const Group& group,
458                       const std::vector<Action>& actions,
459                       const TimerConf& tConf);
460 
461         /**
462          * @brief Remove the given timer event
463          *
464          * @param[in] teIter - Iterator pointing to the timer event to remove
465          */
466         inline void removeTimer(std::vector<TimerEvent>::iterator& teIter)
467         {
468             _timerEvents.erase(teIter);
469         }
470 
471         /**
472          * @brief Callback function for event timers that processes the given
473          * actions for a group
474          *
475          * @param[in] eventGroup - Group to process actions on
476          * @param[in] eventActions - List of event actions to run
477          */
478         void timerExpired(const Group& eventGroup,
479                           const std::vector<Action>& eventActions);
480 
481         /**
482          * @brief Get the service for a given path and interface from cached
483          * dataset and add a service that's not found
484          *
485          * @param[in] path - Path to get service for
486          * @param[in] intf - Interface to get service for
487          *
488          * @return - The service name
489          */
490         const std::string& getService(const std::string& path,
491                                       const std::string& intf);
492 
493         /**
494          * @brief Add a set of services for a path and interface
495          * by retrieving all the path subtrees to the given depth
496          * from root for the interface
497          *
498          * @param[in] path - Path to add services for
499          * @param[in] intf - Interface to add services for
500          * @param[in] depth - Depth of tree traversal from root path
501          *
502          * @return - The associated service to the given path and interface
503          * or empty string for no service found
504          */
505         const std::string& addServices(const std::string& path,
506                                        const std::string& intf,
507                                        int32_t depth);
508 
509         /**
510          * @brief Dbus signal change callback handler
511          *
512          * @param[in] msg - Expanded sdbusplus message data
513          * @param[in] eventData - The single event's data
514          */
515         void handleEvent(sdbusplus::message::message& msg,
516                          const EventData* eventData);
517 
518         /**
519          * @brief Add a signal to the list of signal based events
520          *
521          * @param[in] name - Event name
522          * @param[in] data - Event data for signal
523          * @param[in] match - Subscribed signal match
524          */
525         inline void addSignal(
526                 const std::string& name,
527                 std::unique_ptr<EventData>&& data,
528                 std::unique_ptr<sdbusplus::server::match::match>&& match)
529         {
530             _signalEvents[name].emplace_back(std::move(data), std::move(match));
531         }
532 
533         /**
534          * @brief Set a property to be persisted
535          *
536          * @param[in] intf - Interface containing property
537          * @param[in] prop - Property to be persisted
538          */
539         inline void setPersisted(const std::string& intf,
540                                  const std::string& prop)
541         {
542             _persisted[intf].emplace_back(prop);
543         }
544 
545         /**
546          * @brief Get persisted property
547          *
548          * @param[in] intf - Interface containing property
549          * @param[in] prop - Property persisted
550          *
551          * @return - True if property is to be persisted, false otherwise
552          */
553         auto getPersisted(const std::string& intf,
554                           const std::string& prop);
555 
556         /**
557          * @brief Get a property value from the zone object or the bus when
558          * the property requested is not on the zone object
559          *
560          * @param[in] path - Path of object
561          * @param[in] intf - Object interface
562          * @param[in] prop - Object property
563          *
564          * @return - Property's value
565          */
566         template <typename T>
567         auto getPropertyByName(const std::string& path,
568                                const std::string& intf,
569                                const std::string& prop)
570         {
571             T value;
572             auto pathIter = _objects.find(path);
573             if (pathIter != _objects.end())
574             {
575                 auto intfIter = pathIter->second.find(intf);
576                 if (intfIter != pathIter->second.end())
577                 {
578                     if (intf == "xyz.openbmc_project.Control.ThermalMode")
579                     {
580                         auto var = ThermalMode::getPropertyByName(prop);
581                         // Use visitor to determine if requested property
582                         // type(T) is available on this interface and read it
583                         std::visit([&value](auto&& val)
584                         {
585                             using V = std::decay_t<decltype(val)>;
586                             if constexpr(std::is_same_v<T, V>)
587                             {
588                                 value = val;
589                             }
590                         }, var);
591 
592                         return value;
593                     }
594                 }
595             }
596 
597             auto service = getService(path, intf);
598             value = util::SDBusPlus::getProperty<T>(_bus,
599                                                     service,
600                                                     path,
601                                                     intf,
602                                                     prop);
603 
604             return value;
605         };
606 
607         /**
608          * @brief Overridden thermal object's set 'Current' property function
609          *
610          * @param[in] value - Value to set 'Current' to
611          *
612          * @return - The updated value of the 'Current' property
613          */
614         virtual std::string current(std::string value);
615 
616     private:
617 
618         /**
619          * The dbus object
620          */
621         sdbusplus::bus::bus& _bus;
622 
623         /**
624          * Zone object path
625          */
626         const std::string _path;
627 
628         /**
629          * Zone supported interfaces
630          */
631         const std::vector<std::string> _ifaces;
632 
633         /**
634          * Full speed for the zone
635          */
636         const uint64_t _fullSpeed;
637 
638         /**
639          * The zone number
640          */
641         const size_t _zoneNum;
642 
643         /**
644          * The default floor speed for the zone
645          */
646         const uint64_t _defFloorSpeed;
647 
648         /**
649          * The default ceiling speed for the zone
650          */
651         const uint64_t _defCeilingSpeed;
652 
653         /**
654          * The floor speed to not go below
655          */
656         uint64_t _floorSpeed = _defFloorSpeed;
657 
658         /**
659          * The ceiling speed to not go above
660          */
661         uint64_t _ceilingSpeed = _defCeilingSpeed;
662 
663         /**
664          * The previous sensor value for calculating the ceiling
665          */
666         int64_t _ceilingKeyValue = 0;
667 
668         /**
669          * Automatic fan control active state
670          */
671         bool _isActive = true;
672 
673         /**
674          * Target speed for this zone
675          */
676         uint64_t _targetSpeed = _fullSpeed;
677 
678         /**
679          * Speed increase delta
680          */
681         uint64_t _incSpeedDelta = 0;
682 
683         /**
684          * Speed decrease delta
685          */
686         uint64_t _decSpeedDelta = 0;
687 
688         /**
689          * Requested speed base
690          */
691         uint64_t _requestSpeedBase = 0;
692 
693         /**
694          * Speed increase delay in seconds
695          */
696         std::chrono::seconds _incDelay;
697 
698         /**
699          * Speed decrease interval in seconds
700          */
701         std::chrono::seconds _decInterval;
702 
703         /**
704          * The increase timer object
705          */
706         Timer _incTimer;
707 
708         /**
709          * The decrease timer object
710          */
711         Timer _decTimer;
712 
713         /**
714          * Event loop used on set speed event timers
715          */
716         sdeventplus::Event _eventLoop;
717 
718         /**
719          * The vector of fans in this zone
720          */
721         std::vector<std::unique_ptr<Fan>> _fans;
722 
723         /**
724          * @brief Map of object property values
725          */
726         std::map<std::string,
727                  std::map<std::string,
728                           std::map<std::string,
729                                    PropertyVariantType>>> _properties;
730 
731         /**
732          * @brief Map of zone objects
733          */
734         std::map<std::string,
735                  std::map<std::string,
736                           std::map<std::string,
737                                    EventData*>>> _objects;
738 
739         /**
740          * @brief Map of interfaces to persisted properties
741          */
742         std::map<std::string, std::vector<std::string>> _persisted;
743 
744         /**
745          * @brief Map of active fan control allowed by groups
746          */
747         std::map<const Group, bool> _active;
748 
749         /**
750          * @brief Map of floor change allowed by groups
751          */
752         std::map<const Group, bool> _floorChange;
753 
754         /**
755          * @brief Map of groups controlling decreases allowed
756          */
757         std::map<const Group, bool> _decAllowed;
758 
759         /**
760          * @brief Map of group service names
761          */
762         std::map<const Group, std::vector<Service>> _services;
763 
764         /**
765          * @brief Map tree of paths to services of interfaces
766          */
767         std::map<std::string,
768                 std::map<std::string,
769                 std::vector<std::string>>> _servTree;
770 
771         /**
772          * @brief List of signal event arguments and Dbus matches
773          * for callbacks per event name
774          */
775         std::map<std::string, std::vector<SignalEvent>> _signalEvents;
776 
777         /**
778          * @brief List of timers for events
779          */
780         std::vector<TimerEvent> _timerEvents;
781 
782         /**
783          * @brief Save the thermal control current mode property
784          * to persisted storage
785          */
786         void saveCurrentMode();
787 
788         /**
789          * @brief Restore persisted thermal control current mode property
790          * value, setting the mode to "Default" otherwise
791          */
792         void restoreCurrentMode();
793 
794         /**
795          * @brief Get the request speed base if defined, otherwise the
796          * the current target speed is returned
797          *
798          * @return - The request speed base or current target speed
799          */
800         inline auto getRequestSpeedBase() const
801         {
802             return (_requestSpeedBase != 0) ? _requestSpeedBase : _targetSpeed;
803         };
804 };
805 
806 }
807 }
808 }
809