1 #pragma once
2 
3 #include "occ_pass_through.hpp"
4 #include "occ_status.hpp"
5 #ifdef PLDM
6 #include "pldm.hpp"
7 #endif
8 #include "powercap.hpp"
9 #include "utils.hpp"
10 
11 #include <cstring>
12 #include <functional>
13 #include <sdbusplus/bus.hpp>
14 #include <sdeventplus/event.hpp>
15 #include <sdeventplus/utility/timer.hpp>
16 #include <vector>
17 
18 namespace sdbusRule = sdbusplus::bus::match::rules;
19 namespace open_power
20 {
21 namespace occ
22 {
23 
24 /** @brief Default time, in seconds, between OCC poll commands */
25 constexpr unsigned int defaultPollingInterval = 10;
26 
27 /** @class Manager
28  *  @brief Builds and manages OCC objects
29  */
30 struct Manager
31 {
32   public:
33     Manager() = delete;
34     Manager(const Manager&) = delete;
35     Manager& operator=(const Manager&) = delete;
36     Manager(Manager&&) = delete;
37     Manager& operator=(Manager&&) = delete;
38     ~Manager() = default;
39 
40     /** @brief Adds OCC pass-through and status objects on the bus
41      *         when corresponding CPU inventory is created.
42      *
43      *  @param[in] event - Unique ptr reference to sd_event
44      */
45     Manager(EventPtr& event) :
46         event(event), pollInterval(defaultPollingInterval),
47         sdpEvent(sdeventplus::Event::get_default()),
48         _pollTimer(
49             std::make_unique<
50                 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>(
51                 sdpEvent, std::bind(&Manager::pollerTimerExpired, this)))
52 #ifdef PLDM
53         ,
54         pldmHandle(std::make_unique<pldm::Interface>(
55             std::bind(std::mem_fn(&Manager::updateOCCActive), this,
56                       std::placeholders::_1, std::placeholders::_2)))
57 #endif
58 
59     {
60 #ifdef I2C_OCC
61         // I2C OCC status objects are initialized directly
62         initStatusObjects();
63 #else
64         findAndCreateObjects();
65 #endif
66     }
67 
68     /** @brief Return the number of bound OCCs */
69     inline auto getNumOCCs() const
70     {
71         return activeCount;
72     }
73 
74   private:
75     /** @brief Checks if the CPU inventory is present and if so, creates
76      *         the occ D-Bus objects. Else, registers a handler to be
77      *         called when inventory is created.
78      */
79     void findAndCreateObjects();
80 
81     /** @brief Callback that responds to cpu creation in the inventory -
82      *         by creating the needed objects.
83      *
84      *  @param[in] msg - bus message
85      *
86      *  @returns 0 to indicate success
87      */
88     int cpuCreated(sdbusplus::message::message& msg);
89 
90     /** @brief Create child OCC objects.
91      *
92      *  @param[in] occ - the occ name, such as occ0.
93      */
94     void createObjects(const std::string& occ);
95 
96     /** @brief Callback handler invoked by Status object when the OccActive
97      *         property is changed. This is needed to make sure that the
98      *         error detection is started only after all the OCCs are bound.
99      *         Similarly, when one of the OCC gets its OccActive property
100      *         un-set, then the OCC error detection needs to be stopped on
101      *         all the OCCs
102      *
103      *  @param[in] status - OccActive status
104      */
105     void statusCallBack(bool status);
106 
107     /** @brief Sends a Heartbeat command to host control command handler */
108     void sendHeartBeat();
109 
110     /** @brief reference to sd_event wrapped in unique_ptr */
111     EventPtr& event;
112 
113     /** @brief OCC pass-through objects */
114     std::vector<std::unique_ptr<PassThrough>> passThroughObjects;
115 
116     /** @brief OCC Status objects */
117     std::vector<std::unique_ptr<Status>> statusObjects;
118 
119     /** @brief Power cap monitor and occ notification object */
120     std::unique_ptr<open_power::occ::powercap::PowerCap> pcap;
121 
122     /** @brief sbdbusplus match objects */
123     std::vector<sdbusplus::bus::match_t> cpuMatches;
124 
125     /** @brief Number of OCCs that are bound */
126     uint8_t activeCount = 0;
127 
128     /** @brief Number of seconds between poll commands */
129     uint8_t pollInterval;
130 
131     /** @brief Poll timer event */
132     sdeventplus::Event sdpEvent;
133 
134     /**
135      * @brief The timer to be used once the OCC goes active.  When it expires,
136      *        a POLL command will be sent to the OCC and then timer restarted.
137      */
138     std::unique_ptr<
139         sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
140         _pollTimer;
141 
142 #ifdef I2C_OCC
143     /** @brief Init Status objects for I2C OCC devices
144      *
145      * It iterates in /sys/bus/i2c/devices, finds all occ hwmon devices
146      * and creates status objects.
147      */
148     void initStatusObjects();
149 #endif
150 
151 #ifdef PLDM
152     /** @brief Callback handler invoked by the PLDM event handler when state of
153      *         the OCC is toggled by the host. The caller passes the instance
154      *         of the OCC and state of the OCC.
155      *
156      *  @param[in] instance - instance of the OCC
157      *  @param[in] status - true when the OCC goes active and false when the OCC
158      *                      goes inactive
159      *
160      *  @return true if setting the state of OCC is successful and false if it
161      *          fails.
162      */
163     bool updateOCCActive(instanceID instance, bool status);
164 
165     std::unique_ptr<pldm::Interface> pldmHandle = nullptr;
166 #endif
167 
168     /**
169      * @brief Called when poll timer expires and forces a POLL command to the
170      * OCC. The poll timer will then be restarted.
171      * */
172     void pollerTimerExpired();
173 };
174 
175 } // namespace occ
176 } // namespace open_power
177