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 explicit 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 event)) 99 #endif 100 #ifdef POWER10 101 , 102 discoverTimer( 103 std::make_unique< 104 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>( 105 sdpEvent, std::bind(&Manager::findAndCreateObjects, this))), 106 waitForAllOccsTimer( 107 std::make_unique< 108 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>( 109 sdpEvent, std::bind(&Manager::occsNotAllRunning, this))) 110 #endif 111 { 112 #ifdef I2C_OCC 113 // I2C OCC status objects are initialized directly 114 initStatusObjects(); 115 #else 116 findAndCreateObjects(); 117 #endif 118 readAltitude(); 119 } 120 121 /** @brief Return the number of bound OCCs */ 122 inline auto getNumOCCs() const 123 { 124 return activeCount; 125 } 126 127 #ifdef PLDM 128 /** @brief Called by a Device to report that the SBE timed out 129 * and appropriate action should be taken 130 * 131 * @param[in] instance - the OCC instance id 132 */ 133 void sbeTimeout(unsigned int instance); 134 #endif 135 136 /** @brief Return the latest ambient and altitude readings 137 * 138 * @param[out] ambientValid - true if ambientTemp is valid 139 * @param[out] ambient - ambient temperature in degrees C 140 * @param[out] altitude - altitude in meters 141 */ 142 void getAmbientData(bool& ambientValid, uint8_t& ambientTemp, 143 uint16_t& altitude) const; 144 145 /** @brief Notify pcap object to update bounds */ 146 void updatePcapBounds() const; 147 148 /** @brief Set all sensor values of this OCC to NaN and non functional. 149 * 150 * @param[in] id - Id of the OCC. 151 */ 152 void setSensorValueToNonFunctional(uint32_t id) const; 153 154 private: 155 /** @brief Creates the OCC D-Bus objects. 156 */ 157 void findAndCreateObjects(); 158 159 /** @brief Callback that responds to cpu creation in the inventory - 160 * by creating the needed objects. 161 * 162 * @param[in] msg - bus message 163 * 164 * @returns 0 to indicate success 165 */ 166 int cpuCreated(sdbusplus::message::message& msg); 167 168 /** @brief Create child OCC objects. 169 * 170 * @param[in] occ - the occ name, such as occ0. 171 */ 172 void createObjects(const std::string& occ); 173 174 /** @brief Callback handler invoked by Status object when the OccActive 175 * property is changed. This is needed to make sure that the 176 * error detection is started only after all the OCCs are bound. 177 * Similarly, when one of the OCC gets its OccActive property 178 * un-set, then the OCC error detection needs to be stopped on 179 * all the OCCs 180 * 181 * @param[in] status - OccActive status 182 */ 183 void statusCallBack(instanceID instance, bool status); 184 185 /** @brief Sends a Heartbeat command to host control command handler */ 186 void sendHeartBeat(); 187 188 /** @brief reference to sd_event wrapped in unique_ptr */ 189 EventPtr& event; 190 191 /** @brief OCC pass-through objects */ 192 std::vector<std::unique_ptr<PassThrough>> passThroughObjects; 193 194 /** @brief OCC Status objects */ 195 std::vector<std::unique_ptr<Status>> statusObjects; 196 197 /** @brief Power cap monitor and occ notification object */ 198 std::unique_ptr<open_power::occ::powercap::PowerCap> pcap; 199 200 #ifdef POWER10 201 /** @brief Power mode monitor and notification object */ 202 std::unique_ptr<open_power::occ::powermode::PowerMode> pmode; 203 #endif 204 205 /** @brief sbdbusplus match objects */ 206 std::vector<sdbusplus::bus::match_t> cpuMatches; 207 208 /** @brief Number of OCCs that are bound */ 209 uint8_t activeCount = 0; 210 211 /** @brief Number of seconds between poll commands */ 212 uint8_t pollInterval; 213 214 /** @brief Ambient temperature of the system in degrees C */ 215 uint8_t ambient = 0xFF; // default: not available 216 217 /** @brief Altitude of the system in meters */ 218 uint16_t altitude = 0xFFFF; // default: not available 219 220 /** @brief Poll timer event */ 221 sdeventplus::Event sdpEvent; 222 223 /** @brief Flags to indicate if waiting for all of the OCC active sensors to 224 * come online */ 225 bool waitingForAllOccActiveSensors = false; 226 227 /** 228 * @brief The timer to be used once the OCC goes active. When it expires, 229 * a POLL command will be sent to the OCC and then timer restarted. 230 */ 231 std::unique_ptr< 232 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>> 233 _pollTimer; 234 235 /** @brief Subscribe to ambient temperature changed events */ 236 sdbusplus::bus::match_t ambientPropChanged; 237 238 #ifdef I2C_OCC 239 /** @brief Init Status objects for I2C OCC devices 240 * 241 * It iterates in /sys/bus/i2c/devices, finds all occ hwmon devices 242 * and creates status objects. 243 */ 244 void initStatusObjects(); 245 #endif 246 247 #ifdef PLDM 248 /** @brief Callback handler invoked by the PLDM event handler when state of 249 * the OCC is toggled by the host. The caller passes the instance 250 * of the OCC and state of the OCC. 251 * 252 * @param[in] instance - instance of the OCC 253 * @param[in] status - true when the OCC goes active and false when the OCC 254 * goes inactive 255 * 256 * @return true if setting the state of OCC is successful and false if it 257 * fails. 258 */ 259 bool updateOCCActive(instanceID instance, bool status); 260 261 /** @brief Callback handler invoked by PLDM sensor change when 262 * the HRESET succeeds or fails. 263 * 264 * @param[in] instance - the SBE instance id 265 * @param[in] success - true if the HRESET succeeded, otherwise false 266 */ 267 void sbeHRESETResult(instanceID instance, bool success); 268 269 /** @brief Helper function to check whether an SBE dump should be collected 270 * now. 271 * 272 * @param[in] instance - the SBE instance id 273 * 274 * @return true if an SBE dump should be collected and false if not 275 */ 276 bool sbeCanDump(unsigned int instance); 277 278 /** @brief Helper function to set the SBE state through PDBG/PHAL 279 * 280 * @param[in] instance - instance of the SBE 281 * @param[in] state - the state to which the SBE should be set 282 * 283 */ 284 void setSBEState(unsigned int instance, enum sbe_state state); 285 286 /** @brief Helper function to get the SBE instance PDBG processor target 287 * 288 * @param[in] instance - the SBE instance id 289 * 290 * @return a pointer to the PDBG target 291 */ 292 struct pdbg_target* getPdbgTarget(unsigned int instance); 293 294 /** @brief Whether pdbg_targets_init has been called */ 295 bool pdbgInitialized = false; 296 297 std::unique_ptr<pldm::Interface> pldmHandle = nullptr; 298 #endif 299 300 #ifdef POWER10 301 /** 302 * @brief Timer used when discovering OCCs in /dev. 303 */ 304 std::unique_ptr< 305 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>> 306 discoverTimer; 307 308 /** 309 * @brief Used when discovering /dev/occ objects to know if 310 * any were added since the last check. 311 */ 312 std::vector<int> prevOCCSearch; 313 314 /** 315 * @brief Timer used when waiting for OCCs to go active. 316 */ 317 std::unique_ptr< 318 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>> 319 waitForAllOccsTimer; 320 321 /** @brief Called when code times out waiting for all OCCs to be running or 322 * after the app is restarted (Status does not callback into 323 * Manager). 324 */ 325 void occsNotAllRunning(); 326 327 /** @brief Check if all of the OCC Active sensors are available and if not 328 * restart the discoverTimer 329 */ 330 void checkAllActiveSensors(); 331 #endif 332 333 /** 334 * @brief Called when poll timer expires and forces a POLL command to the 335 * OCC. The poll timer will then be restarted. 336 * */ 337 void pollerTimerExpired(); 338 339 /** 340 * @brief Finds the OCC devices in /dev 341 * 342 * @return The IDs of the OCCs - 0, 1, etc. 343 */ 344 std::vector<int> findOCCsInDev(); 345 346 #ifdef READ_OCC_SENSORS 347 /** 348 * @brief Gets the occ sensor values. 349 * @param[in] occ - pointer to OCCs Status object 350 * */ 351 void getSensorValues(std::unique_ptr<Status>& occ); 352 353 /** 354 * @brief Trigger OCC driver to read the temperature sensors. 355 * @param[in] path - path of the OCC sensors. 356 * @param[in] id - Id of the OCC. 357 * */ 358 void readTempSensors(const fs::path& path, uint32_t id); 359 360 /** 361 * @brief Trigger OCC driver to read the power sensors. 362 * @param[in] path - path of the OCC sensors. 363 * @param[in] id - Id of the OCC. 364 * */ 365 void readPowerSensors(const fs::path& path, uint32_t id); 366 367 /** 368 * @brief Set all sensor values of this OCC to NaN. 369 * @param[in] id - Id of the OCC. 370 * */ 371 void setSensorValueToNaN(uint32_t id); 372 373 /** @brief Store the existing OCC sensors on D-BUS */ 374 std::map<std::string, uint32_t> existingSensors; 375 376 /** @brief Get FunctionID from the `powerX_label` file. 377 * @param[in] value - the value of the `powerX_label` file. 378 * @returns FunctionID of the power sensors. 379 */ 380 std::optional<std::string> 381 getPowerLabelFunctionID(const std::string& value); 382 383 /** @brief The power sensor names map */ 384 const std::map<std::string, std::string> powerSensorName = { 385 {"system", "total_power"}, {"1", "p0_mem_power"}, 386 {"2", "p1_mem_power"}, {"3", "p2_mem_power"}, 387 {"4", "p3_mem_power"}, {"5", "p0_power"}, 388 {"6", "p1_power"}, {"7", "p2_power"}, 389 {"8", "p3_power"}, {"9", "p0_cache_power"}, 390 {"10", "p1_cache_power"}, {"11", "p2_cache_power"}, 391 {"12", "p3_cache_power"}, {"13", "io_a_power"}, 392 {"14", "io_b_power"}, {"15", "io_c_power"}, 393 {"16", "fans_a_power"}, {"17", "fans_b_power"}, 394 {"18", "storage_a_power"}, {"19", "storage_b_power"}, 395 {"23", "mem_cache_power"}, {"25", "p0_mem_0_power"}, 396 {"26", "p0_mem_1_power"}, {"27", "p0_mem_2_power"}, 397 {"35", "pcie_dcm0_power"}, {"36", "pcie_dcm1_power"}, 398 {"37", "pcie_dcm2_power"}, {"38", "pcie_dcm3_power"}, 399 {"39", "io_dcm0_power"}, {"40", "io_dcm1_power"}, 400 {"41", "io_dcm2_power"}, {"42", "io_dcm3_power"}, 401 {"43", "avdd_total_power"}}; 402 403 /** @brief The dimm temperature sensor names map */ 404 const std::map<uint32_t, std::string> dimmTempSensorName = { 405 {internalMemCtlr, "_intmb_temp"}, 406 {dimm, "_dram_temp"}, 407 {memCtrlAndDimm, "_dram_extmb_temp"}, 408 {PMIC, "_pmic_temp"}, 409 {memCtlrExSensor, "_extmb_temp"}}; 410 #endif 411 412 /** @brief Read the altitude from DBus */ 413 void readAltitude(); 414 415 /** @brief Callback function when ambient temperature changes 416 * 417 * @param[in] msg - Data associated with subscribed signal 418 */ 419 void ambientCallback(sdbusplus::message::message& msg); 420 421 /** @brief Confirm that a single OCC master was found and start presence 422 * monitoring 423 */ 424 void validateOccMaster(); 425 }; 426 427 } // namespace occ 428 } // namespace open_power 429