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 Set the default floor
304          *
305          * @param[in] speed - Speed to set the default floor to
306          */
307         inline void setDefFloor(uint64_t speed)
308         {
309             _defFloorSpeed = speed;
310         };
311 
312         /**
313          * @brief Get the ceiling speed
314          *
315          * @return - The current ceiling speed
316          */
317         inline auto& getCeiling() const
318         {
319             return _ceilingSpeed;
320         };
321 
322         /**
323          * @brief Set the ceiling speed to the given speed
324          *
325          * @param[in] speed - Speed to set the ceiling to
326          */
327         inline void setCeiling(uint64_t speed)
328         {
329             _ceilingSpeed = speed;
330         };
331 
332         /**
333          * @brief Swaps the ceiling key value with what's given and
334          * returns the value that was swapped.
335          *
336          * @param[in] keyValue - New ceiling key value
337          *
338          * @return - Ceiling key value prior to swapping
339          */
340         inline auto swapCeilingKeyValue(int64_t keyValue)
341         {
342             std::swap(_ceilingKeyValue, keyValue);
343             return keyValue;
344         };
345 
346         /**
347          * @brief Get the increase speed delta
348          *
349          * @return - The current increase speed delta
350          */
351         inline auto& getIncSpeedDelta() const
352         {
353             return _incSpeedDelta;
354         };
355 
356         /**
357          * @brief Get the decrease speed delta
358          *
359          * @return - The current decrease speed delta
360          */
361         inline auto& getDecSpeedDelta() const
362         {
363             return _decSpeedDelta;
364         };
365 
366         /**
367          * @brief Set the floor speed to the given speed and increase target
368          * speed to the floor when target is below floor where floor changes
369          * are allowed.
370          *
371          * @param[in] speed - Speed to set the floor to
372          */
373         void setFloor(uint64_t speed);
374 
375         /**
376          * @brief Set the requested speed base to be used as the speed to
377          * base a new requested speed target from
378          *
379          * @param[in] speedBase - Base speed value to use
380          */
381         inline void setRequestSpeedBase(uint64_t speedBase)
382         {
383             _requestSpeedBase = speedBase;
384         };
385 
386         /**
387          * @brief Calculate the requested target speed from the given delta
388          * and increase the fan speeds, not going above the ceiling.
389          *
390          * @param[in] targetDelta - The delta to increase the target speed by
391          */
392         void requestSpeedIncrease(uint64_t targetDelta);
393 
394         /**
395          * @brief Calculate the requested target speed from the given delta
396          * and increase the fan speeds, not going above the ceiling.
397          *
398          * @param[in] targetDelta - The delta to increase the target speed by
399          */
400         void requestSpeedDecrease(uint64_t targetDelta);
401 
402         /**
403          * @brief Callback function for the increase timer that delays
404          * processing of requested speed increases while fans are increasing
405          */
406         void incTimerExpired();
407 
408         /**
409          * @brief Callback function for the decrease timer that processes any
410          * requested speed decreases if allowed
411          */
412         void decTimerExpired();
413 
414         /**
415          * @brief Get the event loop used with this zone's timers
416          *
417          * @return - The event loop for timers
418          */
419         inline auto& getEventLoop()
420         {
421             return _eventLoop;
422         }
423 
424         /**
425          * @brief Remove the given signal event
426          *
427          * @param[in] seIter - Iterator pointing to the signal event to remove
428          */
429         inline void removeSignal(std::vector<SignalEvent>::iterator& seIter)
430         {
431             std::get<signalEventDataPos>(*seIter).reset();
432             if (std::get<signalMatchPos>(*seIter) != nullptr)
433             {
434                 std::get<signalMatchPos>(*seIter).reset();
435             }
436         }
437 
438         /**
439          * @brief Get the list of timer events
440          *
441          * @return - List of timer events
442          */
443         inline auto& getTimerEvents()
444         {
445             return _timerEvents;
446         }
447 
448         /**
449          * @brief Find the first instance of a timer event
450          *
451          * @param[in] eventGroup - Group associated with a timer
452          * @param[in] eventActions - List of actions associated with a timer
453          * @param[in] eventTimers - List of timers to find the timer in
454          *
455          * @return - Iterator to the timer event
456          */
457         std::vector<TimerEvent>::iterator findTimer(
458                 const Group& eventGroup,
459                 const std::vector<Action>& eventActions,
460                 std::vector<TimerEvent>& eventTimers);
461 
462         /**
463          * @brief Add a timer to the list of timer based events
464          *
465          * @param[in] name - Event name associated with timer
466          * @param[in] group - Group associated with a timer
467          * @param[in] actions - List of actions associated with a timer
468          * @param[in] tConf - Configuration for the new timer
469          */
470         void addTimer(const std::string& name,
471                       const Group& group,
472                       const std::vector<Action>& actions,
473                       const TimerConf& tConf);
474 
475         /**
476          * @brief Callback function for event timers that processes the given
477          * actions for a group
478          *
479          * @param[in] eventGroup - Group to process actions on
480          * @param[in] eventActions - List of event actions to run
481          */
482         void timerExpired(const Group& eventGroup,
483                           const std::vector<Action>& eventActions);
484 
485         /**
486          * @brief Get the service for a given path and interface from cached
487          * dataset and add a service that's not found
488          *
489          * @param[in] path - Path to get service for
490          * @param[in] intf - Interface to get service for
491          *
492          * @return - The service name
493          */
494         const std::string& getService(const std::string& path,
495                                       const std::string& intf);
496 
497         /**
498          * @brief Add a set of services for a path and interface
499          * by retrieving all the path subtrees to the given depth
500          * from root for the interface
501          *
502          * @param[in] path - Path to add services for
503          * @param[in] intf - Interface to add services for
504          * @param[in] depth - Depth of tree traversal from root path
505          *
506          * @return - The associated service to the given path and interface
507          * or empty string for no service found
508          */
509         const std::string& addServices(const std::string& path,
510                                        const std::string& intf,
511                                        int32_t depth);
512 
513         /**
514          * @brief Dbus signal change callback handler
515          *
516          * @param[in] msg - Expanded sdbusplus message data
517          * @param[in] eventData - The single event's data
518          */
519         void handleEvent(sdbusplus::message::message& msg,
520                          const EventData* eventData);
521 
522         /**
523          * @brief Add a signal to the list of signal based events
524          *
525          * @param[in] name - Event name
526          * @param[in] data - Event data for signal
527          * @param[in] match - Subscribed signal match
528          */
529         inline void addSignal(
530                 const std::string& name,
531                 std::unique_ptr<EventData>&& data,
532                 std::unique_ptr<sdbusplus::server::match::match>&& match)
533         {
534             _signalEvents[name].emplace_back(std::move(data), std::move(match));
535         }
536 
537         /**
538          * @brief Set a property to be persisted
539          *
540          * @param[in] intf - Interface containing property
541          * @param[in] prop - Property to be persisted
542          */
543         inline void setPersisted(const std::string& intf,
544                                  const std::string& prop)
545         {
546             _persisted[intf].emplace_back(prop);
547         }
548 
549         /**
550          * @brief Get persisted property
551          *
552          * @param[in] intf - Interface containing property
553          * @param[in] prop - Property persisted
554          *
555          * @return - True if property is to be persisted, false otherwise
556          */
557         auto getPersisted(const std::string& intf,
558                           const std::string& prop);
559 
560         /**
561          * @brief Get a property value from the zone object or the bus when
562          * the property requested is not on the zone object
563          *
564          * @param[in] path - Path of object
565          * @param[in] intf - Object interface
566          * @param[in] prop - Object property
567          *
568          * @return - Property's value
569          */
570         template <typename T>
571         auto getPropertyByName(const std::string& path,
572                                const std::string& intf,
573                                const std::string& prop)
574         {
575             T value;
576             auto pathIter = _objects.find(path);
577             if (pathIter != _objects.end())
578             {
579                 auto intfIter = pathIter->second.find(intf);
580                 if (intfIter != pathIter->second.end())
581                 {
582                     if (intf == "xyz.openbmc_project.Control.ThermalMode")
583                     {
584                         auto var = ThermalMode::getPropertyByName(prop);
585                         // Use visitor to determine if requested property
586                         // type(T) is available on this interface and read it
587                         std::visit([&value](auto&& val)
588                         {
589                             using V = std::decay_t<decltype(val)>;
590                             if constexpr(std::is_same_v<T, V>)
591                             {
592                                 value = val;
593                             }
594                         }, var);
595 
596                         return value;
597                     }
598                 }
599             }
600 
601             auto service = getService(path, intf);
602             value = util::SDBusPlus::getProperty<T>(_bus,
603                                                     service,
604                                                     path,
605                                                     intf,
606                                                     prop);
607 
608             return value;
609         };
610 
611         /**
612          * @brief Overridden thermal object's set 'Current' property function
613          *
614          * @param[in] value - Value to set 'Current' to
615          *
616          * @return - The updated value of the 'Current' property
617          */
618         virtual std::string current(std::string value);
619 
620     private:
621 
622         /**
623          * The dbus object
624          */
625         sdbusplus::bus::bus& _bus;
626 
627         /**
628          * Zone object path
629          */
630         const std::string _path;
631 
632         /**
633          * Zone supported interfaces
634          */
635         const std::vector<std::string> _ifaces;
636 
637         /**
638          * Full speed for the zone
639          */
640         const uint64_t _fullSpeed;
641 
642         /**
643          * The zone number
644          */
645         const size_t _zoneNum;
646 
647         /**
648          * The default floor speed for the zone
649          */
650         uint64_t _defFloorSpeed;
651 
652         /**
653          * The default ceiling speed for the zone
654          */
655         const uint64_t _defCeilingSpeed;
656 
657         /**
658          * The floor speed to not go below
659          */
660         uint64_t _floorSpeed = _defFloorSpeed;
661 
662         /**
663          * The ceiling speed to not go above
664          */
665         uint64_t _ceilingSpeed = _defCeilingSpeed;
666 
667         /**
668          * The previous sensor value for calculating the ceiling
669          */
670         int64_t _ceilingKeyValue = 0;
671 
672         /**
673          * Automatic fan control active state
674          */
675         bool _isActive = true;
676 
677         /**
678          * Target speed for this zone
679          */
680         uint64_t _targetSpeed = _fullSpeed;
681 
682         /**
683          * Speed increase delta
684          */
685         uint64_t _incSpeedDelta = 0;
686 
687         /**
688          * Speed decrease delta
689          */
690         uint64_t _decSpeedDelta = 0;
691 
692         /**
693          * Requested speed base
694          */
695         uint64_t _requestSpeedBase = 0;
696 
697         /**
698          * Speed increase delay in seconds
699          */
700         std::chrono::seconds _incDelay;
701 
702         /**
703          * Speed decrease interval in seconds
704          */
705         std::chrono::seconds _decInterval;
706 
707         /**
708          * The increase timer object
709          */
710         Timer _incTimer;
711 
712         /**
713          * The decrease timer object
714          */
715         Timer _decTimer;
716 
717         /**
718          * Event loop used on set speed event timers
719          */
720         sdeventplus::Event _eventLoop;
721 
722         /**
723          * The vector of fans in this zone
724          */
725         std::vector<std::unique_ptr<Fan>> _fans;
726 
727         /**
728          * @brief Map of object property values
729          */
730         std::map<std::string,
731                  std::map<std::string,
732                           std::map<std::string,
733                                    PropertyVariantType>>> _properties;
734 
735         /**
736          * @brief Map of zone objects
737          */
738         std::map<std::string,
739                  std::map<std::string,
740                           std::map<std::string,
741                                    EventData*>>> _objects;
742 
743         /**
744          * @brief Map of interfaces to persisted properties
745          */
746         std::map<std::string, std::vector<std::string>> _persisted;
747 
748         /**
749          * @brief Map of active fan control allowed by groups
750          */
751         std::map<const Group, bool> _active;
752 
753         /**
754          * @brief Map of floor change allowed by groups
755          */
756         std::map<const Group, bool> _floorChange;
757 
758         /**
759          * @brief Map of groups controlling decreases allowed
760          */
761         std::map<const Group, bool> _decAllowed;
762 
763         /**
764          * @brief Map of group service names
765          */
766         std::map<const Group, std::vector<Service>> _services;
767 
768         /**
769          * @brief Map tree of paths to services of interfaces
770          */
771         std::map<std::string,
772                 std::map<std::string,
773                 std::vector<std::string>>> _servTree;
774 
775         /**
776          * @brief List of signal event arguments and Dbus matches
777          * for callbacks per event name
778          */
779         std::map<std::string, std::vector<SignalEvent>> _signalEvents;
780 
781         /**
782          * @brief List of timers per event name
783          */
784         std::map<std::string, std::vector<TimerEvent>> _timerEvents;
785 
786         /**
787          * @brief Save the thermal control current mode property
788          * to persisted storage
789          */
790         void saveCurrentMode();
791 
792         /**
793          * @brief Restore persisted thermal control current mode property
794          * value, setting the mode to "Default" otherwise
795          */
796         void restoreCurrentMode();
797 
798         /**
799          * @brief Get the request speed base if defined, otherwise the
800          * the current target speed is returned
801          *
802          * @return - The request speed base or current target speed
803          */
804         inline auto getRequestSpeedBase() const
805         {
806             return (_requestSpeedBase != 0) ? _requestSpeedBase : _targetSpeed;
807         };
808 };
809 
810 }
811 }
812 }
813