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 #ifdef POWER10 11 #include "powermode.hpp" 12 #endif 13 14 #include <sdbusplus/bus.hpp> 15 #include <sdeventplus/event.hpp> 16 #include <sdeventplus/utility/timer.hpp> 17 18 #include <cstring> 19 #include <functional> 20 #include <vector> 21 22 namespace sdbusRule = sdbusplus::bus::match::rules; 23 namespace open_power 24 { 25 namespace occ 26 { 27 28 #ifdef READ_OCC_SENSORS 29 enum occFruType 30 { 31 processorCore = 0, 32 internalMemCtlr = 1, 33 dimm = 2, 34 memCtrlAndDimm = 3, 35 VRMVdd = 6, 36 PMIC = 7, 37 memCtlrExSensor = 8 38 }; 39 #endif 40 41 /** @brief Default time, in seconds, between OCC poll commands */ 42 constexpr unsigned int defaultPollingInterval = 1; 43 44 /** @class Manager 45 * @brief Builds and manages OCC objects 46 */ 47 struct Manager 48 { 49 public: 50 Manager() = delete; 51 Manager(const Manager&) = delete; 52 Manager& operator=(const Manager&) = delete; 53 Manager(Manager&&) = delete; 54 Manager& operator=(Manager&&) = delete; 55 ~Manager() = default; 56 57 /** @brief Adds OCC pass-through and status objects on the bus 58 * when corresponding CPU inventory is created. 59 * 60 * @param[in] event - Unique ptr reference to sd_event 61 */ 62 Manager(EventPtr& event) : 63 event(event), pollInterval(defaultPollingInterval), 64 sdpEvent(sdeventplus::Event::get_default()), 65 _pollTimer( 66 std::make_unique< 67 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>( 68 sdpEvent, std::bind(&Manager::pollerTimerExpired, this))) 69 #ifdef PLDM 70 , 71 pldmHandle(std::make_unique<pldm::Interface>( 72 std::bind(std::mem_fn(&Manager::updateOCCActive), this, 73 std::placeholders::_1, std::placeholders::_2))) 74 #endif 75 #ifdef POWER10 76 , 77 discoverTimer( 78 std::make_unique< 79 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>( 80 sdpEvent, std::bind(&Manager::findAndCreateObjects, this))) 81 #endif 82 { 83 #ifdef I2C_OCC 84 // I2C OCC status objects are initialized directly 85 initStatusObjects(); 86 #else 87 findAndCreateObjects(); 88 #endif 89 } 90 91 /** @brief Return the number of bound OCCs */ 92 inline auto getNumOCCs() const 93 { 94 return activeCount; 95 } 96 97 private: 98 /** @brief Creates the OCC D-Bus objects. 99 */ 100 void findAndCreateObjects(); 101 102 /** @brief Callback that responds to cpu creation in the inventory - 103 * by creating the needed objects. 104 * 105 * @param[in] msg - bus message 106 * 107 * @returns 0 to indicate success 108 */ 109 int cpuCreated(sdbusplus::message::message& msg); 110 111 /** @brief Create child OCC objects. 112 * 113 * @param[in] occ - the occ name, such as occ0. 114 */ 115 void createObjects(const std::string& occ); 116 117 /** @brief Callback handler invoked by Status object when the OccActive 118 * property is changed. This is needed to make sure that the 119 * error detection is started only after all the OCCs are bound. 120 * Similarly, when one of the OCC gets its OccActive property 121 * un-set, then the OCC error detection needs to be stopped on 122 * all the OCCs 123 * 124 * @param[in] status - OccActive status 125 */ 126 void statusCallBack(bool status); 127 128 /** @brief Sends a Heartbeat command to host control command handler */ 129 void sendHeartBeat(); 130 131 /** @brief reference to sd_event wrapped in unique_ptr */ 132 EventPtr& event; 133 134 /** @brief OCC pass-through objects */ 135 std::vector<std::unique_ptr<PassThrough>> passThroughObjects; 136 137 /** @brief OCC Status objects */ 138 std::vector<std::unique_ptr<Status>> statusObjects; 139 140 /** @brief Power cap monitor and occ notification object */ 141 std::unique_ptr<open_power::occ::powercap::PowerCap> pcap; 142 143 #ifdef POWER10 144 /** @brief Power mode monitor and notification object */ 145 std::unique_ptr<open_power::occ::powermode::PowerMode> pmode; 146 #endif 147 148 /** @brief sbdbusplus match objects */ 149 std::vector<sdbusplus::bus::match_t> cpuMatches; 150 151 /** @brief Number of OCCs that are bound */ 152 uint8_t activeCount = 0; 153 154 /** @brief Number of seconds between poll commands */ 155 uint8_t pollInterval; 156 157 /** @brief Poll timer event */ 158 sdeventplus::Event sdpEvent; 159 160 /** 161 * @brief The timer to be used once the OCC goes active. When it expires, 162 * a POLL command will be sent to the OCC and then timer restarted. 163 */ 164 std::unique_ptr< 165 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>> 166 _pollTimer; 167 168 #ifdef I2C_OCC 169 /** @brief Init Status objects for I2C OCC devices 170 * 171 * It iterates in /sys/bus/i2c/devices, finds all occ hwmon devices 172 * and creates status objects. 173 */ 174 void initStatusObjects(); 175 #endif 176 177 #ifdef PLDM 178 /** @brief Callback handler invoked by the PLDM event handler when state of 179 * the OCC is toggled by the host. The caller passes the instance 180 * of the OCC and state of the OCC. 181 * 182 * @param[in] instance - instance of the OCC 183 * @param[in] status - true when the OCC goes active and false when the OCC 184 * goes inactive 185 * 186 * @return true if setting the state of OCC is successful and false if it 187 * fails. 188 */ 189 bool updateOCCActive(instanceID instance, bool status); 190 191 std::unique_ptr<pldm::Interface> pldmHandle = nullptr; 192 #endif 193 194 #ifdef POWER10 195 /** 196 * @brief Timer used when discovering OCCs in /dev. 197 */ 198 std::unique_ptr< 199 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>> 200 discoverTimer; 201 202 /** 203 * @brief Used when discovering /dev/occ objects to know if 204 * any were added since the last check. 205 */ 206 std::vector<int> prevOCCSearch; 207 #endif 208 209 /** 210 * @brief Called when poll timer expires and forces a POLL command to the 211 * OCC. The poll timer will then be restarted. 212 * */ 213 void pollerTimerExpired(); 214 215 /** 216 * @brief Finds the OCC devices in /dev 217 * 218 * @return The IDs of the OCCs - 0, 1, etc. 219 */ 220 std::vector<int> findOCCsInDev(); 221 222 #ifdef READ_OCC_SENSORS 223 /** 224 * @brief Gets the occ sensor values. 225 * @param[in] id - Id of the OCC. 226 * @param[in] masterOcc - Is this OCC the master OCC. 227 * */ 228 void getSensorValues(uint32_t id, bool masterOcc); 229 230 /** 231 * @brief Trigger OCC driver to read the temperature sensors. 232 * @param[in] path - path of the OCC sensors. 233 * @param[in] id - Id of the OCC. 234 * */ 235 void readTempSensors(const fs::path& path, uint32_t id); 236 237 /** 238 * @brief Trigger OCC driver to read the power sensors. 239 * @param[in] path - path of the OCC sensors. 240 * @param[in] id - Id of the OCC. 241 * */ 242 void readPowerSensors(const fs::path& path, uint32_t id); 243 244 /** 245 * @brief Set all sensor values of this OCC to NaN. 246 * @param[in] id - Id of the OCC. 247 * */ 248 void setSensorValueToNaN(uint32_t id); 249 250 /** @brief Store the existing OCC sensors on D-BUS */ 251 std::map<std::string, uint32_t> existingSensors; 252 253 /** @brief Get FunctionID from the `powerX_label` file. 254 * @param[in] value - the value of the `powerX_label` file. 255 * @returns FunctionID of the power sensors. 256 */ 257 std::optional<std::string> 258 getPowerLabelFunctionID(const std::string& value); 259 260 /** @brief The power sensor names map */ 261 const std::map<std::string, std::string> powerSensorName = { 262 {"system", "total_power"}, {"1", "p0_mem_power"}, 263 {"2", "p1_mem_power"}, {"3", "p2_mem_power"}, 264 {"4", "p3_mem_power"}, {"5", "p0_power"}, 265 {"6", "p1_power"}, {"7", "p2_power"}, 266 {"8", "p3_power"}, {"9", "p0_cache_power"}, 267 {"10", "p1_cache_power"}, {"11", "p2_cache_power"}, 268 {"12", "p3_cache_power"}, {"13", "io_a_power"}, 269 {"14", "io_b_power"}, {"15", "io_c_power"}, 270 {"16", "fans_a_power"}, {"17", "fans_b_power"}, 271 {"18", "storage_a_power"}, {"19", "storage_b_power"}, 272 {"23", "mem_cache_power"}, {"25", "p0_mem_0_power"}, 273 {"26", "p0_mem_1_power"}, {"27", "p0_mem_2_power"}}; 274 275 /** @brief The dimm temperature sensor names map */ 276 const std::map<uint32_t, std::string> dimmTempSensorName = { 277 {internalMemCtlr, "_intmb_temp"}, 278 {dimm, "_dram_temp"}, 279 {memCtrlAndDimm, "_dram_extmb_temp"}, 280 {PMIC, "_pmic_temp"}, 281 {memCtlrExSensor, "_extmb_temp"}}; 282 #endif 283 }; 284 285 } // namespace occ 286 } // namespace open_power 287