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