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 
10 #include <cstring>
11 #include <functional>
12 #include <sdbusplus/bus.hpp>
13 #include <sdeventplus/event.hpp>
14 #include <sdeventplus/utility/timer.hpp>
15 #include <vector>
16 
17 namespace sdbusRule = sdbusplus::bus::match::rules;
18 namespace open_power
19 {
20 namespace occ
21 {
22 
23 /** @brief Default time, in seconds, between OCC poll commands */
24 constexpr unsigned int defaultPollingInterval = 10;
25 
26 /** @class Manager
27  *  @brief Builds and manages OCC objects
28  */
29 struct Manager
30 {
31   public:
32     Manager() = delete;
33     Manager(const Manager&) = delete;
34     Manager& operator=(const Manager&) = delete;
35     Manager(Manager&&) = delete;
36     Manager& operator=(Manager&&) = delete;
37     ~Manager() = default;
38 
39     /** @brief Adds OCC pass-through and status objects on the bus
40      *         when corresponding CPU inventory is created.
41      *
42      *  @param[in] bus   - handle to the bus
43      *  @param[in] event - Unique ptr reference to sd_event
44      */
45     Manager(sdbusplus::bus::bus& bus, EventPtr& event) :
46         bus(bus), 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             bus, 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 the bus */
111     sdbusplus::bus::bus& bus;
112 
113     /** @brief reference to sd_event wrapped in unique_ptr */
114     EventPtr& event;
115 
116     /** @brief OCC pass-through objects */
117     std::vector<std::unique_ptr<PassThrough>> passThroughObjects;
118 
119     /** @brief OCC Status objects */
120     std::vector<std::unique_ptr<Status>> statusObjects;
121 
122     /** @brief Power cap monitor and occ notification object */
123     std::unique_ptr<open_power::occ::powercap::PowerCap> pcap;
124 
125     /** @brief sbdbusplus match objects */
126     std::vector<sdbusplus::bus::match_t> cpuMatches;
127 
128     /** @brief Number of OCCs that are bound */
129     uint8_t activeCount = 0;
130 
131     /** @brief Number of seconds between poll commands */
132     uint8_t pollInterval;
133 
134     /** @brief Poll timer event */
135     sdeventplus::Event sdpEvent;
136 
137     /**
138      * @brief The timer to be used once the OCC goes active.  When it expires,
139      *        a POLL command will be sent to the OCC and then timer restarted.
140      */
141     std::unique_ptr<
142         sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
143         _pollTimer;
144 
145 #ifdef I2C_OCC
146     /** @brief Init Status objects for I2C OCC devices
147      *
148      * It iterates in /sys/bus/i2c/devices, finds all occ hwmon devices
149      * and creates status objects.
150      */
151     void initStatusObjects();
152 #endif
153 
154 #ifdef PLDM
155     /** @brief Callback handler invoked by the PLDM event handler when state of
156      *         the OCC is toggled by the host. The caller passes the instance
157      *         of the OCC and state of the OCC.
158      *
159      *  @param[in] instance - instance of the OCC
160      *  @param[in] status - true when the OCC goes active and false when the OCC
161      *                      goes inactive
162      *
163      *  @return true if setting the state of OCC is successful and false if it
164      *          fails.
165      */
166     bool updateOCCActive(instanceID instance, bool status);
167 
168     std::unique_ptr<pldm::Interface> pldmHandle = nullptr;
169 #endif
170 
171     /**
172      * @brief Called when poll timer expires and forces a POLL command to the
173      * OCC. The poll timer will then be restarted.
174      * */
175     void pollerTimerExpired();
176 };
177 
178 } // namespace occ
179 } // namespace open_power
180