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