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