1 #pragma once
2 
3 #include "occ_pass_through.hpp"
4 #include "occ_status.hpp"
5 #ifdef PLDM
6 #include "pldm.hpp"
7 
8 #include <libphal.H>
9 #endif
10 #include "powercap.hpp"
11 #include "utils.hpp"
12 #ifdef POWER10
13 #include "powermode.hpp"
14 #endif
15 
16 #include <sdbusplus/bus.hpp>
17 #include <sdeventplus/event.hpp>
18 #include <sdeventplus/utility/timer.hpp>
19 
20 #include <cstring>
21 #include <functional>
22 #include <vector>
23 
24 namespace sdbusRule = sdbusplus::bus::match::rules;
25 namespace open_power
26 {
27 namespace occ
28 {
29 
30 #ifdef READ_OCC_SENSORS
31 enum occFruType
32 {
33     processorCore = 0,
34     internalMemCtlr = 1,
35     dimm = 2,
36     memCtrlAndDimm = 3,
37     VRMVdd = 6,
38     PMIC = 7,
39     memCtlrExSensor = 8,
40     processorIoRing = 9
41 };
42 #endif
43 
44 /** @brief Default time, in seconds, between OCC poll commands */
45 #ifndef POWER10
46 constexpr unsigned int defaultPollingInterval = 1;
47 #else
48 constexpr unsigned int defaultPollingInterval = 5;
49 #endif
50 
51 constexpr auto AMBIENT_PATH =
52     "/xyz/openbmc_project/sensors/temperature/Ambient_Virtual_Temp";
53 constexpr auto AMBIENT_INTERFACE = "xyz.openbmc_project.Sensor.Value";
54 constexpr auto AMBIENT_PROP = "Value";
55 constexpr auto ALTITUDE_PATH = "/xyz/openbmc_project/sensors/altitude/Altitude";
56 constexpr auto ALTITUDE_INTERFACE = "xyz.openbmc_project.Sensor.Value";
57 constexpr auto ALTITUDE_PROP = "Value";
58 
59 /** @class Manager
60  *  @brief Builds and manages OCC objects
61  */
62 struct Manager
63 {
64   public:
65     Manager() = delete;
66     Manager(const Manager&) = delete;
67     Manager& operator=(const Manager&) = delete;
68     Manager(Manager&&) = delete;
69     Manager& operator=(Manager&&) = delete;
70     ~Manager() = default;
71 
72     /** @brief Adds OCC pass-through and status objects on the bus
73      *         when corresponding CPU inventory is created.
74      *
75      *  @param[in] event - Unique ptr reference to sd_event
76      */
77     Manager(EventPtr& event) :
78         event(event), pollInterval(defaultPollingInterval),
79         sdpEvent(sdeventplus::Event::get_default()),
80         _pollTimer(
81             std::make_unique<
82                 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>(
83                 sdpEvent, std::bind(&Manager::pollerTimerExpired, this))),
84         ambientPropChanged(
85             utils::getBus(),
86             sdbusRule::member("PropertiesChanged") +
87                 sdbusRule::path(AMBIENT_PATH) +
88                 sdbusRule::argN(0, AMBIENT_INTERFACE) +
89                 sdbusRule::interface("org.freedesktop.DBus.Properties"),
90             std::bind(&Manager::ambientCallback, this, std::placeholders::_1))
91 #ifdef PLDM
92         ,
93         pldmHandle(std::make_unique<pldm::Interface>(
94             std::bind(std::mem_fn(&Manager::updateOCCActive), this,
95                       std::placeholders::_1, std::placeholders::_2),
96             std::bind(std::mem_fn(&Manager::sbeHRESETResult), this,
97                       std::placeholders::_1, std::placeholders::_2)))
98 #endif
99 #ifdef POWER10
100         ,
101         discoverTimer(
102             std::make_unique<
103                 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>(
104                 sdpEvent, std::bind(&Manager::findAndCreateObjects, this)))
105 #endif
106     {
107 #ifdef I2C_OCC
108         // I2C OCC status objects are initialized directly
109         initStatusObjects();
110 #else
111         findAndCreateObjects();
112 #endif
113         readAltitude();
114     }
115 
116     /** @brief Return the number of bound OCCs */
117     inline auto getNumOCCs() const
118     {
119         return activeCount;
120     }
121 
122 #ifdef PLDM
123     /** @brief Called by a Device to report that the SBE timed out
124      *         and appropriate action should be taken
125      *
126      * @param[in] instance - the OCC instance id
127      */
128     void sbeTimeout(unsigned int instance);
129 #endif
130 
131     /** @brief Return the latest ambient and altitude readings
132      *
133      *  @param[out] ambientValid - true if ambientTemp is valid
134      *  @param[out] ambient - ambient temperature in degrees C
135      *  @param[out] altitude - altitude in meters
136      */
137     void getAmbientData(bool& ambientValid, uint8_t& ambientTemp,
138                         uint16_t& altitude) const;
139 
140   private:
141     /** @brief Creates the OCC D-Bus objects.
142      */
143     void findAndCreateObjects();
144 
145     /** @brief Callback that responds to cpu creation in the inventory -
146      *         by creating the needed objects.
147      *
148      *  @param[in] msg - bus message
149      *
150      *  @returns 0 to indicate success
151      */
152     int cpuCreated(sdbusplus::message::message& msg);
153 
154     /** @brief Create child OCC objects.
155      *
156      *  @param[in] occ - the occ name, such as occ0.
157      */
158     void createObjects(const std::string& occ);
159 
160     /** @brief Callback handler invoked by Status object when the OccActive
161      *         property is changed. This is needed to make sure that the
162      *         error detection is started only after all the OCCs are bound.
163      *         Similarly, when one of the OCC gets its OccActive property
164      *         un-set, then the OCC error detection needs to be stopped on
165      *         all the OCCs
166      *
167      *  @param[in] status - OccActive status
168      */
169     void statusCallBack(bool status);
170 
171     /** @brief Sends a Heartbeat command to host control command handler */
172     void sendHeartBeat();
173 
174     /** @brief reference to sd_event wrapped in unique_ptr */
175     EventPtr& event;
176 
177     /** @brief OCC pass-through objects */
178     std::vector<std::unique_ptr<PassThrough>> passThroughObjects;
179 
180     /** @brief OCC Status objects */
181     std::vector<std::unique_ptr<Status>> statusObjects;
182 
183     /** @brief Power cap monitor and occ notification object */
184     std::unique_ptr<open_power::occ::powercap::PowerCap> pcap;
185 
186 #ifdef POWER10
187     /** @brief Power mode monitor and notification object */
188     std::unique_ptr<open_power::occ::powermode::PowerMode> pmode;
189 
190     /** @brief Idle Power Saver monitor and notification object */
191     std::unique_ptr<open_power::occ::powermode::PowerIPS> pips;
192 #endif
193 
194     /** @brief sbdbusplus match objects */
195     std::vector<sdbusplus::bus::match_t> cpuMatches;
196 
197     /** @brief Number of OCCs that are bound */
198     uint8_t activeCount = 0;
199 
200     /** @brief Number of seconds between poll commands */
201     uint8_t pollInterval;
202 
203     /** @brief Ambient temperature of the system in degrees C */
204     uint8_t ambient = 0xFF; // default: not available
205 
206     /** @brief Altitude of the system in meters */
207     uint16_t altitude = 0xFFFF; // default: not available
208 
209     /** @brief Poll timer event */
210     sdeventplus::Event sdpEvent;
211 
212     /**
213      * @brief The timer to be used once the OCC goes active.  When it expires,
214      *        a POLL command will be sent to the OCC and then timer restarted.
215      */
216     std::unique_ptr<
217         sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
218         _pollTimer;
219 
220     /** @brief Subscribe to ambient temperature changed events */
221     sdbusplus::bus::match_t ambientPropChanged;
222 
223 #ifdef I2C_OCC
224     /** @brief Init Status objects for I2C OCC devices
225      *
226      * It iterates in /sys/bus/i2c/devices, finds all occ hwmon devices
227      * and creates status objects.
228      */
229     void initStatusObjects();
230 #endif
231 
232 #ifdef PLDM
233     /** @brief Callback handler invoked by the PLDM event handler when state of
234      *         the OCC is toggled by the host. The caller passes the instance
235      *         of the OCC and state of the OCC.
236      *
237      *  @param[in] instance - instance of the OCC
238      *  @param[in] status - true when the OCC goes active and false when the OCC
239      *                      goes inactive
240      *
241      *  @return true if setting the state of OCC is successful and false if it
242      *          fails.
243      */
244     bool updateOCCActive(instanceID instance, bool status);
245 
246     /** @brief Callback handler invoked by PLDM sensor change when
247      *         the HRESET succeeds or fails.
248      *
249      *  @param[in] instance - the SBE instance id
250      *  @param[in] success - true if the HRESET succeeded, otherwise false
251      */
252     void sbeHRESETResult(instanceID instance, bool success);
253 
254     /** @brief Helper function to check whether an SBE dump should be collected
255      *         now.
256      *
257      *  @param[in] instance - the SBE instance id
258      *
259      *  @return true if an SBE dump should be collected and false if not
260      */
261     bool sbeCanDump(unsigned int instance);
262 
263     /** @brief Helper function to set the SBE state through PDBG/PHAL
264      *
265      * @param[in] instance - instance of the SBE
266      * @param[in] state - the state to which the SBE should be set
267      *
268      */
269     void setSBEState(unsigned int instance, enum sbe_state state);
270 
271     /** @brief Helper function to get the SBE instance PDBG processor target
272      *
273      * @param[in] instance - the SBE instance id
274      *
275      * @return a pointer to the PDBG target
276      */
277     struct pdbg_target* getPdbgTarget(unsigned int instance);
278 
279     /** @brief Whether pdbg_targets_init has been called */
280     bool pdbgInitialized = false;
281 
282     std::unique_ptr<pldm::Interface> pldmHandle = nullptr;
283 #endif
284 
285 #ifdef POWER10
286     /**
287      * @brief Timer used when discovering OCCs in /dev.
288      */
289     std::unique_ptr<
290         sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
291         discoverTimer;
292 
293     /**
294      * @brief Used when discovering /dev/occ objects to know if
295      *        any were added since the last check.
296      */
297     std::vector<int> prevOCCSearch;
298 #endif
299 
300     /**
301      * @brief Called when poll timer expires and forces a POLL command to the
302      * OCC. The poll timer will then be restarted.
303      * */
304     void pollerTimerExpired();
305 
306     /**
307      * @brief Finds the OCC devices in /dev
308      *
309      * @return The IDs of the OCCs - 0, 1, etc.
310      */
311     std::vector<int> findOCCsInDev();
312 
313 #ifdef READ_OCC_SENSORS
314     /**
315      * @brief Gets the occ sensor values.
316      * @param[in] id - Id of the OCC.
317      * @param[in] masterOcc - Is this OCC the master OCC.
318      * */
319     void getSensorValues(uint32_t id, bool masterOcc);
320 
321     /**
322      * @brief Trigger OCC driver to read the temperature sensors.
323      * @param[in] path - path of the OCC sensors.
324      * @param[in] id - Id of the OCC.
325      * */
326     void readTempSensors(const fs::path& path, uint32_t id);
327 
328     /**
329      * @brief Trigger OCC driver to read the power sensors.
330      * @param[in] path - path of the OCC sensors.
331      * @param[in] id - Id of the OCC.
332      * */
333     void readPowerSensors(const fs::path& path, uint32_t id);
334 
335     /**
336      * @brief Set all sensor values of this OCC to NaN.
337      * @param[in] id - Id of the OCC.
338      * */
339     void setSensorValueToNaN(uint32_t id);
340 
341     /** @brief Store the existing OCC sensors on D-BUS */
342     std::map<std::string, uint32_t> existingSensors;
343 
344     /** @brief Get FunctionID from the `powerX_label` file.
345      *  @param[in] value - the value of the `powerX_label` file.
346      *  @returns FunctionID of the power sensors.
347      */
348     std::optional<std::string>
349         getPowerLabelFunctionID(const std::string& value);
350 
351     /** @brief The power sensor names map */
352     const std::map<std::string, std::string> powerSensorName = {
353         {"system", "total_power"}, {"1", "p0_mem_power"},
354         {"2", "p1_mem_power"},     {"3", "p2_mem_power"},
355         {"4", "p3_mem_power"},     {"5", "p0_power"},
356         {"6", "p1_power"},         {"7", "p2_power"},
357         {"8", "p3_power"},         {"9", "p0_cache_power"},
358         {"10", "p1_cache_power"},  {"11", "p2_cache_power"},
359         {"12", "p3_cache_power"},  {"13", "io_a_power"},
360         {"14", "io_b_power"},      {"15", "io_c_power"},
361         {"16", "fans_a_power"},    {"17", "fans_b_power"},
362         {"18", "storage_a_power"}, {"19", "storage_b_power"},
363         {"23", "mem_cache_power"}, {"25", "p0_mem_0_power"},
364         {"26", "p0_mem_1_power"},  {"27", "p0_mem_2_power"}};
365 
366     /** @brief The dimm temperature sensor names map */
367     const std::map<uint32_t, std::string> dimmTempSensorName = {
368         {internalMemCtlr, "_intmb_temp"},
369         {dimm, "_dram_temp"},
370         {memCtrlAndDimm, "_dram_extmb_temp"},
371         {PMIC, "_pmic_temp"},
372         {memCtlrExSensor, "_extmb_temp"}};
373 #endif
374 
375     /** @brief Read the altitude from DBus */
376     void readAltitude();
377 
378     /** @brief Callback function when ambient temperature changes
379      *
380      *  @param[in]  msg - Data associated with subscribed signal
381      */
382     void ambientCallback(sdbusplus::message::message& msg);
383 };
384 
385 } // namespace occ
386 } // namespace open_power
387