1dfc7ec73SVishwanatha Subbanna #include "config.h" 2dfc7ec73SVishwanatha Subbanna 394df8c90SGunnar Mills #include "occ_manager.hpp" 494df8c90SGunnar Mills 594df8c90SGunnar Mills #include "i2c_occ.hpp" 6bb895cb8SChicago Duan #include "occ_dbus.hpp" 74b82f3e3SChris Cain #include "occ_errors.hpp" 894df8c90SGunnar Mills #include "utils.hpp" 994df8c90SGunnar Mills 10b5ca1015SGeorge Liu #include <phosphor-logging/elog-errors.hpp> 11b5ca1015SGeorge Liu #include <phosphor-logging/log.hpp> 12b5ca1015SGeorge Liu #include <xyz/openbmc_project/Common/error.hpp> 13b5ca1015SGeorge Liu 14d267cec2SMatt Spinler #include <chrono> 15bb895cb8SChicago Duan #include <cmath> 16bcef3b48SGeorge Liu #include <filesystem> 1736f9cdedSChris Cain #include <fstream> 18bb895cb8SChicago Duan #include <regex> 1994df8c90SGunnar Mills 20dfc7ec73SVishwanatha Subbanna namespace open_power 21dfc7ec73SVishwanatha Subbanna { 22dfc7ec73SVishwanatha Subbanna namespace occ 23dfc7ec73SVishwanatha Subbanna { 24dfc7ec73SVishwanatha Subbanna 258b8abeedSMatt Spinler constexpr uint32_t fruTypeNotAvailable = 0xFF; 26a26f1527SMatt Spinler constexpr auto fruTypeSuffix = "fru_type"; 27a26f1527SMatt Spinler constexpr auto faultSuffix = "fault"; 28a26f1527SMatt Spinler constexpr auto inputSuffix = "input"; 29ace67d85SMatt Spinler constexpr auto maxSuffix = "max"; 308b8abeedSMatt Spinler 311718fd8bSChris Cain const auto HOST_ON_FILE = "/run/openbmc/host@0-on"; 321718fd8bSChris Cain 33a8857c50SChris Cain using namespace phosphor::logging; 34a7b74dc3SChris Cain using namespace std::literals::chrono_literals; 35a8857c50SChris Cain 36a26f1527SMatt Spinler template <typename T> 37a26f1527SMatt Spinler T readFile(const std::string& path) 38a26f1527SMatt Spinler { 39a26f1527SMatt Spinler std::ifstream ifs; 40a26f1527SMatt Spinler ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit | 41a26f1527SMatt Spinler std::ifstream::eofbit); 42a26f1527SMatt Spinler T data; 43a26f1527SMatt Spinler 44a26f1527SMatt Spinler try 45a26f1527SMatt Spinler { 46a26f1527SMatt Spinler ifs.open(path); 47a26f1527SMatt Spinler ifs >> data; 48a26f1527SMatt Spinler ifs.close(); 49a26f1527SMatt Spinler } 50a26f1527SMatt Spinler catch (const std::exception& e) 51a26f1527SMatt Spinler { 52a26f1527SMatt Spinler auto err = errno; 53a26f1527SMatt Spinler throw std::system_error(err, std::generic_category()); 54a26f1527SMatt Spinler } 55a26f1527SMatt Spinler 56a26f1527SMatt Spinler return data; 57a26f1527SMatt Spinler } 58a26f1527SMatt Spinler 59c33171bbSChris Cain // findAndCreateObjects(): 60c33171bbSChris Cain // Takes care of getting the required objects created and 61c33171bbSChris Cain // finds the available devices/processors. 62c33171bbSChris Cain // (function is called everytime the discoverTimer expires) 63c33171bbSChris Cain // - create the PowerMode object to control OCC modes 64c33171bbSChris Cain // - create statusObjects for each OCC device found 65c33171bbSChris Cain // - waits for OCC Active sensors PDRs to become available 66c33171bbSChris Cain // - restart discoverTimer if all data is not available yet 67dfc7ec73SVishwanatha Subbanna void Manager::findAndCreateObjects() 68dfc7ec73SVishwanatha Subbanna { 69d267cec2SMatt Spinler #ifndef POWER10 70dfc7ec73SVishwanatha Subbanna for (auto id = 0; id < MAX_CPUS; ++id) 71dfc7ec73SVishwanatha Subbanna { 7230417a15SDeepak Kodihalli // Create one occ per cpu 7330417a15SDeepak Kodihalli auto occ = std::string(OCC_NAME) + std::to_string(id); 74dfc7ec73SVishwanatha Subbanna createObjects(occ); 75dfc7ec73SVishwanatha Subbanna } 76d267cec2SMatt Spinler #else 77613dc90dSChris Cain if (!pmode) 78613dc90dSChris Cain { 79613dc90dSChris Cain // Create the power mode object 80613dc90dSChris Cain pmode = std::make_unique<powermode::PowerMode>( 81613dc90dSChris Cain *this, powermode::PMODE_PATH, powermode::PIPS_PATH, event); 82613dc90dSChris Cain } 83613dc90dSChris Cain 841718fd8bSChris Cain if (!fs::exists(HOST_ON_FILE)) 851718fd8bSChris Cain { 86bae4d07eSChris Cain static bool statusObjCreated = false; 87bae4d07eSChris Cain if (!statusObjCreated) 88bae4d07eSChris Cain { 89d267cec2SMatt Spinler // Create the OCCs based on on the /dev/occX devices 90d267cec2SMatt Spinler auto occs = findOCCsInDev(); 91d267cec2SMatt Spinler 92d267cec2SMatt Spinler if (occs.empty() || (prevOCCSearch.size() != occs.size())) 93d267cec2SMatt Spinler { 94d267cec2SMatt Spinler // Something changed or no OCCs yet, try again in 10s. 95d267cec2SMatt Spinler // Note on the first pass prevOCCSearch will be empty, 96d267cec2SMatt Spinler // so there will be at least one delay to give things 97d267cec2SMatt Spinler // a chance to settle. 98d267cec2SMatt Spinler prevOCCSearch = occs; 99d267cec2SMatt Spinler 100bae4d07eSChris Cain log<level::INFO>( 10148002498SPatrick Williams std::format( 102bae4d07eSChris Cain "Manager::findAndCreateObjects(): Waiting for OCCs (currently {})", 103bae4d07eSChris Cain occs.size()) 104bae4d07eSChris Cain .c_str()); 105bae4d07eSChris Cain 106d267cec2SMatt Spinler discoverTimer->restartOnce(10s); 107d267cec2SMatt Spinler } 108d267cec2SMatt Spinler else 109d267cec2SMatt Spinler { 110bae4d07eSChris Cain // All OCCs appear to be available, create status objects 111d267cec2SMatt Spinler 112d267cec2SMatt Spinler // createObjects requires OCC0 first. 113d267cec2SMatt Spinler std::sort(occs.begin(), occs.end()); 114d267cec2SMatt Spinler 115bae4d07eSChris Cain log<level::INFO>( 11648002498SPatrick Williams std::format( 117bae4d07eSChris Cain "Manager::findAndCreateObjects(): Creating {} OCC Status Objects", 118bae4d07eSChris Cain occs.size()) 119bae4d07eSChris Cain .c_str()); 120d267cec2SMatt Spinler for (auto id : occs) 121d267cec2SMatt Spinler { 122d267cec2SMatt Spinler createObjects(std::string(OCC_NAME) + std::to_string(id)); 123d267cec2SMatt Spinler } 124bae4d07eSChris Cain statusObjCreated = true; 1256d8f37a2SChris Cain waitingForAllOccActiveSensors = true; 126c86d80faSChris Cain 127c86d80faSChris Cain // Find/update the processor path associated with each OCC 128c86d80faSChris Cain for (auto& obj : statusObjects) 129c86d80faSChris Cain { 130c86d80faSChris Cain obj->updateProcAssociation(); 131c86d80faSChris Cain } 132bae4d07eSChris Cain } 133bae4d07eSChris Cain } 134bae4d07eSChris Cain 1356d8f37a2SChris Cain if (statusObjCreated && waitingForAllOccActiveSensors) 136bae4d07eSChris Cain { 137bae4d07eSChris Cain static bool tracedHostWait = false; 138bae4d07eSChris Cain if (utils::isHostRunning()) 139bae4d07eSChris Cain { 140bae4d07eSChris Cain if (tracedHostWait) 141bae4d07eSChris Cain { 142bae4d07eSChris Cain log<level::INFO>( 143bae4d07eSChris Cain "Manager::findAndCreateObjects(): Host is running"); 144bae4d07eSChris Cain tracedHostWait = false; 145bae4d07eSChris Cain } 146bae4d07eSChris Cain checkAllActiveSensors(); 147bae4d07eSChris Cain } 148bae4d07eSChris Cain else 149bae4d07eSChris Cain { 150bae4d07eSChris Cain if (!tracedHostWait) 151bae4d07eSChris Cain { 152bae4d07eSChris Cain log<level::INFO>( 153bae4d07eSChris Cain "Manager::findAndCreateObjects(): Waiting for host to start"); 154bae4d07eSChris Cain tracedHostWait = true; 155bae4d07eSChris Cain } 156bae4d07eSChris Cain discoverTimer->restartOnce(30s); 1577651c06bSChris Cain #ifdef PLDM 158c33171bbSChris Cain if (throttlePldmTraceTimer->isEnabled()) 1597651c06bSChris Cain { 1607651c06bSChris Cain // Host is no longer running, disable throttle timer and 1617651c06bSChris Cain // make sure traces are not throttled 1627651c06bSChris Cain log<level::INFO>( 1637651c06bSChris Cain "findAndCreateObjects(): disabling sensor timer"); 164c33171bbSChris Cain throttlePldmTraceTimer->setEnabled(false); 1657651c06bSChris Cain pldmHandle->setTraceThrottle(false); 1667651c06bSChris Cain } 1677651c06bSChris Cain #endif 168bae4d07eSChris Cain } 169d267cec2SMatt Spinler } 1701718fd8bSChris Cain } 1711718fd8bSChris Cain else 1721718fd8bSChris Cain { 1731718fd8bSChris Cain log<level::INFO>( 17448002498SPatrick Williams std::format( 1751718fd8bSChris Cain "Manager::findAndCreateObjects(): Waiting for {} to complete...", 1761718fd8bSChris Cain HOST_ON_FILE) 1771718fd8bSChris Cain .c_str()); 1781718fd8bSChris Cain discoverTimer->restartOnce(10s); 1791718fd8bSChris Cain } 180d267cec2SMatt Spinler #endif 181d267cec2SMatt Spinler } 182d267cec2SMatt Spinler 183bae4d07eSChris Cain #ifdef POWER10 184bae4d07eSChris Cain // Check if all occActive sensors are available 185bae4d07eSChris Cain void Manager::checkAllActiveSensors() 186bae4d07eSChris Cain { 187bae4d07eSChris Cain static bool allActiveSensorAvailable = false; 188bae4d07eSChris Cain static bool tracedSensorWait = false; 189082a6ca7SChris Cain static bool waitingForHost = false; 190082a6ca7SChris Cain 191082a6ca7SChris Cain if (open_power::occ::utils::isHostRunning()) 192082a6ca7SChris Cain { 193082a6ca7SChris Cain if (waitingForHost) 194082a6ca7SChris Cain { 195082a6ca7SChris Cain waitingForHost = false; 196082a6ca7SChris Cain log<level::INFO>("checkAllActiveSensors(): Host is now running"); 197082a6ca7SChris Cain } 198bae4d07eSChris Cain 199bae4d07eSChris Cain // Start with the assumption that all are available 200bae4d07eSChris Cain allActiveSensorAvailable = true; 201bae4d07eSChris Cain for (auto& obj : statusObjects) 202bae4d07eSChris Cain { 203082a6ca7SChris Cain if ((!obj->occActive()) && (!obj->getPldmSensorReceived())) 204bae4d07eSChris Cain { 205bd551de3SChris Cain auto instance = obj->getOccInstanceID(); 206bd551de3SChris Cain // Check if sensor was queued while waiting for discovery 207bd551de3SChris Cain auto match = queuedActiveState.find(instance); 208bd551de3SChris Cain if (match != queuedActiveState.end()) 209bd551de3SChris Cain { 2107f89e4d1SChris Cain queuedActiveState.erase(match); 211bd551de3SChris Cain log<level::INFO>( 21248002498SPatrick Williams std::format( 213bd551de3SChris Cain "checkAllActiveSensors(): OCC{} is ACTIVE (queued)", 214bd551de3SChris Cain instance) 215bd551de3SChris Cain .c_str()); 216bd551de3SChris Cain obj->occActive(true); 217bd551de3SChris Cain } 218bd551de3SChris Cain else 219bd551de3SChris Cain { 220bae4d07eSChris Cain allActiveSensorAvailable = false; 221bae4d07eSChris Cain if (!tracedSensorWait) 222bae4d07eSChris Cain { 223bae4d07eSChris Cain log<level::INFO>( 22448002498SPatrick Williams std::format( 225bd551de3SChris Cain "checkAllActiveSensors(): Waiting on OCC{} Active sensor", 226bd551de3SChris Cain instance) 227bae4d07eSChris Cain .c_str()); 228bae4d07eSChris Cain tracedSensorWait = true; 229755af102SChris Cain #ifdef PLDM 230c33171bbSChris Cain // Make sure PLDM traces are not throttled 231755af102SChris Cain pldmHandle->setTraceThrottle(false); 232c33171bbSChris Cain // Start timer to throttle PLDM traces when timer 233755af102SChris Cain // expires 234c33171bbSChris Cain onPldmTimeoutCreatePel = false; 235c33171bbSChris Cain throttlePldmTraceTimer->restartOnce(5min); 236755af102SChris Cain #endif 237bae4d07eSChris Cain } 238fb0a5c3cSPatrick Williams #ifdef PLDM 239bae4d07eSChris Cain pldmHandle->checkActiveSensor(obj->getOccInstanceID()); 240fb0a5c3cSPatrick Williams #endif 241bae4d07eSChris Cain break; 242bae4d07eSChris Cain } 243bae4d07eSChris Cain } 244bd551de3SChris Cain } 2457f89e4d1SChris Cain } 246082a6ca7SChris Cain else 247082a6ca7SChris Cain { 248082a6ca7SChris Cain if (!waitingForHost) 249082a6ca7SChris Cain { 250082a6ca7SChris Cain waitingForHost = true; 251082a6ca7SChris Cain log<level::INFO>( 252082a6ca7SChris Cain "checkAllActiveSensors(): Waiting for host to start"); 2537651c06bSChris Cain #ifdef PLDM 254c33171bbSChris Cain if (throttlePldmTraceTimer->isEnabled()) 2557651c06bSChris Cain { 2567651c06bSChris Cain // Host is no longer running, disable throttle timer and 2577651c06bSChris Cain // make sure traces are not throttled 2587651c06bSChris Cain log<level::INFO>( 2597651c06bSChris Cain "checkAllActiveSensors(): disabling sensor timer"); 260c33171bbSChris Cain throttlePldmTraceTimer->setEnabled(false); 2617651c06bSChris Cain pldmHandle->setTraceThrottle(false); 2627651c06bSChris Cain } 2637651c06bSChris Cain #endif 264082a6ca7SChris Cain } 265082a6ca7SChris Cain } 266bae4d07eSChris Cain 267bae4d07eSChris Cain if (allActiveSensorAvailable) 268bae4d07eSChris Cain { 269bae4d07eSChris Cain // All sensors were found, disable the discovery timer 2707f89e4d1SChris Cain if (discoverTimer->isEnabled()) 2717f89e4d1SChris Cain { 272f55f91acSChris Cain discoverTimer->setEnabled(false); 2737f89e4d1SChris Cain } 274755af102SChris Cain #ifdef PLDM 275c33171bbSChris Cain if (throttlePldmTraceTimer->isEnabled()) 276755af102SChris Cain { 277755af102SChris Cain // Disable throttle timer and make sure traces are not throttled 278c33171bbSChris Cain throttlePldmTraceTimer->setEnabled(false); 279755af102SChris Cain pldmHandle->setTraceThrottle(false); 280755af102SChris Cain } 281755af102SChris Cain #endif 2827f89e4d1SChris Cain if (waitingForAllOccActiveSensors) 2837f89e4d1SChris Cain { 284bae4d07eSChris Cain log<level::INFO>( 285bd551de3SChris Cain "checkAllActiveSensors(): OCC Active sensors are available"); 2867f89e4d1SChris Cain waitingForAllOccActiveSensors = false; 2877f89e4d1SChris Cain } 2887f89e4d1SChris Cain queuedActiveState.clear(); 289bae4d07eSChris Cain tracedSensorWait = false; 290bae4d07eSChris Cain } 291bae4d07eSChris Cain else 292bae4d07eSChris Cain { 293bae4d07eSChris Cain // Not all sensors were available, so keep waiting 294bae4d07eSChris Cain if (!tracedSensorWait) 295bae4d07eSChris Cain { 296bae4d07eSChris Cain log<level::INFO>( 297bd551de3SChris Cain "checkAllActiveSensors(): Waiting for OCC Active sensors to become available"); 298bae4d07eSChris Cain tracedSensorWait = true; 299bae4d07eSChris Cain } 300bd551de3SChris Cain discoverTimer->restartOnce(10s); 301bae4d07eSChris Cain } 302bae4d07eSChris Cain } 303bae4d07eSChris Cain #endif 304bae4d07eSChris Cain 305d267cec2SMatt Spinler std::vector<int> Manager::findOCCsInDev() 306d267cec2SMatt Spinler { 307d267cec2SMatt Spinler std::vector<int> occs; 308d267cec2SMatt Spinler std::regex expr{R"(occ(\d+)$)"}; 309d267cec2SMatt Spinler 310d267cec2SMatt Spinler for (auto& file : fs::directory_iterator("/dev")) 311d267cec2SMatt Spinler { 312d267cec2SMatt Spinler std::smatch match; 313d267cec2SMatt Spinler std::string path{file.path().string()}; 314d267cec2SMatt Spinler if (std::regex_search(path, match, expr)) 315d267cec2SMatt Spinler { 316d267cec2SMatt Spinler auto num = std::stoi(match[1].str()); 317d267cec2SMatt Spinler 318d267cec2SMatt Spinler // /dev numbering starts at 1, ours starts at 0. 319d267cec2SMatt Spinler occs.push_back(num - 1); 320d267cec2SMatt Spinler } 321d267cec2SMatt Spinler } 322d267cec2SMatt Spinler 323d267cec2SMatt Spinler return occs; 324dfc7ec73SVishwanatha Subbanna } 325dfc7ec73SVishwanatha Subbanna 326af40808fSPatrick Williams int Manager::cpuCreated(sdbusplus::message_t& msg) 327dfc7ec73SVishwanatha Subbanna { 328bcef3b48SGeorge Liu namespace fs = std::filesystem; 329dfc7ec73SVishwanatha Subbanna 330dfc7ec73SVishwanatha Subbanna sdbusplus::message::object_path o; 331dfc7ec73SVishwanatha Subbanna msg.read(o); 332dfc7ec73SVishwanatha Subbanna fs::path cpuPath(std::string(std::move(o))); 333dfc7ec73SVishwanatha Subbanna 334dfc7ec73SVishwanatha Subbanna auto name = cpuPath.filename().string(); 335dfc7ec73SVishwanatha Subbanna auto index = name.find(CPU_NAME); 336dfc7ec73SVishwanatha Subbanna name.replace(index, std::strlen(CPU_NAME), OCC_NAME); 337dfc7ec73SVishwanatha Subbanna 338dfc7ec73SVishwanatha Subbanna createObjects(name); 339dfc7ec73SVishwanatha Subbanna 340dfc7ec73SVishwanatha Subbanna return 0; 341dfc7ec73SVishwanatha Subbanna } 342dfc7ec73SVishwanatha Subbanna 343dfc7ec73SVishwanatha Subbanna void Manager::createObjects(const std::string& occ) 344dfc7ec73SVishwanatha Subbanna { 345dfc7ec73SVishwanatha Subbanna auto path = fs::path(OCC_CONTROL_ROOT) / occ; 346dfc7ec73SVishwanatha Subbanna 34794df8c90SGunnar Mills statusObjects.emplace_back(std::make_unique<Status>( 348f3b7514eSGeorge Liu event, path.c_str(), *this, 34936f9cdedSChris Cain #ifdef POWER10 35036f9cdedSChris Cain pmode, 35136f9cdedSChris Cain #endif 35294df8c90SGunnar Mills std::bind(std::mem_fn(&Manager::statusCallBack), this, 353373af757SSheldon Bailey std::placeholders::_1, std::placeholders::_2) 35400325238STom Joseph #ifdef PLDM 35500325238STom Joseph , 35600325238STom Joseph std::bind(std::mem_fn(&pldm::Interface::resetOCC), pldmHandle.get(), 35700325238STom Joseph std::placeholders::_1) 35800325238STom Joseph #endif 35900325238STom Joseph )); 360dfc7ec73SVishwanatha Subbanna 36140501a23SChris Cain // Create the power cap monitor object 36240501a23SChris Cain if (!pcap) 36340501a23SChris Cain { 36440501a23SChris Cain pcap = std::make_unique<open_power::occ::powercap::PowerCap>( 36540501a23SChris Cain *statusObjects.back()); 36640501a23SChris Cain } 36740501a23SChris Cain 36836f9cdedSChris Cain if (statusObjects.back()->isMasterOcc()) 36936f9cdedSChris Cain { 37036f9cdedSChris Cain log<level::INFO>( 37148002498SPatrick Williams std::format("Manager::createObjects(): OCC{} is the master", 37236f9cdedSChris Cain statusObjects.back()->getOccInstanceID()) 37336f9cdedSChris Cain .c_str()); 37436f9cdedSChris Cain _pollTimer->setEnabled(false); 37536f9cdedSChris Cain 37678e86012SChris Cain #ifdef POWER10 3776fa848a9SChris Cain // Set the master OCC on the PowerMode object 3786fa848a9SChris Cain pmode->setMasterOcc(path); 37978e86012SChris Cain #endif 380dfc7ec73SVishwanatha Subbanna } 381dfc7ec73SVishwanatha Subbanna 382*d7542c83SPatrick Williams passThroughObjects.emplace_back(std::make_unique<PassThrough>( 383*d7542c83SPatrick Williams path.c_str() 38436f9cdedSChris Cain #ifdef POWER10 38536f9cdedSChris Cain , 38636f9cdedSChris Cain pmode 38736f9cdedSChris Cain #endif 38836f9cdedSChris Cain )); 38936f9cdedSChris Cain } 39036f9cdedSChris Cain 391373af757SSheldon Bailey void Manager::statusCallBack(instanceID instance, bool status) 392dfc7ec73SVishwanatha Subbanna { 393a7b74dc3SChris Cain if (status == true) 394a7b74dc3SChris Cain { 395a7b74dc3SChris Cain // OCC went active 396a7b74dc3SChris Cain ++activeCount; 397dae2d940SEddie James 398a7b74dc3SChris Cain #ifdef POWER10 399a7b74dc3SChris Cain if (activeCount == 1) 400a7b74dc3SChris Cain { 401a7b74dc3SChris Cain // First OCC went active (allow some time for all OCCs to go active) 402bd551de3SChris Cain waitForAllOccsTimer->restartOnce(60s); 403a7b74dc3SChris Cain } 404a7b74dc3SChris Cain #endif 405a7b74dc3SChris Cain 406dae2d940SEddie James if (activeCount == statusObjects.size()) 407dae2d940SEddie James { 408a7b74dc3SChris Cain #ifdef POWER10 409a7b74dc3SChris Cain // All OCCs are now running 410a7b74dc3SChris Cain if (waitForAllOccsTimer->isEnabled()) 411dae2d940SEddie James { 412a7b74dc3SChris Cain // stop occ wait timer 413a7b74dc3SChris Cain waitForAllOccsTimer->setEnabled(false); 414dae2d940SEddie James } 415a7b74dc3SChris Cain #endif 416a7b74dc3SChris Cain 417a7b74dc3SChris Cain // Verify master OCC and start presence monitor 418a7b74dc3SChris Cain validateOccMaster(); 419dae2d940SEddie James } 420a8857c50SChris Cain 421a7b74dc3SChris Cain // Start poll timer if not already started 422a7b74dc3SChris Cain if (!_pollTimer->isEnabled()) 423a8857c50SChris Cain { 424b5ca1015SGeorge Liu log<level::INFO>( 42548002498SPatrick Williams std::format("Manager: OCCs will be polled every {} seconds", 42636f9cdedSChris Cain pollInterval) 427a8857c50SChris Cain .c_str()); 428a8857c50SChris Cain 429a8857c50SChris Cain // Send poll and start OCC poll timer 430a8857c50SChris Cain pollerTimerExpired(); 431a8857c50SChris Cain } 432a7b74dc3SChris Cain } 433a7b74dc3SChris Cain else 434a8857c50SChris Cain { 435a7b74dc3SChris Cain // OCC went away 436082a6ca7SChris Cain if (activeCount > 0) 437082a6ca7SChris Cain { 438a7b74dc3SChris Cain --activeCount; 439082a6ca7SChris Cain } 440082a6ca7SChris Cain else 441082a6ca7SChris Cain { 442082a6ca7SChris Cain log<level::ERR>( 44348002498SPatrick Williams std::format("OCC{} disabled, but currently no active OCCs", 444082a6ca7SChris Cain instance) 445082a6ca7SChris Cain .c_str()); 446082a6ca7SChris Cain } 447a7b74dc3SChris Cain 448a7b74dc3SChris Cain if (activeCount == 0) 449a7b74dc3SChris Cain { 450a7b74dc3SChris Cain // No OCCs are running 451a7b74dc3SChris Cain 452a8857c50SChris Cain // Stop OCC poll timer 453a7b74dc3SChris Cain if (_pollTimer->isEnabled()) 454a7b74dc3SChris Cain { 455b5ca1015SGeorge Liu log<level::INFO>( 456b5ca1015SGeorge Liu "Manager::statusCallBack(): OCCs are not running, stopping poll timer"); 457a8857c50SChris Cain _pollTimer->setEnabled(false); 458a7b74dc3SChris Cain } 459a7b74dc3SChris Cain 460a7b74dc3SChris Cain #ifdef POWER10 461a7b74dc3SChris Cain // stop wait timer 462a7b74dc3SChris Cain if (waitForAllOccsTimer->isEnabled()) 463a7b74dc3SChris Cain { 464a7b74dc3SChris Cain waitForAllOccsTimer->setEnabled(false); 465a7b74dc3SChris Cain } 466a7b74dc3SChris Cain #endif 467373af757SSheldon Bailey } 46853f68148SMatt Spinler #ifdef READ_OCC_SENSORS 469a7b74dc3SChris Cain // Clear OCC sensors 470c8dd4599SSheldon Bailey setSensorValueToNaN(instance); 47153f68148SMatt Spinler #endif 472a8857c50SChris Cain } 473bae4d07eSChris Cain 474bae4d07eSChris Cain #ifdef POWER10 475bae4d07eSChris Cain if (waitingForAllOccActiveSensors) 476bae4d07eSChris Cain { 4776d8f37a2SChris Cain if (utils::isHostRunning()) 4786d8f37a2SChris Cain { 479bae4d07eSChris Cain checkAllActiveSensors(); 480bae4d07eSChris Cain } 4816d8f37a2SChris Cain } 482bae4d07eSChris Cain #endif 483dfc7ec73SVishwanatha Subbanna } 484dfc7ec73SVishwanatha Subbanna 485dfc7ec73SVishwanatha Subbanna #ifdef I2C_OCC 486dfc7ec73SVishwanatha Subbanna void Manager::initStatusObjects() 487dfc7ec73SVishwanatha Subbanna { 488dfc7ec73SVishwanatha Subbanna // Make sure we have a valid path string 489dfc7ec73SVishwanatha Subbanna static_assert(sizeof(DEV_PATH) != 0); 490dfc7ec73SVishwanatha Subbanna 491dfc7ec73SVishwanatha Subbanna auto deviceNames = i2c_occ::getOccHwmonDevices(DEV_PATH); 492dfc7ec73SVishwanatha Subbanna for (auto& name : deviceNames) 493dfc7ec73SVishwanatha Subbanna { 494dfc7ec73SVishwanatha Subbanna i2c_occ::i2cToDbus(name); 495b5259a1eSLei YU name = std::string(OCC_NAME) + '_' + name; 496dfc7ec73SVishwanatha Subbanna auto path = fs::path(OCC_CONTROL_ROOT) / name; 497dfc7ec73SVishwanatha Subbanna statusObjects.emplace_back( 498f3b7514eSGeorge Liu std::make_unique<Status>(event, path.c_str(), *this)); 499dfc7ec73SVishwanatha Subbanna } 50040501a23SChris Cain // The first device is master occ 50140501a23SChris Cain pcap = std::make_unique<open_power::occ::powercap::PowerCap>( 50240501a23SChris Cain *statusObjects.front()); 50378e86012SChris Cain #ifdef POWER10 5045d66a0aaSChris Cain pmode = std::make_unique<powermode::PowerMode>(*this, powermode::PMODE_PATH, 5055d66a0aaSChris Cain powermode::PIPS_PATH); 5066fa848a9SChris Cain // Set the master OCC on the PowerMode object 5076fa848a9SChris Cain pmode->setMasterOcc(path); 50878e86012SChris Cain #endif 509dfc7ec73SVishwanatha Subbanna } 510dfc7ec73SVishwanatha Subbanna #endif 511dfc7ec73SVishwanatha Subbanna 512815f9f55STom Joseph #ifdef PLDM 513cbad219eSEddie James void Manager::sbeTimeout(unsigned int instance) 514cbad219eSEddie James { 5152a751d70SEddie James auto obj = std::find_if(statusObjects.begin(), statusObjects.end(), 5162a751d70SEddie James [instance](const auto& obj) { 5172a751d70SEddie James return instance == obj->getOccInstanceID(); 5182a751d70SEddie James }); 5192a751d70SEddie James 520cb018dafSEddie James if (obj != statusObjects.end() && (*obj)->occActive()) 5212a751d70SEddie James { 522bae4d07eSChris Cain log<level::INFO>( 52348002498SPatrick Williams std::format("SBE timeout, requesting HRESET (OCC{})", instance) 524bae4d07eSChris Cain .c_str()); 525cbad219eSEddie James 526cbad219eSEddie James setSBEState(instance, SBE_STATE_NOT_USABLE); 527cbad219eSEddie James 528cbad219eSEddie James pldmHandle->sendHRESET(instance); 529cbad219eSEddie James } 5302a751d70SEddie James } 531cbad219eSEddie James 532815f9f55STom Joseph bool Manager::updateOCCActive(instanceID instance, bool status) 533815f9f55STom Joseph { 5347e374fb4SChris Cain auto obj = std::find_if(statusObjects.begin(), statusObjects.end(), 5357e374fb4SChris Cain [instance](const auto& obj) { 5367e374fb4SChris Cain return instance == obj->getOccInstanceID(); 5377e374fb4SChris Cain }); 5387e374fb4SChris Cain 539082a6ca7SChris Cain const bool hostRunning = open_power::occ::utils::isHostRunning(); 5407e374fb4SChris Cain if (obj != statusObjects.end()) 5417e374fb4SChris Cain { 542082a6ca7SChris Cain if (!hostRunning && (status == true)) 5437e374fb4SChris Cain { 5447e374fb4SChris Cain log<level::WARNING>( 54548002498SPatrick Williams std::format( 546082a6ca7SChris Cain "updateOCCActive: Host is not running yet (OCC{} active={}), clearing sensor received", 5477e374fb4SChris Cain instance, status) 5487e374fb4SChris Cain .c_str()); 549082a6ca7SChris Cain (*obj)->setPldmSensorReceived(false); 550082a6ca7SChris Cain if (!waitingForAllOccActiveSensors) 551082a6ca7SChris Cain { 552082a6ca7SChris Cain log<level::INFO>( 553082a6ca7SChris Cain "updateOCCActive: Waiting for Host and all OCC Active Sensors"); 554082a6ca7SChris Cain waitingForAllOccActiveSensors = true; 555082a6ca7SChris Cain } 556755af102SChris Cain #ifdef POWER10 557082a6ca7SChris Cain discoverTimer->restartOnce(30s); 558755af102SChris Cain #endif 559082a6ca7SChris Cain return false; 560082a6ca7SChris Cain } 561082a6ca7SChris Cain else 562082a6ca7SChris Cain { 56348002498SPatrick Williams log<level::INFO>(std::format("updateOCCActive: OCC{} active={}", 564082a6ca7SChris Cain instance, status) 565082a6ca7SChris Cain .c_str()); 566082a6ca7SChris Cain (*obj)->setPldmSensorReceived(true); 567082a6ca7SChris Cain return (*obj)->occActive(status); 568082a6ca7SChris Cain } 569082a6ca7SChris Cain } 570082a6ca7SChris Cain else 571082a6ca7SChris Cain { 572082a6ca7SChris Cain if (hostRunning) 573082a6ca7SChris Cain { 574082a6ca7SChris Cain log<level::WARNING>( 57548002498SPatrick Williams std::format( 576082a6ca7SChris Cain "updateOCCActive: No status object to update for OCC{} (active={})", 577082a6ca7SChris Cain instance, status) 578082a6ca7SChris Cain .c_str()); 579082a6ca7SChris Cain } 580082a6ca7SChris Cain else 581082a6ca7SChris Cain { 582082a6ca7SChris Cain if (status == true) 583082a6ca7SChris Cain { 584082a6ca7SChris Cain log<level::WARNING>( 58548002498SPatrick Williams std::format( 586082a6ca7SChris Cain "updateOCCActive: No status objects and Host is not running yet (OCC{} active={})", 587082a6ca7SChris Cain instance, status) 588082a6ca7SChris Cain .c_str()); 589082a6ca7SChris Cain } 590082a6ca7SChris Cain } 591bd551de3SChris Cain if (status == true) 592bd551de3SChris Cain { 593bd551de3SChris Cain // OCC went active 594bd551de3SChris Cain queuedActiveState.insert(instance); 595bd551de3SChris Cain } 596bd551de3SChris Cain else 597bd551de3SChris Cain { 598bd551de3SChris Cain auto match = queuedActiveState.find(instance); 599bd551de3SChris Cain if (match != queuedActiveState.end()) 600bd551de3SChris Cain { 601bd551de3SChris Cain // OCC was disabled 602bd551de3SChris Cain queuedActiveState.erase(match); 603bd551de3SChris Cain } 604bd551de3SChris Cain } 6057e374fb4SChris Cain return false; 6067e374fb4SChris Cain } 607815f9f55STom Joseph } 608cbad219eSEddie James 60931a2f13aSSheldon Bailey // Called upon pldm event To set powermode Safe Mode State for system. 61031a2f13aSSheldon Bailey void Manager::updateOccSafeMode(bool safeMode) 61131a2f13aSSheldon Bailey { 61231a2f13aSSheldon Bailey #ifdef POWER10 61331a2f13aSSheldon Bailey pmode->updateDbusSafeMode(safeMode); 61431a2f13aSSheldon Bailey #endif 615c86d80faSChris Cain // Update the processor throttle status on dbus 616c86d80faSChris Cain for (auto& obj : statusObjects) 617c86d80faSChris Cain { 618c86d80faSChris Cain obj->updateThrottle(safeMode, THROTTLED_SAFE); 619c86d80faSChris Cain } 62031a2f13aSSheldon Bailey } 62131a2f13aSSheldon Bailey 622cbad219eSEddie James void Manager::sbeHRESETResult(instanceID instance, bool success) 623cbad219eSEddie James { 624cbad219eSEddie James if (success) 625cbad219eSEddie James { 626bae4d07eSChris Cain log<level::INFO>( 62748002498SPatrick Williams std::format("HRESET succeeded (OCC{})", instance).c_str()); 628cbad219eSEddie James 629cbad219eSEddie James setSBEState(instance, SBE_STATE_BOOTED); 630cbad219eSEddie James 631cbad219eSEddie James return; 632cbad219eSEddie James } 633cbad219eSEddie James 634cbad219eSEddie James setSBEState(instance, SBE_STATE_FAILED); 635cbad219eSEddie James 636cbad219eSEddie James if (sbeCanDump(instance)) 637cbad219eSEddie James { 638bae4d07eSChris Cain log<level::INFO>( 63948002498SPatrick Williams std::format("HRESET failed (OCC{}), triggering SBE dump", instance) 640bae4d07eSChris Cain .c_str()); 641cbad219eSEddie James 642cbad219eSEddie James auto& bus = utils::getBus(); 643cbad219eSEddie James uint32_t src6 = instance << 16; 644cbad219eSEddie James uint32_t logId = 645cbad219eSEddie James FFDC::createPEL("org.open_power.Processor.Error.SbeChipOpTimeout", 646cbad219eSEddie James src6, "SBE command timeout"); 647cbad219eSEddie James 648cbad219eSEddie James try 649cbad219eSEddie James { 650f3a4a69fSGeorge Liu constexpr auto interface = "xyz.openbmc_project.Dump.Create"; 651f3a4a69fSGeorge Liu constexpr auto function = "CreateDump"; 652f3a4a69fSGeorge Liu 653*d7542c83SPatrick Williams std::string service = 654*d7542c83SPatrick Williams utils::getService(OP_DUMP_OBJ_PATH, interface); 6551173b2b1SDhruvaraj Subhashchandran auto method = bus.new_method_call(service.c_str(), OP_DUMP_OBJ_PATH, 6561173b2b1SDhruvaraj Subhashchandran interface, function); 657cbad219eSEddie James 658cbad219eSEddie James std::map<std::string, std::variant<std::string, uint64_t>> 659cbad219eSEddie James createParams{ 660cbad219eSEddie James {"com.ibm.Dump.Create.CreateParameters.ErrorLogId", 661cbad219eSEddie James uint64_t(logId)}, 662cbad219eSEddie James {"com.ibm.Dump.Create.CreateParameters.DumpType", 663cbad219eSEddie James "com.ibm.Dump.Create.DumpType.SBE"}, 664cbad219eSEddie James {"com.ibm.Dump.Create.CreateParameters.FailingUnitId", 665cbad219eSEddie James uint64_t(instance)}, 666cbad219eSEddie James }; 667cbad219eSEddie James 668cbad219eSEddie James method.append(createParams); 669cbad219eSEddie James 670cbad219eSEddie James auto response = bus.call(method); 671cbad219eSEddie James } 672af40808fSPatrick Williams catch (const sdbusplus::exception_t& e) 673cbad219eSEddie James { 674cbad219eSEddie James constexpr auto ERROR_DUMP_DISABLED = 675cbad219eSEddie James "xyz.openbmc_project.Dump.Create.Error.Disabled"; 676cbad219eSEddie James if (e.name() == ERROR_DUMP_DISABLED) 677cbad219eSEddie James { 678cbad219eSEddie James log<level::INFO>("Dump is disabled, skipping"); 679cbad219eSEddie James } 680cbad219eSEddie James else 681cbad219eSEddie James { 682cbad219eSEddie James log<level::ERR>("Dump failed"); 683cbad219eSEddie James } 684cbad219eSEddie James } 685cbad219eSEddie James } 686cbad219eSEddie James } 687cbad219eSEddie James 688cbad219eSEddie James bool Manager::sbeCanDump(unsigned int instance) 689cbad219eSEddie James { 690cbad219eSEddie James struct pdbg_target* proc = getPdbgTarget(instance); 691cbad219eSEddie James 692cbad219eSEddie James if (!proc) 693cbad219eSEddie James { 694cbad219eSEddie James // allow the dump in the error case 695cbad219eSEddie James return true; 696cbad219eSEddie James } 697cbad219eSEddie James 698cbad219eSEddie James try 699cbad219eSEddie James { 700cbad219eSEddie James if (!openpower::phal::sbe::isDumpAllowed(proc)) 701cbad219eSEddie James { 702cbad219eSEddie James return false; 703cbad219eSEddie James } 704cbad219eSEddie James 705cbad219eSEddie James if (openpower::phal::pdbg::isSbeVitalAttnActive(proc)) 706cbad219eSEddie James { 707cbad219eSEddie James return false; 708cbad219eSEddie James } 709cbad219eSEddie James } 710cbad219eSEddie James catch (openpower::phal::exception::SbeError& e) 711cbad219eSEddie James { 712cbad219eSEddie James log<level::INFO>("Failed to query SBE state"); 713cbad219eSEddie James } 714cbad219eSEddie James 715cbad219eSEddie James // allow the dump in the error case 716cbad219eSEddie James return true; 717cbad219eSEddie James } 718cbad219eSEddie James 719cbad219eSEddie James void Manager::setSBEState(unsigned int instance, enum sbe_state state) 720cbad219eSEddie James { 721cbad219eSEddie James struct pdbg_target* proc = getPdbgTarget(instance); 722cbad219eSEddie James 723cbad219eSEddie James if (!proc) 724cbad219eSEddie James { 725cbad219eSEddie James return; 726cbad219eSEddie James } 727cbad219eSEddie James 728cbad219eSEddie James try 729cbad219eSEddie James { 730cbad219eSEddie James openpower::phal::sbe::setState(proc, state); 731cbad219eSEddie James } 732cbad219eSEddie James catch (const openpower::phal::exception::SbeError& e) 733cbad219eSEddie James { 734cbad219eSEddie James log<level::ERR>("Failed to set SBE state"); 735cbad219eSEddie James } 736cbad219eSEddie James } 737cbad219eSEddie James 738cbad219eSEddie James struct pdbg_target* Manager::getPdbgTarget(unsigned int instance) 739cbad219eSEddie James { 740cbad219eSEddie James if (!pdbgInitialized) 741cbad219eSEddie James { 742cbad219eSEddie James try 743cbad219eSEddie James { 744cbad219eSEddie James openpower::phal::pdbg::init(); 745cbad219eSEddie James pdbgInitialized = true; 746cbad219eSEddie James } 747cbad219eSEddie James catch (const openpower::phal::exception::PdbgError& e) 748cbad219eSEddie James { 749cbad219eSEddie James log<level::ERR>("pdbg initialization failed"); 750cbad219eSEddie James return nullptr; 751cbad219eSEddie James } 752cbad219eSEddie James } 753cbad219eSEddie James 754cbad219eSEddie James struct pdbg_target* proc = nullptr; 755cbad219eSEddie James pdbg_for_each_class_target("proc", proc) 756cbad219eSEddie James { 757cbad219eSEddie James if (pdbg_target_index(proc) == instance) 758cbad219eSEddie James { 759cbad219eSEddie James return proc; 760cbad219eSEddie James } 761cbad219eSEddie James } 762cbad219eSEddie James 763cbad219eSEddie James log<level::ERR>("Failed to get pdbg target"); 764cbad219eSEddie James return nullptr; 765cbad219eSEddie James } 766815f9f55STom Joseph #endif 767815f9f55STom Joseph 768a8857c50SChris Cain void Manager::pollerTimerExpired() 769a8857c50SChris Cain { 770a8857c50SChris Cain if (!_pollTimer) 771a8857c50SChris Cain { 772a8857c50SChris Cain log<level::ERR>( 773a8857c50SChris Cain "Manager::pollerTimerExpired() ERROR: Timer not defined"); 774a8857c50SChris Cain return; 775a8857c50SChris Cain } 776a8857c50SChris Cain 777a8857c50SChris Cain for (auto& obj : statusObjects) 778a8857c50SChris Cain { 779a7b74dc3SChris Cain if (!obj->occActive()) 780a7b74dc3SChris Cain { 781a7b74dc3SChris Cain // OCC is not running yet 782a7b74dc3SChris Cain #ifdef READ_OCC_SENSORS 7835d66a0aaSChris Cain auto id = obj->getOccInstanceID(); 784c8dd4599SSheldon Bailey setSensorValueToNaN(id); 785a7b74dc3SChris Cain #endif 786a7b74dc3SChris Cain continue; 787a7b74dc3SChris Cain } 788a7b74dc3SChris Cain 789a8857c50SChris Cain // Read sysfs to force kernel to poll OCC 790a8857c50SChris Cain obj->readOccState(); 791bb895cb8SChicago Duan 792bb895cb8SChicago Duan #ifdef READ_OCC_SENSORS 793bb895cb8SChicago Duan // Read occ sensor values 7945d66a0aaSChris Cain getSensorValues(obj); 795bb895cb8SChicago Duan #endif 796a8857c50SChris Cain } 797a8857c50SChris Cain 798a7b74dc3SChris Cain if (activeCount > 0) 799a7b74dc3SChris Cain { 800a8857c50SChris Cain // Restart OCC poll timer 801a8857c50SChris Cain _pollTimer->restartOnce(std::chrono::seconds(pollInterval)); 802a8857c50SChris Cain } 803a7b74dc3SChris Cain else 804a7b74dc3SChris Cain { 805a7b74dc3SChris Cain // No OCCs running, so poll timer will not be restarted 806a7b74dc3SChris Cain log<level::INFO>( 80748002498SPatrick Williams std::format( 808a7b74dc3SChris Cain "Manager::pollerTimerExpired: poll timer will not be restarted") 809a7b74dc3SChris Cain .c_str()); 810a7b74dc3SChris Cain } 811a7b74dc3SChris Cain } 812a8857c50SChris Cain 813bb895cb8SChicago Duan #ifdef READ_OCC_SENSORS 814ae157b68SChris Cain void Manager::readTempSensors(const fs::path& path, uint32_t occInstance) 815bb895cb8SChicago Duan { 816818cc8d7SMatt Spinler // There may be more than one sensor with the same FRU type 817818cc8d7SMatt Spinler // and label so make two passes: the first to read the temps 818818cc8d7SMatt Spinler // from sysfs, and the second to put them on D-Bus after 819818cc8d7SMatt Spinler // resolving any conflicts. 820818cc8d7SMatt Spinler std::map<std::string, double> sensorData; 821818cc8d7SMatt Spinler 822bb895cb8SChicago Duan std::regex expr{"temp\\d+_label$"}; // Example: temp5_label 823bb895cb8SChicago Duan for (auto& file : fs::directory_iterator(path)) 824bb895cb8SChicago Duan { 825bb895cb8SChicago Duan if (!std::regex_search(file.path().string(), expr)) 826bb895cb8SChicago Duan { 827bb895cb8SChicago Duan continue; 828bb895cb8SChicago Duan } 829bb895cb8SChicago Duan 830a26f1527SMatt Spinler uint32_t labelValue{0}; 831a26f1527SMatt Spinler 832a26f1527SMatt Spinler try 833a26f1527SMatt Spinler { 834a26f1527SMatt Spinler labelValue = readFile<uint32_t>(file.path()); 835a26f1527SMatt Spinler } 836a26f1527SMatt Spinler catch (const std::system_error& e) 837a26f1527SMatt Spinler { 838a26f1527SMatt Spinler log<level::DEBUG>( 83948002498SPatrick Williams std::format("readTempSensors: Failed reading {}, errno = {}", 840a26f1527SMatt Spinler file.path().string(), e.code().value()) 841a26f1527SMatt Spinler .c_str()); 842bb895cb8SChicago Duan continue; 843bb895cb8SChicago Duan } 844bb895cb8SChicago Duan 845bb895cb8SChicago Duan const std::string& tempLabel = "label"; 846bb895cb8SChicago Duan const std::string filePathString = file.path().string().substr( 847bb895cb8SChicago Duan 0, file.path().string().length() - tempLabel.length()); 848a26f1527SMatt Spinler 849a26f1527SMatt Spinler uint32_t fruTypeValue{0}; 850a26f1527SMatt Spinler try 851bb895cb8SChicago Duan { 852a26f1527SMatt Spinler fruTypeValue = readFile<uint32_t>(filePathString + fruTypeSuffix); 853a26f1527SMatt Spinler } 854a26f1527SMatt Spinler catch (const std::system_error& e) 855a26f1527SMatt Spinler { 856bb895cb8SChicago Duan log<level::DEBUG>( 85748002498SPatrick Williams std::format("readTempSensors: Failed reading {}, errno = {}", 858a26f1527SMatt Spinler filePathString + fruTypeSuffix, e.code().value()) 859bb895cb8SChicago Duan .c_str()); 860bb895cb8SChicago Duan continue; 861bb895cb8SChicago Duan } 862bb895cb8SChicago Duan 863*d7542c83SPatrick Williams std::string sensorPath = 864*d7542c83SPatrick Williams OCC_SENSORS_ROOT + std::string("/temperature/"); 865bb895cb8SChicago Duan 866ace67d85SMatt Spinler std::string dvfsTempPath; 867ace67d85SMatt Spinler 868bb895cb8SChicago Duan if (fruTypeValue == VRMVdd) 869bb895cb8SChicago Duan { 870*d7542c83SPatrick Williams sensorPath.append( 871*d7542c83SPatrick Williams "vrm_vdd" + std::to_string(occInstance) + "_temp"); 872bb895cb8SChicago Duan } 873ace67d85SMatt Spinler else if (fruTypeValue == processorIoRing) 874ace67d85SMatt Spinler { 875*d7542c83SPatrick Williams sensorPath.append( 876*d7542c83SPatrick Williams "proc" + std::to_string(occInstance) + "_ioring_temp"); 877ace67d85SMatt Spinler dvfsTempPath = std::string{OCC_SENSORS_ROOT} + "/temperature/proc" + 878ae157b68SChris Cain std::to_string(occInstance) + "_ioring_dvfs_temp"; 879ace67d85SMatt Spinler } 880bb895cb8SChicago Duan else 881bb895cb8SChicago Duan { 88214d1402dSMatt Spinler uint16_t type = (labelValue & 0xFF000000) >> 24; 88314d1402dSMatt Spinler uint16_t instanceID = labelValue & 0x0000FFFF; 884bb895cb8SChicago Duan 885bb895cb8SChicago Duan if (type == OCC_DIMM_TEMP_SENSOR_TYPE) 886bb895cb8SChicago Duan { 8878b8abeedSMatt Spinler if (fruTypeValue == fruTypeNotAvailable) 8888b8abeedSMatt Spinler { 8898b8abeedSMatt Spinler // Not all DIMM related temps are available to read 8908b8abeedSMatt Spinler // (no _input file in this case) 8918b8abeedSMatt Spinler continue; 8928b8abeedSMatt Spinler } 893bb895cb8SChicago Duan auto iter = dimmTempSensorName.find(fruTypeValue); 894bb895cb8SChicago Duan if (iter == dimmTempSensorName.end()) 895bb895cb8SChicago Duan { 896b5ca1015SGeorge Liu log<level::ERR>( 89748002498SPatrick Williams std::format( 898b5ca1015SGeorge Liu "readTempSensors: Fru type error! fruTypeValue = {}) ", 899bb895cb8SChicago Duan fruTypeValue) 900bb895cb8SChicago Duan .c_str()); 901bb895cb8SChicago Duan continue; 902bb895cb8SChicago Duan } 903bb895cb8SChicago Duan 904*d7542c83SPatrick Williams sensorPath.append( 905*d7542c83SPatrick Williams "dimm" + std::to_string(instanceID) + iter->second); 906ad8f4524SMatt Spinler 907ad8f4524SMatt Spinler dvfsTempPath = std::string{OCC_SENSORS_ROOT} + "/temperature/" + 908ad8f4524SMatt Spinler dimmDVFSSensorName.at(fruTypeValue); 909bb895cb8SChicago Duan } 910bb895cb8SChicago Duan else if (type == OCC_CPU_TEMP_SENSOR_TYPE) 911bb895cb8SChicago Duan { 912ace67d85SMatt Spinler if (fruTypeValue == processorCore) 913bb895cb8SChicago Duan { 914ff7afd98SMatt Spinler // The OCC reports small core temps, of which there are 915ff7afd98SMatt Spinler // two per big core. All current P10 systems are in big 916ff7afd98SMatt Spinler // core mode, so use a big core name. 917ff7afd98SMatt Spinler uint16_t coreNum = instanceID / 2; 918ff7afd98SMatt Spinler uint16_t tempNum = instanceID % 2; 919ae157b68SChris Cain sensorPath.append("proc" + std::to_string(occInstance) + 920ae157b68SChris Cain "_core" + std::to_string(coreNum) + "_" + 921ff7afd98SMatt Spinler std::to_string(tempNum) + "_temp"); 922ace67d85SMatt Spinler 923ae157b68SChris Cain dvfsTempPath = 924ae157b68SChris Cain std::string{OCC_SENSORS_ROOT} + "/temperature/proc" + 925ae157b68SChris Cain std::to_string(occInstance) + "_core_dvfs_temp"; 926bb895cb8SChicago Duan } 927bb895cb8SChicago Duan else 928bb895cb8SChicago Duan { 929bb895cb8SChicago Duan continue; 930bb895cb8SChicago Duan } 931bb895cb8SChicago Duan } 932ace67d85SMatt Spinler else 933ace67d85SMatt Spinler { 934ace67d85SMatt Spinler continue; 935ace67d85SMatt Spinler } 936ace67d85SMatt Spinler } 937ace67d85SMatt Spinler 938ace67d85SMatt Spinler // The dvfs temp file only needs to be read once per chip per type. 939ace67d85SMatt Spinler if (!dvfsTempPath.empty() && 940ace67d85SMatt Spinler !dbus::OccDBusSensors::getOccDBus().hasDvfsTemp(dvfsTempPath)) 941ace67d85SMatt Spinler { 942ace67d85SMatt Spinler try 943ace67d85SMatt Spinler { 944ace67d85SMatt Spinler auto dvfsValue = readFile<double>(filePathString + maxSuffix); 945ace67d85SMatt Spinler 946ace67d85SMatt Spinler dbus::OccDBusSensors::getOccDBus().setDvfsTemp( 947ace67d85SMatt Spinler dvfsTempPath, dvfsValue * std::pow(10, -3)); 948ace67d85SMatt Spinler } 949ace67d85SMatt Spinler catch (const std::system_error& e) 950ace67d85SMatt Spinler { 951ace67d85SMatt Spinler log<level::DEBUG>( 95248002498SPatrick Williams std::format( 953ace67d85SMatt Spinler "readTempSensors: Failed reading {}, errno = {}", 954ace67d85SMatt Spinler filePathString + maxSuffix, e.code().value()) 955ace67d85SMatt Spinler .c_str()); 956ace67d85SMatt Spinler } 957ace67d85SMatt Spinler } 958bb895cb8SChicago Duan 959a26f1527SMatt Spinler uint32_t faultValue{0}; 960a26f1527SMatt Spinler try 961bb895cb8SChicago Duan { 962a26f1527SMatt Spinler faultValue = readFile<uint32_t>(filePathString + faultSuffix); 963a26f1527SMatt Spinler } 964a26f1527SMatt Spinler catch (const std::system_error& e) 965a26f1527SMatt Spinler { 966a26f1527SMatt Spinler log<level::DEBUG>( 96748002498SPatrick Williams std::format("readTempSensors: Failed reading {}, errno = {}", 968a26f1527SMatt Spinler filePathString + faultSuffix, e.code().value()) 969a26f1527SMatt Spinler .c_str()); 970a26f1527SMatt Spinler continue; 971a26f1527SMatt Spinler } 972bb895cb8SChicago Duan 973ae157b68SChris Cain double tempValue{0}; 974ae157b68SChris Cain // NOTE: if OCC sends back 0xFF, kernal sets this fault value to 1. 975bb895cb8SChicago Duan if (faultValue != 0) 976bb895cb8SChicago Duan { 977ae157b68SChris Cain tempValue = std::numeric_limits<double>::quiet_NaN(); 978ae157b68SChris Cain } 979ae157b68SChris Cain else 980818cc8d7SMatt Spinler { 981ae157b68SChris Cain // Read the temperature 982a26f1527SMatt Spinler try 983bb895cb8SChicago Duan { 984a26f1527SMatt Spinler tempValue = readFile<double>(filePathString + inputSuffix); 985a26f1527SMatt Spinler } 986a26f1527SMatt Spinler catch (const std::system_error& e) 987a26f1527SMatt Spinler { 988a26f1527SMatt Spinler log<level::DEBUG>( 98948002498SPatrick Williams std::format( 990ae157b68SChris Cain "readTempSensors: Failed reading {}, errno = {}", 991a26f1527SMatt Spinler filePathString + inputSuffix, e.code().value()) 992a26f1527SMatt Spinler .c_str()); 993cd0940b5SSheldon Bailey 994cd0940b5SSheldon Bailey // if errno == EAGAIN(Resource temporarily unavailable) then set 995ae157b68SChris Cain // temp to 0, to avoid using old temp, and affecting FAN 996ae157b68SChris Cain // Control. 997cd0940b5SSheldon Bailey if (e.code().value() == EAGAIN) 998cd0940b5SSheldon Bailey { 999cd0940b5SSheldon Bailey tempValue = 0; 1000cd0940b5SSheldon Bailey } 1001cd0940b5SSheldon Bailey // else the errno would be something like 1002cd0940b5SSheldon Bailey // EBADF(Bad file descriptor) 1003cd0940b5SSheldon Bailey // or ENOENT(No such file or directory) 1004cd0940b5SSheldon Bailey else 1005cd0940b5SSheldon Bailey { 1006a26f1527SMatt Spinler continue; 1007a26f1527SMatt Spinler } 1008cd0940b5SSheldon Bailey } 1009ae157b68SChris Cain } 1010bb895cb8SChicago Duan 1011818cc8d7SMatt Spinler // If this object path already has a value, only overwite 1012818cc8d7SMatt Spinler // it if the previous one was an NaN or a smaller value. 1013818cc8d7SMatt Spinler auto existing = sensorData.find(sensorPath); 1014818cc8d7SMatt Spinler if (existing != sensorData.end()) 1015818cc8d7SMatt Spinler { 1016ae157b68SChris Cain // Multiple sensors found for this FRU type 1017ae157b68SChris Cain if ((std::isnan(existing->second) && (tempValue == 0)) || 1018ae157b68SChris Cain ((existing->second == 0) && std::isnan(tempValue))) 1019ae157b68SChris Cain { 1020ae157b68SChris Cain // One of the redundant sensors has failed (0xFF/nan), and the 1021ae157b68SChris Cain // other sensor has no reading (0), so set the FRU to NaN to 1022ae157b68SChris Cain // force fan increase 1023ae157b68SChris Cain tempValue = std::numeric_limits<double>::quiet_NaN(); 1024ae157b68SChris Cain existing->second = tempValue; 1025ae157b68SChris Cain } 1026818cc8d7SMatt Spinler if (std::isnan(existing->second) || (tempValue > existing->second)) 1027818cc8d7SMatt Spinler { 1028818cc8d7SMatt Spinler existing->second = tempValue; 1029818cc8d7SMatt Spinler } 1030818cc8d7SMatt Spinler } 1031818cc8d7SMatt Spinler else 1032818cc8d7SMatt Spinler { 1033ae157b68SChris Cain // First sensor for this FRU type 1034818cc8d7SMatt Spinler sensorData[sensorPath] = tempValue; 1035818cc8d7SMatt Spinler } 1036818cc8d7SMatt Spinler } 1037bb895cb8SChicago Duan 1038818cc8d7SMatt Spinler // Now publish the values on D-Bus. 1039818cc8d7SMatt Spinler for (const auto& [objectPath, value] : sensorData) 1040818cc8d7SMatt Spinler { 1041818cc8d7SMatt Spinler dbus::OccDBusSensors::getOccDBus().setValue(objectPath, 1042818cc8d7SMatt Spinler value * std::pow(10, -3)); 1043bb895cb8SChicago Duan 1044818cc8d7SMatt Spinler dbus::OccDBusSensors::getOccDBus().setOperationalStatus( 1045818cc8d7SMatt Spinler objectPath, !std::isnan(value)); 1046818cc8d7SMatt Spinler 1047818cc8d7SMatt Spinler if (existingSensors.find(objectPath) == existingSensors.end()) 10486fa848a9SChris Cain { 10495d66a0aaSChris Cain dbus::OccDBusSensors::getOccDBus().setChassisAssociation( 1050818cc8d7SMatt Spinler objectPath); 10516fa848a9SChris Cain } 10526fa848a9SChris Cain 1053ae157b68SChris Cain existingSensors[objectPath] = occInstance; 1054bb895cb8SChicago Duan } 1055bb895cb8SChicago Duan } 1056bb895cb8SChicago Duan 1057bb895cb8SChicago Duan std::optional<std::string> 1058bb895cb8SChicago Duan Manager::getPowerLabelFunctionID(const std::string& value) 1059bb895cb8SChicago Duan { 1060bb895cb8SChicago Duan // If the value is "system", then the FunctionID is "system". 1061bb895cb8SChicago Duan if (value == "system") 1062bb895cb8SChicago Duan { 1063bb895cb8SChicago Duan return value; 1064bb895cb8SChicago Duan } 1065bb895cb8SChicago Duan 1066bb895cb8SChicago Duan // If the value is not "system", then the label value have 3 numbers, of 1067bb895cb8SChicago Duan // which we only care about the middle one: 1068bb895cb8SChicago Duan // <sensor id>_<function id>_<apss channel> 1069bb895cb8SChicago Duan // eg: The value is "0_10_5" , then the FunctionID is "10". 1070bb895cb8SChicago Duan if (value.find("_") == std::string::npos) 1071bb895cb8SChicago Duan { 1072bb895cb8SChicago Duan return std::nullopt; 1073bb895cb8SChicago Duan } 1074bb895cb8SChicago Duan 1075bb895cb8SChicago Duan auto powerLabelValue = value.substr((value.find("_") + 1)); 1076bb895cb8SChicago Duan 1077bb895cb8SChicago Duan if (powerLabelValue.find("_") == std::string::npos) 1078bb895cb8SChicago Duan { 1079bb895cb8SChicago Duan return std::nullopt; 1080bb895cb8SChicago Duan } 1081bb895cb8SChicago Duan 1082bb895cb8SChicago Duan return powerLabelValue.substr(0, powerLabelValue.find("_")); 1083bb895cb8SChicago Duan } 1084bb895cb8SChicago Duan 1085bb895cb8SChicago Duan void Manager::readPowerSensors(const fs::path& path, uint32_t id) 1086bb895cb8SChicago Duan { 1087bb895cb8SChicago Duan std::regex expr{"power\\d+_label$"}; // Example: power5_label 1088bb895cb8SChicago Duan for (auto& file : fs::directory_iterator(path)) 1089bb895cb8SChicago Duan { 1090bb895cb8SChicago Duan if (!std::regex_search(file.path().string(), expr)) 1091bb895cb8SChicago Duan { 1092bb895cb8SChicago Duan continue; 1093bb895cb8SChicago Duan } 1094bb895cb8SChicago Duan 1095a26f1527SMatt Spinler std::string labelValue; 1096a26f1527SMatt Spinler try 1097a26f1527SMatt Spinler { 1098a26f1527SMatt Spinler labelValue = readFile<std::string>(file.path()); 1099a26f1527SMatt Spinler } 1100a26f1527SMatt Spinler catch (const std::system_error& e) 1101a26f1527SMatt Spinler { 1102a26f1527SMatt Spinler log<level::DEBUG>( 110348002498SPatrick Williams std::format("readPowerSensors: Failed reading {}, errno = {}", 1104a26f1527SMatt Spinler file.path().string(), e.code().value()) 1105a26f1527SMatt Spinler .c_str()); 1106bb895cb8SChicago Duan continue; 1107bb895cb8SChicago Duan } 1108bb895cb8SChicago Duan 1109bb895cb8SChicago Duan auto functionID = getPowerLabelFunctionID(labelValue); 1110bb895cb8SChicago Duan if (functionID == std::nullopt) 1111bb895cb8SChicago Duan { 1112bb895cb8SChicago Duan continue; 1113bb895cb8SChicago Duan } 1114bb895cb8SChicago Duan 1115bb895cb8SChicago Duan const std::string& tempLabel = "label"; 1116bb895cb8SChicago Duan const std::string filePathString = file.path().string().substr( 1117bb895cb8SChicago Duan 0, file.path().string().length() - tempLabel.length()); 1118bb895cb8SChicago Duan 1119bb895cb8SChicago Duan std::string sensorPath = OCC_SENSORS_ROOT + std::string("/power/"); 1120bb895cb8SChicago Duan 1121bb895cb8SChicago Duan auto iter = powerSensorName.find(*functionID); 1122bb895cb8SChicago Duan if (iter == powerSensorName.end()) 1123bb895cb8SChicago Duan { 1124bb895cb8SChicago Duan continue; 1125bb895cb8SChicago Duan } 1126bb895cb8SChicago Duan sensorPath.append(iter->second); 1127bb895cb8SChicago Duan 1128a26f1527SMatt Spinler double tempValue{0}; 1129a26f1527SMatt Spinler 1130a26f1527SMatt Spinler try 1131bb895cb8SChicago Duan { 1132a26f1527SMatt Spinler tempValue = readFile<double>(filePathString + inputSuffix); 1133a26f1527SMatt Spinler } 1134a26f1527SMatt Spinler catch (const std::system_error& e) 1135bb895cb8SChicago Duan { 1136a26f1527SMatt Spinler log<level::DEBUG>( 113748002498SPatrick Williams std::format("readPowerSensors: Failed reading {}, errno = {}", 1138a26f1527SMatt Spinler filePathString + inputSuffix, e.code().value()) 1139a26f1527SMatt Spinler .c_str()); 1140bb895cb8SChicago Duan continue; 1141bb895cb8SChicago Duan } 1142bb895cb8SChicago Duan 11435d66a0aaSChris Cain dbus::OccDBusSensors::getOccDBus().setUnit( 1144d84a8335SChris Cain sensorPath, "xyz.openbmc_project.Sensor.Value.Unit.Watts"); 1145d84a8335SChris Cain 11465d66a0aaSChris Cain dbus::OccDBusSensors::getOccDBus().setValue( 1147bb895cb8SChicago Duan sensorPath, tempValue * std::pow(10, -3) * std::pow(10, -3)); 1148bb895cb8SChicago Duan 1149*d7542c83SPatrick Williams dbus::OccDBusSensors::getOccDBus().setOperationalStatus( 1150*d7542c83SPatrick Williams sensorPath, true); 1151bb895cb8SChicago Duan 11525901abdaSMatt Spinler if (existingSensors.find(sensorPath) == existingSensors.end()) 11535901abdaSMatt Spinler { 11545d66a0aaSChris Cain dbus::OccDBusSensors::getOccDBus().setChassisAssociation( 11555d66a0aaSChris Cain sensorPath); 11565901abdaSMatt Spinler } 11575901abdaSMatt Spinler 1158bb895cb8SChicago Duan existingSensors[sensorPath] = id; 1159bb895cb8SChicago Duan } 1160bb895cb8SChicago Duan return; 1161bb895cb8SChicago Duan } 1162bb895cb8SChicago Duan 1163c8dd4599SSheldon Bailey void Manager::setSensorValueToNaN(uint32_t id) const 1164bb895cb8SChicago Duan { 1165bb895cb8SChicago Duan for (const auto& [sensorPath, occId] : existingSensors) 1166bb895cb8SChicago Duan { 1167bb895cb8SChicago Duan if (occId == id) 1168bb895cb8SChicago Duan { 11695d66a0aaSChris Cain dbus::OccDBusSensors::getOccDBus().setValue( 1170bb895cb8SChicago Duan sensorPath, std::numeric_limits<double>::quiet_NaN()); 1171c8dd4599SSheldon Bailey 1172*d7542c83SPatrick Williams dbus::OccDBusSensors::getOccDBus().setOperationalStatus( 1173*d7542c83SPatrick Williams sensorPath, true); 1174bb895cb8SChicago Duan } 1175bb895cb8SChicago Duan } 1176bb895cb8SChicago Duan return; 1177bb895cb8SChicago Duan } 1178bb895cb8SChicago Duan 1179373af757SSheldon Bailey void Manager::setSensorValueToNonFunctional(uint32_t id) const 1180373af757SSheldon Bailey { 1181373af757SSheldon Bailey for (const auto& [sensorPath, occId] : existingSensors) 1182373af757SSheldon Bailey { 1183373af757SSheldon Bailey if (occId == id) 1184373af757SSheldon Bailey { 1185373af757SSheldon Bailey dbus::OccDBusSensors::getOccDBus().setValue( 1186373af757SSheldon Bailey sensorPath, std::numeric_limits<double>::quiet_NaN()); 1187373af757SSheldon Bailey 1188*d7542c83SPatrick Williams dbus::OccDBusSensors::getOccDBus().setOperationalStatus( 1189*d7542c83SPatrick Williams sensorPath, false); 1190373af757SSheldon Bailey } 1191373af757SSheldon Bailey } 1192373af757SSheldon Bailey return; 1193373af757SSheldon Bailey } 1194373af757SSheldon Bailey 11955d66a0aaSChris Cain void Manager::getSensorValues(std::unique_ptr<Status>& occ) 1196bb895cb8SChicago Duan { 1197e2d0a43cSChris Cain static bool tracedError[8] = {0}; 1198e2d0a43cSChris Cain const fs::path sensorPath = occ->getHwmonPath(); 11995d66a0aaSChris Cain const uint32_t id = occ->getOccInstanceID(); 1200bb895cb8SChicago Duan 1201e2d0a43cSChris Cain if (fs::exists(sensorPath)) 1202e2d0a43cSChris Cain { 1203bb895cb8SChicago Duan // Read temperature sensors 1204e2d0a43cSChris Cain readTempSensors(sensorPath, id); 1205bb895cb8SChicago Duan 12065d66a0aaSChris Cain if (occ->isMasterOcc()) 1207bb895cb8SChicago Duan { 1208bb895cb8SChicago Duan // Read power sensors 1209e2d0a43cSChris Cain readPowerSensors(sensorPath, id); 1210e2d0a43cSChris Cain } 1211e2d0a43cSChris Cain tracedError[id] = false; 1212e2d0a43cSChris Cain } 1213e2d0a43cSChris Cain else 1214e2d0a43cSChris Cain { 1215e2d0a43cSChris Cain if (!tracedError[id]) 1216e2d0a43cSChris Cain { 1217e2d0a43cSChris Cain log<level::ERR>( 121848002498SPatrick Williams std::format( 1219e2d0a43cSChris Cain "Manager::getSensorValues: OCC{} sensor path missing: {}", 1220e2d0a43cSChris Cain id, sensorPath.c_str()) 1221e2d0a43cSChris Cain .c_str()); 1222e2d0a43cSChris Cain tracedError[id] = true; 1223e2d0a43cSChris Cain } 1224bb895cb8SChicago Duan } 1225bb895cb8SChicago Duan 1226bb895cb8SChicago Duan return; 1227bb895cb8SChicago Duan } 1228bb895cb8SChicago Duan #endif 122917257673SChris Cain 123017257673SChris Cain // Read the altitude from DBus 123117257673SChris Cain void Manager::readAltitude() 123217257673SChris Cain { 123317257673SChris Cain static bool traceAltitudeErr = true; 123417257673SChris Cain 123517257673SChris Cain utils::PropertyValue altitudeProperty{}; 123617257673SChris Cain try 123717257673SChris Cain { 123817257673SChris Cain altitudeProperty = utils::getProperty(ALTITUDE_PATH, ALTITUDE_INTERFACE, 123917257673SChris Cain ALTITUDE_PROP); 124017257673SChris Cain auto sensorVal = std::get<double>(altitudeProperty); 124117257673SChris Cain if (sensorVal < 0xFFFF) 124217257673SChris Cain { 124317257673SChris Cain if (sensorVal < 0) 124417257673SChris Cain { 124517257673SChris Cain altitude = 0; 124617257673SChris Cain } 124717257673SChris Cain else 124817257673SChris Cain { 124917257673SChris Cain // Round to nearest meter 125017257673SChris Cain altitude = uint16_t(sensorVal + 0.5); 125117257673SChris Cain } 125248002498SPatrick Williams log<level::DEBUG>(std::format("readAltitude: sensor={} ({}m)", 125317257673SChris Cain sensorVal, altitude) 125417257673SChris Cain .c_str()); 125517257673SChris Cain traceAltitudeErr = true; 125617257673SChris Cain } 125717257673SChris Cain else 125817257673SChris Cain { 125917257673SChris Cain if (traceAltitudeErr) 126017257673SChris Cain { 126117257673SChris Cain traceAltitudeErr = false; 126217257673SChris Cain log<level::DEBUG>( 126348002498SPatrick Williams std::format("Invalid altitude value: {}", sensorVal) 126417257673SChris Cain .c_str()); 126517257673SChris Cain } 126617257673SChris Cain } 126717257673SChris Cain } 1268af40808fSPatrick Williams catch (const sdbusplus::exception_t& e) 126917257673SChris Cain { 127017257673SChris Cain if (traceAltitudeErr) 127117257673SChris Cain { 127217257673SChris Cain traceAltitudeErr = false; 127317257673SChris Cain log<level::INFO>( 127448002498SPatrick Williams std::format("Unable to read Altitude: {}", e.what()).c_str()); 127517257673SChris Cain } 127617257673SChris Cain altitude = 0xFFFF; // not available 127717257673SChris Cain } 127817257673SChris Cain } 127917257673SChris Cain 128017257673SChris Cain // Callback function when ambient temperature changes 1281af40808fSPatrick Williams void Manager::ambientCallback(sdbusplus::message_t& msg) 128217257673SChris Cain { 128317257673SChris Cain double currentTemp = 0; 128417257673SChris Cain uint8_t truncatedTemp = 0xFF; 128517257673SChris Cain std::string msgSensor; 128617257673SChris Cain std::map<std::string, std::variant<double>> msgData; 128717257673SChris Cain msg.read(msgSensor, msgData); 128817257673SChris Cain 128917257673SChris Cain auto valPropMap = msgData.find(AMBIENT_PROP); 129017257673SChris Cain if (valPropMap == msgData.end()) 129117257673SChris Cain { 129217257673SChris Cain log<level::DEBUG>("ambientCallback: Unknown ambient property changed"); 129317257673SChris Cain return; 129417257673SChris Cain } 129517257673SChris Cain currentTemp = std::get<double>(valPropMap->second); 129617257673SChris Cain if (std::isnan(currentTemp)) 129717257673SChris Cain { 129817257673SChris Cain truncatedTemp = 0xFF; 129917257673SChris Cain } 130017257673SChris Cain else 130117257673SChris Cain { 130217257673SChris Cain if (currentTemp < 0) 130317257673SChris Cain { 130417257673SChris Cain truncatedTemp = 0; 130517257673SChris Cain } 130617257673SChris Cain else 130717257673SChris Cain { 130817257673SChris Cain // Round to nearest degree C 130917257673SChris Cain truncatedTemp = uint8_t(currentTemp + 0.5); 131017257673SChris Cain } 131117257673SChris Cain } 131217257673SChris Cain 131317257673SChris Cain // If ambient changes, notify OCCs 131417257673SChris Cain if (truncatedTemp != ambient) 131517257673SChris Cain { 131617257673SChris Cain log<level::DEBUG>( 131748002498SPatrick Williams std::format("ambientCallback: Ambient change from {} to {}C", 131817257673SChris Cain ambient, currentTemp) 131917257673SChris Cain .c_str()); 132017257673SChris Cain 132117257673SChris Cain ambient = truncatedTemp; 132217257673SChris Cain if (altitude == 0xFFFF) 132317257673SChris Cain { 132417257673SChris Cain // No altitude yet, try reading again 132517257673SChris Cain readAltitude(); 132617257673SChris Cain } 132717257673SChris Cain 132817257673SChris Cain log<level::DEBUG>( 132948002498SPatrick Williams std::format("ambientCallback: Ambient: {}C, altitude: {}m", ambient, 133017257673SChris Cain altitude) 133117257673SChris Cain .c_str()); 133217257673SChris Cain #ifdef POWER10 133317257673SChris Cain // Send ambient and altitude to all OCCs 133417257673SChris Cain for (auto& obj : statusObjects) 133517257673SChris Cain { 133617257673SChris Cain if (obj->occActive()) 133717257673SChris Cain { 133817257673SChris Cain obj->sendAmbient(ambient, altitude); 133917257673SChris Cain } 134017257673SChris Cain } 134117257673SChris Cain #endif // POWER10 134217257673SChris Cain } 134317257673SChris Cain } 134417257673SChris Cain 134517257673SChris Cain // return the current ambient and altitude readings 134617257673SChris Cain void Manager::getAmbientData(bool& ambientValid, uint8_t& ambientTemp, 134717257673SChris Cain uint16_t& altitudeValue) const 134817257673SChris Cain { 134917257673SChris Cain ambientValid = true; 135017257673SChris Cain ambientTemp = ambient; 135117257673SChris Cain altitudeValue = altitude; 135217257673SChris Cain 135317257673SChris Cain if (ambient == 0xFF) 135417257673SChris Cain { 135517257673SChris Cain ambientValid = false; 135617257673SChris Cain } 135717257673SChris Cain } 135817257673SChris Cain 1359a7b74dc3SChris Cain #ifdef POWER10 13607f89e4d1SChris Cain // Called when waitForAllOccsTimer expires 13617f89e4d1SChris Cain // After the first OCC goes active, this timer will be started (60 seconds) 1362a7b74dc3SChris Cain void Manager::occsNotAllRunning() 1363a7b74dc3SChris Cain { 1364a7b74dc3SChris Cain if (activeCount != statusObjects.size()) 1365a7b74dc3SChris Cain { 1366a7b74dc3SChris Cain // Not all OCCs went active 1367a7b74dc3SChris Cain log<level::WARNING>( 136848002498SPatrick Williams std::format( 1369a7b74dc3SChris Cain "occsNotAllRunning: Active OCC count ({}) does not match expected count ({})", 1370a7b74dc3SChris Cain activeCount, statusObjects.size()) 1371a7b74dc3SChris Cain .c_str()); 13727f89e4d1SChris Cain // Procs may be garded, so may be expected 1373a7b74dc3SChris Cain } 1374a7b74dc3SChris Cain 1375a7b74dc3SChris Cain validateOccMaster(); 1376a7b74dc3SChris Cain } 1377755af102SChris Cain 1378755af102SChris Cain #ifdef PLDM 1379c33171bbSChris Cain // Called when throttlePldmTraceTimer expires. 1380a19bd428SChris Cain // If this timer expires, that indicates there are no OCC active sensor PDRs 1381c33171bbSChris Cain // found which will trigger pldm traces to be throttled. 1382c33171bbSChris Cain // The second time this timer expires, a PEL will get created. 1383c33171bbSChris Cain void Manager::throttlePldmTraceExpired() 1384755af102SChris Cain { 13857651c06bSChris Cain if (utils::isHostRunning()) 13867651c06bSChris Cain { 1387c33171bbSChris Cain if (!onPldmTimeoutCreatePel) 1388c33171bbSChris Cain { 1389755af102SChris Cain // Throttle traces 1390755af102SChris Cain pldmHandle->setTraceThrottle(true); 1391c33171bbSChris Cain // Restart timer to log a PEL when timer expires 1392c33171bbSChris Cain onPldmTimeoutCreatePel = true; 1393c33171bbSChris Cain throttlePldmTraceTimer->restartOnce(40min); 1394c33171bbSChris Cain } 1395c33171bbSChris Cain else 1396c33171bbSChris Cain { 1397c33171bbSChris Cain log<level::ERR>( 1398c33171bbSChris Cain "throttlePldmTraceExpired(): OCC active sensors still not available!"); 13994b82f3e3SChris Cain // Create PEL 14004b82f3e3SChris Cain createPldmSensorPEL(); 14014b82f3e3SChris Cain } 1402c33171bbSChris Cain } 14037651c06bSChris Cain else 14047651c06bSChris Cain { 14057651c06bSChris Cain // Make sure traces are not throttled 14067651c06bSChris Cain pldmHandle->setTraceThrottle(false); 14077651c06bSChris Cain log<level::INFO>( 1408c33171bbSChris Cain "throttlePldmTraceExpired(): host it not running ignoring sensor timer"); 14097651c06bSChris Cain } 14107651c06bSChris Cain } 14114b82f3e3SChris Cain 14124b82f3e3SChris Cain void Manager::createPldmSensorPEL() 14134b82f3e3SChris Cain { 14144b82f3e3SChris Cain Error::Descriptor d = Error::Descriptor(MISSING_OCC_SENSORS_PATH); 14154b82f3e3SChris Cain std::map<std::string, std::string> additionalData; 14164b82f3e3SChris Cain 14174b82f3e3SChris Cain additionalData.emplace("_PID", std::to_string(getpid())); 14184b82f3e3SChris Cain 14194b82f3e3SChris Cain log<level::INFO>( 14204b82f3e3SChris Cain std::format( 14214b82f3e3SChris Cain "createPldmSensorPEL(): Unable to find PLDM sensors for the OCCs") 14224b82f3e3SChris Cain .c_str()); 14234b82f3e3SChris Cain 14244b82f3e3SChris Cain auto& bus = utils::getBus(); 14254b82f3e3SChris Cain 14264b82f3e3SChris Cain try 14274b82f3e3SChris Cain { 14284b82f3e3SChris Cain FFDCFiles ffdc; 14294b82f3e3SChris Cain // Add occ-control journal traces to PEL FFDC 14304b82f3e3SChris Cain auto occJournalFile = 14314b82f3e3SChris Cain FFDC::addJournalEntries(ffdc, "openpower-occ-control", 40); 14324b82f3e3SChris Cain 14334b82f3e3SChris Cain static constexpr auto loggingObjectPath = 14344b82f3e3SChris Cain "/xyz/openbmc_project/logging"; 14354b82f3e3SChris Cain static constexpr auto opLoggingInterface = "org.open_power.Logging.PEL"; 1436*d7542c83SPatrick Williams std::string service = 1437*d7542c83SPatrick Williams utils::getService(loggingObjectPath, opLoggingInterface); 1438*d7542c83SPatrick Williams auto method = 1439*d7542c83SPatrick Williams bus.new_method_call(service.c_str(), loggingObjectPath, 1440*d7542c83SPatrick Williams opLoggingInterface, "CreatePELWithFFDCFiles"); 14414b82f3e3SChris Cain 14421c3349e4SChris Cain // Set level to Warning (Predictive). 14434b82f3e3SChris Cain auto level = 14444b82f3e3SChris Cain sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage( 14454b82f3e3SChris Cain sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level:: 14461c3349e4SChris Cain Warning); 14474b82f3e3SChris Cain 14484b82f3e3SChris Cain method.append(d.path, level, additionalData, ffdc); 14494b82f3e3SChris Cain bus.call(method); 14504b82f3e3SChris Cain } 14514b82f3e3SChris Cain catch (const sdbusplus::exception_t& e) 14524b82f3e3SChris Cain { 14534b82f3e3SChris Cain log<level::ERR>( 14544b82f3e3SChris Cain std::format("Failed to create MISSING_OCC_SENSORS PEL: {}", 14554b82f3e3SChris Cain e.what()) 14564b82f3e3SChris Cain .c_str()); 14574b82f3e3SChris Cain } 1458755af102SChris Cain } 1459755af102SChris Cain #endif // PLDM 1460a7b74dc3SChris Cain #endif // POWER10 1461a7b74dc3SChris Cain 1462a7b74dc3SChris Cain // Verify single master OCC and start presence monitor 1463a7b74dc3SChris Cain void Manager::validateOccMaster() 1464a7b74dc3SChris Cain { 1465a7b74dc3SChris Cain int masterInstance = -1; 1466a7b74dc3SChris Cain for (auto& obj : statusObjects) 1467a7b74dc3SChris Cain { 1468bd551de3SChris Cain auto instance = obj->getOccInstanceID(); 1469bae4d07eSChris Cain #ifdef POWER10 1470bae4d07eSChris Cain if (!obj->occActive()) 1471bae4d07eSChris Cain { 1472bae4d07eSChris Cain if (utils::isHostRunning()) 1473bae4d07eSChris Cain { 1474bd551de3SChris Cain // Check if sensor was queued while waiting for discovery 1475bd551de3SChris Cain auto match = queuedActiveState.find(instance); 1476bd551de3SChris Cain if (match != queuedActiveState.end()) 1477bd551de3SChris Cain { 14787f89e4d1SChris Cain queuedActiveState.erase(match); 1479bd551de3SChris Cain log<level::INFO>( 148048002498SPatrick Williams std::format( 1481bd551de3SChris Cain "validateOccMaster: OCC{} is ACTIVE (queued)", 1482bd551de3SChris Cain instance) 1483bd551de3SChris Cain .c_str()); 1484bd551de3SChris Cain obj->occActive(true); 1485bd551de3SChris Cain } 1486bd551de3SChris Cain else 1487bd551de3SChris Cain { 1488bae4d07eSChris Cain // OCC does not appear to be active yet, check active sensor 1489fb0a5c3cSPatrick Williams #ifdef PLDM 1490bd551de3SChris Cain pldmHandle->checkActiveSensor(instance); 1491fb0a5c3cSPatrick Williams #endif 1492bae4d07eSChris Cain if (obj->occActive()) 1493bae4d07eSChris Cain { 1494bae4d07eSChris Cain log<level::INFO>( 149548002498SPatrick Williams std::format( 1496bae4d07eSChris Cain "validateOccMaster: OCC{} is ACTIVE after reading sensor", 1497bd551de3SChris Cain instance) 1498bae4d07eSChris Cain .c_str()); 1499bae4d07eSChris Cain } 1500bae4d07eSChris Cain } 1501bd551de3SChris Cain } 1502bae4d07eSChris Cain else 1503bae4d07eSChris Cain { 1504bae4d07eSChris Cain log<level::WARNING>( 150548002498SPatrick Williams std::format( 1506bae4d07eSChris Cain "validateOccMaster: HOST is not running (OCC{})", 1507bd551de3SChris Cain instance) 1508bae4d07eSChris Cain .c_str()); 1509bae4d07eSChris Cain return; 1510bae4d07eSChris Cain } 1511bae4d07eSChris Cain } 1512bae4d07eSChris Cain #endif // POWER10 1513bae4d07eSChris Cain 1514a7b74dc3SChris Cain if (obj->isMasterOcc()) 1515a7b74dc3SChris Cain { 15165d66a0aaSChris Cain obj->addPresenceWatchMaster(); 15175d66a0aaSChris Cain 1518a7b74dc3SChris Cain if (masterInstance == -1) 1519a7b74dc3SChris Cain { 1520bd551de3SChris Cain masterInstance = instance; 1521a7b74dc3SChris Cain } 1522a7b74dc3SChris Cain else 1523a7b74dc3SChris Cain { 1524a7b74dc3SChris Cain log<level::ERR>( 152548002498SPatrick Williams std::format( 1526a7b74dc3SChris Cain "validateOccMaster: Multiple OCC masters! ({} and {})", 1527bd551de3SChris Cain masterInstance, instance) 1528a7b74dc3SChris Cain .c_str()); 1529a7b74dc3SChris Cain // request reset 15309789e71fSEddie James obj->deviceError(Error::Descriptor(PRESENCE_ERROR_PATH)); 1531a7b74dc3SChris Cain } 1532a7b74dc3SChris Cain } 1533a7b74dc3SChris Cain } 1534bae4d07eSChris Cain 1535a7b74dc3SChris Cain if (masterInstance < 0) 1536a7b74dc3SChris Cain { 1537bae4d07eSChris Cain log<level::ERR>( 153848002498SPatrick Williams std::format("validateOccMaster: Master OCC not found! (of {} OCCs)", 1539bae4d07eSChris Cain statusObjects.size()) 1540bae4d07eSChris Cain .c_str()); 1541a7b74dc3SChris Cain // request reset 15429789e71fSEddie James statusObjects.front()->deviceError( 15439789e71fSEddie James Error::Descriptor(PRESENCE_ERROR_PATH)); 1544a7b74dc3SChris Cain } 1545a7b74dc3SChris Cain else 1546a7b74dc3SChris Cain { 1547a7b74dc3SChris Cain log<level::INFO>( 154848002498SPatrick Williams std::format("validateOccMaster: OCC{} is master of {} OCCs", 154936f9cdedSChris Cain masterInstance, activeCount) 1550a7b74dc3SChris Cain .c_str()); 155131a2f13aSSheldon Bailey #ifdef POWER10 155231a2f13aSSheldon Bailey pmode->updateDbusSafeMode(false); 155331a2f13aSSheldon Bailey #endif 1554a7b74dc3SChris Cain } 1555a7b74dc3SChris Cain } 1556a7b74dc3SChris Cain 155740501a23SChris Cain void Manager::updatePcapBounds() const 155840501a23SChris Cain { 155940501a23SChris Cain if (pcap) 156040501a23SChris Cain { 156140501a23SChris Cain pcap->updatePcapBounds(); 156240501a23SChris Cain } 156340501a23SChris Cain } 156440501a23SChris Cain 1565dfc7ec73SVishwanatha Subbanna } // namespace occ 1566dfc7ec73SVishwanatha Subbanna } // namespace open_power 1567