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