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" 794df8c90SGunnar Mills #include "utils.hpp" 894df8c90SGunnar Mills 9b5ca1015SGeorge Liu #include <phosphor-logging/elog-errors.hpp> 10b5ca1015SGeorge Liu #include <phosphor-logging/log.hpp> 11b5ca1015SGeorge Liu #include <xyz/openbmc_project/Common/error.hpp> 12b5ca1015SGeorge Liu 13d267cec2SMatt Spinler #include <chrono> 14bb895cb8SChicago Duan #include <cmath> 15bcef3b48SGeorge Liu #include <filesystem> 1636f9cdedSChris Cain #include <fstream> 17bb895cb8SChicago Duan #include <regex> 1894df8c90SGunnar Mills 19dfc7ec73SVishwanatha Subbanna namespace open_power 20dfc7ec73SVishwanatha Subbanna { 21dfc7ec73SVishwanatha Subbanna namespace occ 22dfc7ec73SVishwanatha Subbanna { 23dfc7ec73SVishwanatha Subbanna 248b8abeedSMatt Spinler constexpr uint32_t fruTypeNotAvailable = 0xFF; 25a26f1527SMatt Spinler constexpr auto fruTypeSuffix = "fru_type"; 26a26f1527SMatt Spinler constexpr auto faultSuffix = "fault"; 27a26f1527SMatt Spinler constexpr auto inputSuffix = "input"; 28ace67d85SMatt Spinler constexpr auto maxSuffix = "max"; 298b8abeedSMatt Spinler 301718fd8bSChris Cain const auto HOST_ON_FILE = "/run/openbmc/host@0-on"; 311718fd8bSChris Cain 32a8857c50SChris Cain using namespace phosphor::logging; 33a7b74dc3SChris Cain using namespace std::literals::chrono_literals; 34a8857c50SChris Cain 35a26f1527SMatt Spinler template <typename T> 36a26f1527SMatt Spinler T readFile(const std::string& path) 37a26f1527SMatt Spinler { 38a26f1527SMatt Spinler std::ifstream ifs; 39a26f1527SMatt Spinler ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit | 40a26f1527SMatt Spinler std::ifstream::eofbit); 41a26f1527SMatt Spinler T data; 42a26f1527SMatt Spinler 43a26f1527SMatt Spinler try 44a26f1527SMatt Spinler { 45a26f1527SMatt Spinler ifs.open(path); 46a26f1527SMatt Spinler ifs >> data; 47a26f1527SMatt Spinler ifs.close(); 48a26f1527SMatt Spinler } 49a26f1527SMatt Spinler catch (const std::exception& e) 50a26f1527SMatt Spinler { 51a26f1527SMatt Spinler auto err = errno; 52a26f1527SMatt Spinler throw std::system_error(err, std::generic_category()); 53a26f1527SMatt Spinler } 54a26f1527SMatt Spinler 55a26f1527SMatt Spinler return data; 56a26f1527SMatt Spinler } 57a26f1527SMatt Spinler 58dfc7ec73SVishwanatha Subbanna void Manager::findAndCreateObjects() 59dfc7ec73SVishwanatha Subbanna { 60d267cec2SMatt Spinler #ifndef POWER10 61dfc7ec73SVishwanatha Subbanna for (auto id = 0; id < MAX_CPUS; ++id) 62dfc7ec73SVishwanatha Subbanna { 6330417a15SDeepak Kodihalli // Create one occ per cpu 6430417a15SDeepak Kodihalli auto occ = std::string(OCC_NAME) + std::to_string(id); 65dfc7ec73SVishwanatha Subbanna createObjects(occ); 66dfc7ec73SVishwanatha Subbanna } 67d267cec2SMatt Spinler #else 681718fd8bSChris Cain if (!fs::exists(HOST_ON_FILE)) 691718fd8bSChris Cain { 70d267cec2SMatt Spinler // Create the OCCs based on on the /dev/occX devices 71d267cec2SMatt Spinler auto occs = findOCCsInDev(); 72d267cec2SMatt Spinler 73d267cec2SMatt Spinler if (occs.empty() || (prevOCCSearch.size() != occs.size())) 74d267cec2SMatt Spinler { 75d267cec2SMatt Spinler // Something changed or no OCCs yet, try again in 10s. 76d267cec2SMatt Spinler // Note on the first pass prevOCCSearch will be empty, 77d267cec2SMatt Spinler // so there will be at least one delay to give things 78d267cec2SMatt Spinler // a chance to settle. 79d267cec2SMatt Spinler prevOCCSearch = occs; 80d267cec2SMatt Spinler 81d267cec2SMatt Spinler discoverTimer->restartOnce(10s); 82d267cec2SMatt Spinler } 83d267cec2SMatt Spinler else 84d267cec2SMatt Spinler { 85d267cec2SMatt Spinler discoverTimer.reset(); 86d267cec2SMatt Spinler 87d267cec2SMatt Spinler // createObjects requires OCC0 first. 88d267cec2SMatt Spinler std::sort(occs.begin(), occs.end()); 89d267cec2SMatt Spinler 90d267cec2SMatt Spinler for (auto id : occs) 91d267cec2SMatt Spinler { 92d267cec2SMatt Spinler createObjects(std::string(OCC_NAME) + std::to_string(id)); 93d267cec2SMatt Spinler } 94d267cec2SMatt Spinler } 951718fd8bSChris Cain } 961718fd8bSChris Cain else 971718fd8bSChris Cain { 981718fd8bSChris Cain log<level::INFO>( 991718fd8bSChris Cain fmt::format( 1001718fd8bSChris Cain "Manager::findAndCreateObjects(): Waiting for {} to complete...", 1011718fd8bSChris Cain HOST_ON_FILE) 1021718fd8bSChris Cain .c_str()); 1031718fd8bSChris Cain discoverTimer->restartOnce(10s); 1041718fd8bSChris Cain } 105d267cec2SMatt Spinler #endif 106d267cec2SMatt Spinler } 107d267cec2SMatt Spinler 108d267cec2SMatt Spinler std::vector<int> Manager::findOCCsInDev() 109d267cec2SMatt Spinler { 110d267cec2SMatt Spinler std::vector<int> occs; 111d267cec2SMatt Spinler std::regex expr{R"(occ(\d+)$)"}; 112d267cec2SMatt Spinler 113d267cec2SMatt Spinler for (auto& file : fs::directory_iterator("/dev")) 114d267cec2SMatt Spinler { 115d267cec2SMatt Spinler std::smatch match; 116d267cec2SMatt Spinler std::string path{file.path().string()}; 117d267cec2SMatt Spinler if (std::regex_search(path, match, expr)) 118d267cec2SMatt Spinler { 119d267cec2SMatt Spinler auto num = std::stoi(match[1].str()); 120d267cec2SMatt Spinler 121d267cec2SMatt Spinler // /dev numbering starts at 1, ours starts at 0. 122d267cec2SMatt Spinler occs.push_back(num - 1); 123d267cec2SMatt Spinler } 124d267cec2SMatt Spinler } 125d267cec2SMatt Spinler 126d267cec2SMatt Spinler return occs; 127dfc7ec73SVishwanatha Subbanna } 128dfc7ec73SVishwanatha Subbanna 129dfc7ec73SVishwanatha Subbanna int Manager::cpuCreated(sdbusplus::message::message& msg) 130dfc7ec73SVishwanatha Subbanna { 131bcef3b48SGeorge Liu namespace fs = std::filesystem; 132dfc7ec73SVishwanatha Subbanna 133dfc7ec73SVishwanatha Subbanna sdbusplus::message::object_path o; 134dfc7ec73SVishwanatha Subbanna msg.read(o); 135dfc7ec73SVishwanatha Subbanna fs::path cpuPath(std::string(std::move(o))); 136dfc7ec73SVishwanatha Subbanna 137dfc7ec73SVishwanatha Subbanna auto name = cpuPath.filename().string(); 138dfc7ec73SVishwanatha Subbanna auto index = name.find(CPU_NAME); 139dfc7ec73SVishwanatha Subbanna name.replace(index, std::strlen(CPU_NAME), OCC_NAME); 140dfc7ec73SVishwanatha Subbanna 141dfc7ec73SVishwanatha Subbanna createObjects(name); 142dfc7ec73SVishwanatha Subbanna 143dfc7ec73SVishwanatha Subbanna return 0; 144dfc7ec73SVishwanatha Subbanna } 145dfc7ec73SVishwanatha Subbanna 146dfc7ec73SVishwanatha Subbanna void Manager::createObjects(const std::string& occ) 147dfc7ec73SVishwanatha Subbanna { 148dfc7ec73SVishwanatha Subbanna auto path = fs::path(OCC_CONTROL_ROOT) / occ; 149dfc7ec73SVishwanatha Subbanna 1506fa848a9SChris Cain #ifdef POWER10 1516fa848a9SChris Cain if (!pmode) 1526fa848a9SChris Cain { 1531be4337bSChris Cain // Create the power mode object 1541be4337bSChris Cain pmode = std::make_unique<open_power::occ::powermode::PowerMode>( 1551be4337bSChris Cain *this, powermode::PMODE_PATH, powermode::PIPS_PATH); 1566fa848a9SChris Cain } 1576fa848a9SChris Cain #endif 1586fa848a9SChris Cain 15994df8c90SGunnar Mills statusObjects.emplace_back(std::make_unique<Status>( 160f3b7514eSGeorge Liu event, path.c_str(), *this, 16136f9cdedSChris Cain #ifdef POWER10 16236f9cdedSChris Cain pmode, 16336f9cdedSChris Cain #endif 16494df8c90SGunnar Mills std::bind(std::mem_fn(&Manager::statusCallBack), this, 16500325238STom Joseph std::placeholders::_1) 16600325238STom Joseph #ifdef PLDM 16700325238STom Joseph , 16800325238STom Joseph std::bind(std::mem_fn(&pldm::Interface::resetOCC), pldmHandle.get(), 16900325238STom Joseph std::placeholders::_1) 17000325238STom Joseph #endif 17100325238STom Joseph )); 172dfc7ec73SVishwanatha Subbanna 17336f9cdedSChris Cain if (statusObjects.back()->isMasterOcc()) 17436f9cdedSChris Cain { 17536f9cdedSChris Cain log<level::INFO>( 17636f9cdedSChris Cain fmt::format("Manager::createObjects(): OCC{} is the master", 17736f9cdedSChris Cain statusObjects.back()->getOccInstanceID()) 17836f9cdedSChris Cain .c_str()); 17936f9cdedSChris Cain _pollTimer->setEnabled(false); 18036f9cdedSChris Cain 18136f9cdedSChris Cain // Create the power cap monitor object for master OCC 182dfc7ec73SVishwanatha Subbanna if (!pcap) 183dfc7ec73SVishwanatha Subbanna { 184dfc7ec73SVishwanatha Subbanna pcap = std::make_unique<open_power::occ::powercap::PowerCap>( 1851be4337bSChris Cain *statusObjects.back()); 186dfc7ec73SVishwanatha Subbanna } 18778e86012SChris Cain 18878e86012SChris Cain #ifdef POWER10 1896fa848a9SChris Cain // Set the master OCC on the PowerMode object 1906fa848a9SChris Cain pmode->setMasterOcc(path); 19178e86012SChris Cain #endif 192dfc7ec73SVishwanatha Subbanna } 193dfc7ec73SVishwanatha Subbanna 19436f9cdedSChris Cain passThroughObjects.emplace_back(std::make_unique<PassThrough>(path.c_str() 19536f9cdedSChris Cain #ifdef POWER10 19636f9cdedSChris Cain , 19736f9cdedSChris Cain pmode 19836f9cdedSChris Cain #endif 19936f9cdedSChris Cain )); 20036f9cdedSChris Cain } 20136f9cdedSChris Cain 202dfc7ec73SVishwanatha Subbanna void Manager::statusCallBack(bool status) 203dfc7ec73SVishwanatha Subbanna { 20494df8c90SGunnar Mills using InternalFailure = 20594df8c90SGunnar Mills sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 206dfc7ec73SVishwanatha Subbanna 207dfc7ec73SVishwanatha Subbanna // At this time, it won't happen but keeping it 208dfc7ec73SVishwanatha Subbanna // here just in case something changes in the future 209dfc7ec73SVishwanatha Subbanna if ((activeCount == 0) && (!status)) 210dfc7ec73SVishwanatha Subbanna { 211dfc7ec73SVishwanatha Subbanna log<level::ERR>("Invalid update on OCCActive"); 212dfc7ec73SVishwanatha Subbanna elog<InternalFailure>(); 213dfc7ec73SVishwanatha Subbanna } 214dfc7ec73SVishwanatha Subbanna 215a7b74dc3SChris Cain if (status == true) 216a7b74dc3SChris Cain { 217a7b74dc3SChris Cain // OCC went active 218a7b74dc3SChris Cain ++activeCount; 219dae2d940SEddie James 220a7b74dc3SChris Cain #ifdef POWER10 221a7b74dc3SChris Cain if (activeCount == 1) 222a7b74dc3SChris Cain { 223a7b74dc3SChris Cain // First OCC went active (allow some time for all OCCs to go active) 224a7b74dc3SChris Cain waitForAllOccsTimer->restartOnce(30s); 225a7b74dc3SChris Cain } 226a7b74dc3SChris Cain #endif 227a7b74dc3SChris Cain 228dae2d940SEddie James if (activeCount == statusObjects.size()) 229dae2d940SEddie James { 230a7b74dc3SChris Cain #ifdef POWER10 231a7b74dc3SChris Cain // All OCCs are now running 232a7b74dc3SChris Cain if (waitForAllOccsTimer->isEnabled()) 233dae2d940SEddie James { 234a7b74dc3SChris Cain // stop occ wait timer 235a7b74dc3SChris Cain waitForAllOccsTimer->setEnabled(false); 236dae2d940SEddie James } 237a7b74dc3SChris Cain #endif 238a7b74dc3SChris Cain 239a7b74dc3SChris Cain // Verify master OCC and start presence monitor 240a7b74dc3SChris Cain validateOccMaster(); 241dae2d940SEddie James } 242a8857c50SChris Cain 243a7b74dc3SChris Cain // Start poll timer if not already started 244a7b74dc3SChris Cain if (!_pollTimer->isEnabled()) 245a8857c50SChris Cain { 246b5ca1015SGeorge Liu log<level::INFO>( 24736f9cdedSChris Cain fmt::format("Manager: OCCs will be polled every {} seconds", 24836f9cdedSChris Cain pollInterval) 249a8857c50SChris Cain .c_str()); 250a8857c50SChris Cain 251a8857c50SChris Cain // Send poll and start OCC poll timer 252a8857c50SChris Cain pollerTimerExpired(); 253a8857c50SChris Cain } 254a7b74dc3SChris Cain } 255a7b74dc3SChris Cain else 256a8857c50SChris Cain { 257a7b74dc3SChris Cain // OCC went away 258a7b74dc3SChris Cain --activeCount; 259a7b74dc3SChris Cain 260a7b74dc3SChris Cain if (activeCount == 0) 261a7b74dc3SChris Cain { 262a7b74dc3SChris Cain // No OCCs are running 263a7b74dc3SChris Cain 264a8857c50SChris Cain // Stop OCC poll timer 265a7b74dc3SChris Cain if (_pollTimer->isEnabled()) 266a7b74dc3SChris Cain { 267b5ca1015SGeorge Liu log<level::INFO>( 268b5ca1015SGeorge Liu "Manager::statusCallBack(): OCCs are not running, stopping poll timer"); 269a8857c50SChris Cain _pollTimer->setEnabled(false); 270a7b74dc3SChris Cain } 271a7b74dc3SChris Cain 272a7b74dc3SChris Cain #ifdef POWER10 273a7b74dc3SChris Cain // stop wait timer 274a7b74dc3SChris Cain if (waitForAllOccsTimer->isEnabled()) 275a7b74dc3SChris Cain { 276a7b74dc3SChris Cain waitForAllOccsTimer->setEnabled(false); 277a7b74dc3SChris Cain } 278a7b74dc3SChris Cain #endif 27953f68148SMatt Spinler 28053f68148SMatt Spinler #ifdef READ_OCC_SENSORS 281a7b74dc3SChris Cain // Clear OCC sensors 28253f68148SMatt Spinler for (auto& obj : statusObjects) 28353f68148SMatt Spinler { 28453f68148SMatt Spinler setSensorValueToNaN(obj->getOccInstanceID()); 28553f68148SMatt Spinler } 28653f68148SMatt Spinler #endif 287a8857c50SChris Cain } 288dfc7ec73SVishwanatha Subbanna } 289a7b74dc3SChris Cain } 290dfc7ec73SVishwanatha Subbanna 291dfc7ec73SVishwanatha Subbanna #ifdef I2C_OCC 292dfc7ec73SVishwanatha Subbanna void Manager::initStatusObjects() 293dfc7ec73SVishwanatha Subbanna { 294dfc7ec73SVishwanatha Subbanna // Make sure we have a valid path string 295dfc7ec73SVishwanatha Subbanna static_assert(sizeof(DEV_PATH) != 0); 296dfc7ec73SVishwanatha Subbanna 297dfc7ec73SVishwanatha Subbanna auto deviceNames = i2c_occ::getOccHwmonDevices(DEV_PATH); 29841470e56SLei YU auto occMasterName = deviceNames.front(); 299dfc7ec73SVishwanatha Subbanna for (auto& name : deviceNames) 300dfc7ec73SVishwanatha Subbanna { 301dfc7ec73SVishwanatha Subbanna i2c_occ::i2cToDbus(name); 302b5259a1eSLei YU name = std::string(OCC_NAME) + '_' + name; 303dfc7ec73SVishwanatha Subbanna auto path = fs::path(OCC_CONTROL_ROOT) / name; 304dfc7ec73SVishwanatha Subbanna statusObjects.emplace_back( 305f3b7514eSGeorge Liu std::make_unique<Status>(event, path.c_str(), *this)); 306dfc7ec73SVishwanatha Subbanna } 30741470e56SLei YU // The first device is master occ 30841470e56SLei YU pcap = std::make_unique<open_power::occ::powercap::PowerCap>( 309f3b7514eSGeorge Liu *statusObjects.front(), occMasterName); 31078e86012SChris Cain #ifdef POWER10 3111be4337bSChris Cain pmode = std::make_unique<open_power::occ::powermode::PowerMode>( 3121be4337bSChris Cain *this, open_power::occ::powermode::PMODE_PATH, 3131be4337bSChris Cain open_power::occ::powermode::PIPS_PATH); 3146fa848a9SChris Cain // Set the master OCC on the PowerMode object 3156fa848a9SChris Cain pmode->setMasterOcc(path); 31678e86012SChris Cain #endif 317dfc7ec73SVishwanatha Subbanna } 318dfc7ec73SVishwanatha Subbanna #endif 319dfc7ec73SVishwanatha Subbanna 320815f9f55STom Joseph #ifdef PLDM 321cbad219eSEddie James void Manager::sbeTimeout(unsigned int instance) 322cbad219eSEddie James { 3232a751d70SEddie James auto obj = std::find_if(statusObjects.begin(), statusObjects.end(), 3242a751d70SEddie James [instance](const auto& obj) { 3252a751d70SEddie James return instance == obj->getOccInstanceID(); 3262a751d70SEddie James }); 3272a751d70SEddie James 328*cb018dafSEddie James if (obj != statusObjects.end() && (*obj)->occActive()) 3292a751d70SEddie James { 330cbad219eSEddie James log<level::INFO>("SBE timeout, requesting HRESET", 331cbad219eSEddie James entry("SBE=%d", instance)); 332cbad219eSEddie James 333cbad219eSEddie James setSBEState(instance, SBE_STATE_NOT_USABLE); 334cbad219eSEddie James 335cbad219eSEddie James pldmHandle->sendHRESET(instance); 336cbad219eSEddie James } 3372a751d70SEddie James } 338cbad219eSEddie James 339815f9f55STom Joseph bool Manager::updateOCCActive(instanceID instance, bool status) 340815f9f55STom Joseph { 341815f9f55STom Joseph return (statusObjects[instance])->occActive(status); 342815f9f55STom Joseph } 343cbad219eSEddie James 344cbad219eSEddie James void Manager::sbeHRESETResult(instanceID instance, bool success) 345cbad219eSEddie James { 346cbad219eSEddie James if (success) 347cbad219eSEddie James { 348cbad219eSEddie James log<level::INFO>("HRESET succeeded", entry("SBE=%d", instance)); 349cbad219eSEddie James 350cbad219eSEddie James setSBEState(instance, SBE_STATE_BOOTED); 351cbad219eSEddie James 352cbad219eSEddie James return; 353cbad219eSEddie James } 354cbad219eSEddie James 355cbad219eSEddie James setSBEState(instance, SBE_STATE_FAILED); 356cbad219eSEddie James 357cbad219eSEddie James if (sbeCanDump(instance)) 358cbad219eSEddie James { 359cbad219eSEddie James log<level::INFO>("HRESET failed, triggering SBE dump", 360cbad219eSEddie James entry("SBE=%d", instance)); 361cbad219eSEddie James 362cbad219eSEddie James auto& bus = utils::getBus(); 363cbad219eSEddie James uint32_t src6 = instance << 16; 364cbad219eSEddie James uint32_t logId = 365cbad219eSEddie James FFDC::createPEL("org.open_power.Processor.Error.SbeChipOpTimeout", 366cbad219eSEddie James src6, "SBE command timeout"); 367cbad219eSEddie James 368cbad219eSEddie James try 369cbad219eSEddie James { 370f3a4a69fSGeorge Liu constexpr auto path = "/org/openpower/dump"; 371f3a4a69fSGeorge Liu constexpr auto interface = "xyz.openbmc_project.Dump.Create"; 372f3a4a69fSGeorge Liu constexpr auto function = "CreateDump"; 373f3a4a69fSGeorge Liu 374cbad219eSEddie James std::string service = utils::getService(path, interface); 375cbad219eSEddie James auto method = 376cbad219eSEddie James bus.new_method_call(service.c_str(), path, interface, function); 377cbad219eSEddie James 378cbad219eSEddie James std::map<std::string, std::variant<std::string, uint64_t>> 379cbad219eSEddie James createParams{ 380cbad219eSEddie James {"com.ibm.Dump.Create.CreateParameters.ErrorLogId", 381cbad219eSEddie James uint64_t(logId)}, 382cbad219eSEddie James {"com.ibm.Dump.Create.CreateParameters.DumpType", 383cbad219eSEddie James "com.ibm.Dump.Create.DumpType.SBE"}, 384cbad219eSEddie James {"com.ibm.Dump.Create.CreateParameters.FailingUnitId", 385cbad219eSEddie James uint64_t(instance)}, 386cbad219eSEddie James }; 387cbad219eSEddie James 388cbad219eSEddie James method.append(createParams); 389cbad219eSEddie James 390cbad219eSEddie James auto response = bus.call(method); 391cbad219eSEddie James } 392cbad219eSEddie James catch (const sdbusplus::exception::exception& e) 393cbad219eSEddie James { 394cbad219eSEddie James constexpr auto ERROR_DUMP_DISABLED = 395cbad219eSEddie James "xyz.openbmc_project.Dump.Create.Error.Disabled"; 396cbad219eSEddie James if (e.name() == ERROR_DUMP_DISABLED) 397cbad219eSEddie James { 398cbad219eSEddie James log<level::INFO>("Dump is disabled, skipping"); 399cbad219eSEddie James } 400cbad219eSEddie James else 401cbad219eSEddie James { 402cbad219eSEddie James log<level::ERR>("Dump failed"); 403cbad219eSEddie James } 404cbad219eSEddie James } 405cbad219eSEddie James } 406cbad219eSEddie James } 407cbad219eSEddie James 408cbad219eSEddie James bool Manager::sbeCanDump(unsigned int instance) 409cbad219eSEddie James { 410cbad219eSEddie James struct pdbg_target* proc = getPdbgTarget(instance); 411cbad219eSEddie James 412cbad219eSEddie James if (!proc) 413cbad219eSEddie James { 414cbad219eSEddie James // allow the dump in the error case 415cbad219eSEddie James return true; 416cbad219eSEddie James } 417cbad219eSEddie James 418cbad219eSEddie James try 419cbad219eSEddie James { 420cbad219eSEddie James if (!openpower::phal::sbe::isDumpAllowed(proc)) 421cbad219eSEddie James { 422cbad219eSEddie James return false; 423cbad219eSEddie James } 424cbad219eSEddie James 425cbad219eSEddie James if (openpower::phal::pdbg::isSbeVitalAttnActive(proc)) 426cbad219eSEddie James { 427cbad219eSEddie James return false; 428cbad219eSEddie James } 429cbad219eSEddie James } 430cbad219eSEddie James catch (openpower::phal::exception::SbeError& e) 431cbad219eSEddie James { 432cbad219eSEddie James log<level::INFO>("Failed to query SBE state"); 433cbad219eSEddie James } 434cbad219eSEddie James 435cbad219eSEddie James // allow the dump in the error case 436cbad219eSEddie James return true; 437cbad219eSEddie James } 438cbad219eSEddie James 439cbad219eSEddie James void Manager::setSBEState(unsigned int instance, enum sbe_state state) 440cbad219eSEddie James { 441cbad219eSEddie James struct pdbg_target* proc = getPdbgTarget(instance); 442cbad219eSEddie James 443cbad219eSEddie James if (!proc) 444cbad219eSEddie James { 445cbad219eSEddie James return; 446cbad219eSEddie James } 447cbad219eSEddie James 448cbad219eSEddie James try 449cbad219eSEddie James { 450cbad219eSEddie James openpower::phal::sbe::setState(proc, state); 451cbad219eSEddie James } 452cbad219eSEddie James catch (const openpower::phal::exception::SbeError& e) 453cbad219eSEddie James { 454cbad219eSEddie James log<level::ERR>("Failed to set SBE state"); 455cbad219eSEddie James } 456cbad219eSEddie James } 457cbad219eSEddie James 458cbad219eSEddie James struct pdbg_target* Manager::getPdbgTarget(unsigned int instance) 459cbad219eSEddie James { 460cbad219eSEddie James if (!pdbgInitialized) 461cbad219eSEddie James { 462cbad219eSEddie James try 463cbad219eSEddie James { 464cbad219eSEddie James openpower::phal::pdbg::init(); 465cbad219eSEddie James pdbgInitialized = true; 466cbad219eSEddie James } 467cbad219eSEddie James catch (const openpower::phal::exception::PdbgError& e) 468cbad219eSEddie James { 469cbad219eSEddie James log<level::ERR>("pdbg initialization failed"); 470cbad219eSEddie James return nullptr; 471cbad219eSEddie James } 472cbad219eSEddie James } 473cbad219eSEddie James 474cbad219eSEddie James struct pdbg_target* proc = nullptr; 475cbad219eSEddie James pdbg_for_each_class_target("proc", proc) 476cbad219eSEddie James { 477cbad219eSEddie James if (pdbg_target_index(proc) == instance) 478cbad219eSEddie James { 479cbad219eSEddie James return proc; 480cbad219eSEddie James } 481cbad219eSEddie James } 482cbad219eSEddie James 483cbad219eSEddie James log<level::ERR>("Failed to get pdbg target"); 484cbad219eSEddie James return nullptr; 485cbad219eSEddie James } 486815f9f55STom Joseph #endif 487815f9f55STom Joseph 488a8857c50SChris Cain void Manager::pollerTimerExpired() 489a8857c50SChris Cain { 490a8857c50SChris Cain if (!_pollTimer) 491a8857c50SChris Cain { 492a8857c50SChris Cain log<level::ERR>( 493a8857c50SChris Cain "Manager::pollerTimerExpired() ERROR: Timer not defined"); 494a8857c50SChris Cain return; 495a8857c50SChris Cain } 496a8857c50SChris Cain 497a8857c50SChris Cain for (auto& obj : statusObjects) 498a8857c50SChris Cain { 499a7b74dc3SChris Cain #ifdef READ_OCC_SENSORS 500a7b74dc3SChris Cain auto id = obj->getOccInstanceID(); 501a7b74dc3SChris Cain #endif 502a7b74dc3SChris Cain if (!obj->occActive()) 503a7b74dc3SChris Cain { 504a7b74dc3SChris Cain // OCC is not running yet 505a7b74dc3SChris Cain #ifdef READ_OCC_SENSORS 506a7b74dc3SChris Cain setSensorValueToNaN(id); 507a7b74dc3SChris Cain #endif 508a7b74dc3SChris Cain continue; 509a7b74dc3SChris Cain } 510a7b74dc3SChris Cain 511a8857c50SChris Cain // Read sysfs to force kernel to poll OCC 512a8857c50SChris Cain obj->readOccState(); 513bb895cb8SChicago Duan 514bb895cb8SChicago Duan #ifdef READ_OCC_SENSORS 515bb895cb8SChicago Duan // Read occ sensor values 516bb895cb8SChicago Duan getSensorValues(id, obj->isMasterOcc()); 517bb895cb8SChicago Duan #endif 518a8857c50SChris Cain } 519a8857c50SChris Cain 520a7b74dc3SChris Cain if (activeCount > 0) 521a7b74dc3SChris Cain { 522a8857c50SChris Cain // Restart OCC poll timer 523a8857c50SChris Cain _pollTimer->restartOnce(std::chrono::seconds(pollInterval)); 524a8857c50SChris Cain } 525a7b74dc3SChris Cain else 526a7b74dc3SChris Cain { 527a7b74dc3SChris Cain // No OCCs running, so poll timer will not be restarted 528a7b74dc3SChris Cain log<level::INFO>( 529a7b74dc3SChris Cain fmt::format( 530a7b74dc3SChris Cain "Manager::pollerTimerExpired: poll timer will not be restarted") 531a7b74dc3SChris Cain .c_str()); 532a7b74dc3SChris Cain } 533a7b74dc3SChris Cain } 534a8857c50SChris Cain 535bb895cb8SChicago Duan #ifdef READ_OCC_SENSORS 536bb895cb8SChicago Duan void Manager::readTempSensors(const fs::path& path, uint32_t id) 537bb895cb8SChicago Duan { 538bb895cb8SChicago Duan std::regex expr{"temp\\d+_label$"}; // Example: temp5_label 539bb895cb8SChicago Duan for (auto& file : fs::directory_iterator(path)) 540bb895cb8SChicago Duan { 541bb895cb8SChicago Duan if (!std::regex_search(file.path().string(), expr)) 542bb895cb8SChicago Duan { 543bb895cb8SChicago Duan continue; 544bb895cb8SChicago Duan } 545bb895cb8SChicago Duan 546a26f1527SMatt Spinler uint32_t labelValue{0}; 547a26f1527SMatt Spinler 548a26f1527SMatt Spinler try 549a26f1527SMatt Spinler { 550a26f1527SMatt Spinler labelValue = readFile<uint32_t>(file.path()); 551a26f1527SMatt Spinler } 552a26f1527SMatt Spinler catch (const std::system_error& e) 553a26f1527SMatt Spinler { 554a26f1527SMatt Spinler log<level::DEBUG>( 555a26f1527SMatt Spinler fmt::format("readTempSensors: Failed reading {}, errno = {}", 556a26f1527SMatt Spinler file.path().string(), e.code().value()) 557a26f1527SMatt Spinler .c_str()); 558bb895cb8SChicago Duan continue; 559bb895cb8SChicago Duan } 560bb895cb8SChicago Duan 561bb895cb8SChicago Duan const std::string& tempLabel = "label"; 562bb895cb8SChicago Duan const std::string filePathString = file.path().string().substr( 563bb895cb8SChicago Duan 0, file.path().string().length() - tempLabel.length()); 564a26f1527SMatt Spinler 565a26f1527SMatt Spinler uint32_t fruTypeValue{0}; 566a26f1527SMatt Spinler try 567bb895cb8SChicago Duan { 568a26f1527SMatt Spinler fruTypeValue = readFile<uint32_t>(filePathString + fruTypeSuffix); 569a26f1527SMatt Spinler } 570a26f1527SMatt Spinler catch (const std::system_error& e) 571a26f1527SMatt Spinler { 572bb895cb8SChicago Duan log<level::DEBUG>( 573a26f1527SMatt Spinler fmt::format("readTempSensors: Failed reading {}, errno = {}", 574a26f1527SMatt Spinler filePathString + fruTypeSuffix, e.code().value()) 575bb895cb8SChicago Duan .c_str()); 576bb895cb8SChicago Duan continue; 577bb895cb8SChicago Duan } 578bb895cb8SChicago Duan 579bb895cb8SChicago Duan std::string sensorPath = 580bb895cb8SChicago Duan OCC_SENSORS_ROOT + std::string("/temperature/"); 581bb895cb8SChicago Duan 582ace67d85SMatt Spinler std::string dvfsTempPath; 583ace67d85SMatt Spinler 584bb895cb8SChicago Duan if (fruTypeValue == VRMVdd) 585bb895cb8SChicago Duan { 586bb895cb8SChicago Duan sensorPath.append("vrm_vdd" + std::to_string(id) + "_temp"); 587bb895cb8SChicago Duan } 588ace67d85SMatt Spinler else if (fruTypeValue == processorIoRing) 589ace67d85SMatt Spinler { 590ace67d85SMatt Spinler sensorPath.append("proc" + std::to_string(id) + "_ioring_temp"); 591ace67d85SMatt Spinler dvfsTempPath = std::string{OCC_SENSORS_ROOT} + "/temperature/proc" + 592ace67d85SMatt Spinler std::to_string(id) + "_ioring_dvfs_temp"; 593ace67d85SMatt Spinler } 594bb895cb8SChicago Duan else 595bb895cb8SChicago Duan { 59614d1402dSMatt Spinler uint16_t type = (labelValue & 0xFF000000) >> 24; 59714d1402dSMatt Spinler uint16_t instanceID = labelValue & 0x0000FFFF; 598bb895cb8SChicago Duan 599bb895cb8SChicago Duan if (type == OCC_DIMM_TEMP_SENSOR_TYPE) 600bb895cb8SChicago Duan { 6018b8abeedSMatt Spinler if (fruTypeValue == fruTypeNotAvailable) 6028b8abeedSMatt Spinler { 6038b8abeedSMatt Spinler // Not all DIMM related temps are available to read 6048b8abeedSMatt Spinler // (no _input file in this case) 6058b8abeedSMatt Spinler continue; 6068b8abeedSMatt Spinler } 607bb895cb8SChicago Duan auto iter = dimmTempSensorName.find(fruTypeValue); 608bb895cb8SChicago Duan if (iter == dimmTempSensorName.end()) 609bb895cb8SChicago Duan { 610b5ca1015SGeorge Liu log<level::ERR>( 611b5ca1015SGeorge Liu fmt::format( 612b5ca1015SGeorge Liu "readTempSensors: Fru type error! fruTypeValue = {}) ", 613bb895cb8SChicago Duan fruTypeValue) 614bb895cb8SChicago Duan .c_str()); 615bb895cb8SChicago Duan continue; 616bb895cb8SChicago Duan } 617bb895cb8SChicago Duan 618bb895cb8SChicago Duan sensorPath.append("dimm" + std::to_string(instanceID) + 619bb895cb8SChicago Duan iter->second); 620bb895cb8SChicago Duan } 621bb895cb8SChicago Duan else if (type == OCC_CPU_TEMP_SENSOR_TYPE) 622bb895cb8SChicago Duan { 623ace67d85SMatt Spinler if (fruTypeValue == processorCore) 624bb895cb8SChicago Duan { 625ff7afd98SMatt Spinler // The OCC reports small core temps, of which there are 626ff7afd98SMatt Spinler // two per big core. All current P10 systems are in big 627ff7afd98SMatt Spinler // core mode, so use a big core name. 628ff7afd98SMatt Spinler uint16_t coreNum = instanceID / 2; 629ff7afd98SMatt Spinler uint16_t tempNum = instanceID % 2; 630bb895cb8SChicago Duan sensorPath.append("proc" + std::to_string(id) + "_core" + 631ff7afd98SMatt Spinler std::to_string(coreNum) + "_" + 632ff7afd98SMatt Spinler std::to_string(tempNum) + "_temp"); 633ace67d85SMatt Spinler 634ace67d85SMatt Spinler dvfsTempPath = std::string{OCC_SENSORS_ROOT} + 635ace67d85SMatt Spinler "/temperature/proc" + std::to_string(id) + 636ace67d85SMatt Spinler "_core_dvfs_temp"; 637bb895cb8SChicago Duan } 638bb895cb8SChicago Duan else 639bb895cb8SChicago Duan { 640bb895cb8SChicago Duan continue; 641bb895cb8SChicago Duan } 642bb895cb8SChicago Duan } 643ace67d85SMatt Spinler else 644ace67d85SMatt Spinler { 645ace67d85SMatt Spinler continue; 646ace67d85SMatt Spinler } 647ace67d85SMatt Spinler } 648ace67d85SMatt Spinler 649ace67d85SMatt Spinler // The dvfs temp file only needs to be read once per chip per type. 650ace67d85SMatt Spinler if (!dvfsTempPath.empty() && 651ace67d85SMatt Spinler !dbus::OccDBusSensors::getOccDBus().hasDvfsTemp(dvfsTempPath)) 652ace67d85SMatt Spinler { 653ace67d85SMatt Spinler try 654ace67d85SMatt Spinler { 655ace67d85SMatt Spinler auto dvfsValue = readFile<double>(filePathString + maxSuffix); 656ace67d85SMatt Spinler 657ace67d85SMatt Spinler dbus::OccDBusSensors::getOccDBus().setDvfsTemp( 658ace67d85SMatt Spinler dvfsTempPath, dvfsValue * std::pow(10, -3)); 659ace67d85SMatt Spinler } 660ace67d85SMatt Spinler catch (const std::system_error& e) 661ace67d85SMatt Spinler { 662ace67d85SMatt Spinler log<level::DEBUG>( 663ace67d85SMatt Spinler fmt::format( 664ace67d85SMatt Spinler "readTempSensors: Failed reading {}, errno = {}", 665ace67d85SMatt Spinler filePathString + maxSuffix, e.code().value()) 666ace67d85SMatt Spinler .c_str()); 667ace67d85SMatt Spinler } 668ace67d85SMatt Spinler } 669bb895cb8SChicago Duan 670a26f1527SMatt Spinler uint32_t faultValue{0}; 671a26f1527SMatt Spinler try 672bb895cb8SChicago Duan { 673a26f1527SMatt Spinler faultValue = readFile<uint32_t>(filePathString + faultSuffix); 674a26f1527SMatt Spinler } 675a26f1527SMatt Spinler catch (const std::system_error& e) 676a26f1527SMatt Spinler { 677a26f1527SMatt Spinler log<level::DEBUG>( 678a26f1527SMatt Spinler fmt::format("readTempSensors: Failed reading {}, errno = {}", 679a26f1527SMatt Spinler filePathString + faultSuffix, e.code().value()) 680a26f1527SMatt Spinler .c_str()); 681a26f1527SMatt Spinler continue; 682a26f1527SMatt Spinler } 683bb895cb8SChicago Duan 684bb895cb8SChicago Duan if (faultValue != 0) 685bb895cb8SChicago Duan { 686bb895cb8SChicago Duan open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue( 687bb895cb8SChicago Duan sensorPath, std::numeric_limits<double>::quiet_NaN()); 688bb895cb8SChicago Duan 689bb895cb8SChicago Duan open_power::occ::dbus::OccDBusSensors::getOccDBus() 690bb895cb8SChicago Duan .setOperationalStatus(sensorPath, false); 691bb895cb8SChicago Duan 692bb895cb8SChicago Duan continue; 693bb895cb8SChicago Duan } 694bb895cb8SChicago Duan 695a26f1527SMatt Spinler double tempValue{0}; 696a26f1527SMatt Spinler 697a26f1527SMatt Spinler try 698bb895cb8SChicago Duan { 699a26f1527SMatt Spinler tempValue = readFile<double>(filePathString + inputSuffix); 700a26f1527SMatt Spinler } 701a26f1527SMatt Spinler catch (const std::system_error& e) 702a26f1527SMatt Spinler { 703a26f1527SMatt Spinler log<level::DEBUG>( 704a26f1527SMatt Spinler fmt::format("readTempSensors: Failed reading {}, errno = {}", 705a26f1527SMatt Spinler filePathString + inputSuffix, e.code().value()) 706a26f1527SMatt Spinler .c_str()); 707a26f1527SMatt Spinler continue; 708a26f1527SMatt Spinler } 709bb895cb8SChicago Duan 710bb895cb8SChicago Duan open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue( 711bb895cb8SChicago Duan sensorPath, tempValue * std::pow(10, -3)); 712bb895cb8SChicago Duan 713bb895cb8SChicago Duan open_power::occ::dbus::OccDBusSensors::getOccDBus() 714bb895cb8SChicago Duan .setOperationalStatus(sensorPath, true); 715bb895cb8SChicago Duan 7166fa848a9SChris Cain // At this point, the sensor will be created for sure. 7176fa848a9SChris Cain if (existingSensors.find(sensorPath) == existingSensors.end()) 7186fa848a9SChris Cain { 7196fa848a9SChris Cain open_power::occ::dbus::OccDBusSensors::getOccDBus() 7206fa848a9SChris Cain .setChassisAssociation(sensorPath); 7216fa848a9SChris Cain } 7226fa848a9SChris Cain 723bb895cb8SChicago Duan existingSensors[sensorPath] = id; 724bb895cb8SChicago Duan } 725bb895cb8SChicago Duan return; 726bb895cb8SChicago Duan } 727bb895cb8SChicago Duan 728bb895cb8SChicago Duan std::optional<std::string> 729bb895cb8SChicago Duan Manager::getPowerLabelFunctionID(const std::string& value) 730bb895cb8SChicago Duan { 731bb895cb8SChicago Duan // If the value is "system", then the FunctionID is "system". 732bb895cb8SChicago Duan if (value == "system") 733bb895cb8SChicago Duan { 734bb895cb8SChicago Duan return value; 735bb895cb8SChicago Duan } 736bb895cb8SChicago Duan 737bb895cb8SChicago Duan // If the value is not "system", then the label value have 3 numbers, of 738bb895cb8SChicago Duan // which we only care about the middle one: 739bb895cb8SChicago Duan // <sensor id>_<function id>_<apss channel> 740bb895cb8SChicago Duan // eg: The value is "0_10_5" , then the FunctionID is "10". 741bb895cb8SChicago Duan if (value.find("_") == std::string::npos) 742bb895cb8SChicago Duan { 743bb895cb8SChicago Duan return std::nullopt; 744bb895cb8SChicago Duan } 745bb895cb8SChicago Duan 746bb895cb8SChicago Duan auto powerLabelValue = value.substr((value.find("_") + 1)); 747bb895cb8SChicago Duan 748bb895cb8SChicago Duan if (powerLabelValue.find("_") == std::string::npos) 749bb895cb8SChicago Duan { 750bb895cb8SChicago Duan return std::nullopt; 751bb895cb8SChicago Duan } 752bb895cb8SChicago Duan 753bb895cb8SChicago Duan return powerLabelValue.substr(0, powerLabelValue.find("_")); 754bb895cb8SChicago Duan } 755bb895cb8SChicago Duan 756bb895cb8SChicago Duan void Manager::readPowerSensors(const fs::path& path, uint32_t id) 757bb895cb8SChicago Duan { 758bb895cb8SChicago Duan std::regex expr{"power\\d+_label$"}; // Example: power5_label 759bb895cb8SChicago Duan for (auto& file : fs::directory_iterator(path)) 760bb895cb8SChicago Duan { 761bb895cb8SChicago Duan if (!std::regex_search(file.path().string(), expr)) 762bb895cb8SChicago Duan { 763bb895cb8SChicago Duan continue; 764bb895cb8SChicago Duan } 765bb895cb8SChicago Duan 766a26f1527SMatt Spinler std::string labelValue; 767a26f1527SMatt Spinler try 768a26f1527SMatt Spinler { 769a26f1527SMatt Spinler labelValue = readFile<std::string>(file.path()); 770a26f1527SMatt Spinler } 771a26f1527SMatt Spinler catch (const std::system_error& e) 772a26f1527SMatt Spinler { 773a26f1527SMatt Spinler log<level::DEBUG>( 774a26f1527SMatt Spinler fmt::format("readPowerSensors: Failed reading {}, errno = {}", 775a26f1527SMatt Spinler file.path().string(), e.code().value()) 776a26f1527SMatt Spinler .c_str()); 777bb895cb8SChicago Duan continue; 778bb895cb8SChicago Duan } 779bb895cb8SChicago Duan 780bb895cb8SChicago Duan auto functionID = getPowerLabelFunctionID(labelValue); 781bb895cb8SChicago Duan if (functionID == std::nullopt) 782bb895cb8SChicago Duan { 783bb895cb8SChicago Duan continue; 784bb895cb8SChicago Duan } 785bb895cb8SChicago Duan 786bb895cb8SChicago Duan const std::string& tempLabel = "label"; 787bb895cb8SChicago Duan const std::string filePathString = file.path().string().substr( 788bb895cb8SChicago Duan 0, file.path().string().length() - tempLabel.length()); 789bb895cb8SChicago Duan 790bb895cb8SChicago Duan std::string sensorPath = OCC_SENSORS_ROOT + std::string("/power/"); 791bb895cb8SChicago Duan 792bb895cb8SChicago Duan auto iter = powerSensorName.find(*functionID); 793bb895cb8SChicago Duan if (iter == powerSensorName.end()) 794bb895cb8SChicago Duan { 795bb895cb8SChicago Duan continue; 796bb895cb8SChicago Duan } 797bb895cb8SChicago Duan sensorPath.append(iter->second); 798bb895cb8SChicago Duan 799a26f1527SMatt Spinler double tempValue{0}; 800a26f1527SMatt Spinler 801a26f1527SMatt Spinler try 802bb895cb8SChicago Duan { 803a26f1527SMatt Spinler tempValue = readFile<double>(filePathString + inputSuffix); 804a26f1527SMatt Spinler } 805a26f1527SMatt Spinler catch (const std::system_error& e) 806bb895cb8SChicago Duan { 807a26f1527SMatt Spinler log<level::DEBUG>( 808a26f1527SMatt Spinler fmt::format("readTempSensors: Failed reading {}, errno = {}", 809a26f1527SMatt Spinler filePathString + inputSuffix, e.code().value()) 810a26f1527SMatt Spinler .c_str()); 811bb895cb8SChicago Duan continue; 812bb895cb8SChicago Duan } 813bb895cb8SChicago Duan 814d84a8335SChris Cain open_power::occ::dbus::OccDBusSensors::getOccDBus().setUnit( 815d84a8335SChris Cain sensorPath, "xyz.openbmc_project.Sensor.Value.Unit.Watts"); 816d84a8335SChris Cain 817bb895cb8SChicago Duan open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue( 818bb895cb8SChicago Duan sensorPath, tempValue * std::pow(10, -3) * std::pow(10, -3)); 819bb895cb8SChicago Duan 820bb895cb8SChicago Duan open_power::occ::dbus::OccDBusSensors::getOccDBus() 821bb895cb8SChicago Duan .setOperationalStatus(sensorPath, true); 822bb895cb8SChicago Duan 8235901abdaSMatt Spinler if (existingSensors.find(sensorPath) == existingSensors.end()) 8245901abdaSMatt Spinler { 8255901abdaSMatt Spinler open_power::occ::dbus::OccDBusSensors::getOccDBus() 8265901abdaSMatt Spinler .setChassisAssociation(sensorPath); 8275901abdaSMatt Spinler } 8285901abdaSMatt Spinler 829bb895cb8SChicago Duan existingSensors[sensorPath] = id; 830bb895cb8SChicago Duan } 831bb895cb8SChicago Duan return; 832bb895cb8SChicago Duan } 833bb895cb8SChicago Duan 834bb895cb8SChicago Duan void Manager::setSensorValueToNaN(uint32_t id) 835bb895cb8SChicago Duan { 836bb895cb8SChicago Duan for (const auto& [sensorPath, occId] : existingSensors) 837bb895cb8SChicago Duan { 838bb895cb8SChicago Duan if (occId == id) 839bb895cb8SChicago Duan { 840bb895cb8SChicago Duan open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue( 841bb895cb8SChicago Duan sensorPath, std::numeric_limits<double>::quiet_NaN()); 842bb895cb8SChicago Duan } 843bb895cb8SChicago Duan } 844bb895cb8SChicago Duan return; 845bb895cb8SChicago Duan } 846bb895cb8SChicago Duan 847bb895cb8SChicago Duan void Manager::getSensorValues(uint32_t id, bool masterOcc) 848bb895cb8SChicago Duan { 849bb895cb8SChicago Duan const auto occ = std::string("occ-hwmon.") + std::to_string(id + 1); 850bb895cb8SChicago Duan 851bb895cb8SChicago Duan fs::path fileName{OCC_HWMON_PATH + occ + "/hwmon/"}; 852bb895cb8SChicago Duan 853bb895cb8SChicago Duan // Need to get the hwmonXX directory name, there better only be 1 dir 854bb895cb8SChicago Duan assert(std::distance(fs::directory_iterator(fileName), 855bb895cb8SChicago Duan fs::directory_iterator{}) == 1); 856bb895cb8SChicago Duan // Now set our path to this full path, including this hwmonXX directory 857bb895cb8SChicago Duan fileName = fs::path(*fs::directory_iterator(fileName)); 858bb895cb8SChicago Duan 859bb895cb8SChicago Duan // Read temperature sensors 860bb895cb8SChicago Duan readTempSensors(fileName, id); 861bb895cb8SChicago Duan 862bb895cb8SChicago Duan if (masterOcc) 863bb895cb8SChicago Duan { 864bb895cb8SChicago Duan // Read power sensors 865bb895cb8SChicago Duan readPowerSensors(fileName, id); 866bb895cb8SChicago Duan } 867bb895cb8SChicago Duan 868bb895cb8SChicago Duan return; 869bb895cb8SChicago Duan } 870bb895cb8SChicago Duan #endif 87117257673SChris Cain 87217257673SChris Cain // Read the altitude from DBus 87317257673SChris Cain void Manager::readAltitude() 87417257673SChris Cain { 87517257673SChris Cain static bool traceAltitudeErr = true; 87617257673SChris Cain 87717257673SChris Cain utils::PropertyValue altitudeProperty{}; 87817257673SChris Cain try 87917257673SChris Cain { 88017257673SChris Cain altitudeProperty = utils::getProperty(ALTITUDE_PATH, ALTITUDE_INTERFACE, 88117257673SChris Cain ALTITUDE_PROP); 88217257673SChris Cain auto sensorVal = std::get<double>(altitudeProperty); 88317257673SChris Cain if (sensorVal < 0xFFFF) 88417257673SChris Cain { 88517257673SChris Cain if (sensorVal < 0) 88617257673SChris Cain { 88717257673SChris Cain altitude = 0; 88817257673SChris Cain } 88917257673SChris Cain else 89017257673SChris Cain { 89117257673SChris Cain // Round to nearest meter 89217257673SChris Cain altitude = uint16_t(sensorVal + 0.5); 89317257673SChris Cain } 89417257673SChris Cain log<level::DEBUG>(fmt::format("readAltitude: sensor={} ({}m)", 89517257673SChris Cain sensorVal, altitude) 89617257673SChris Cain .c_str()); 89717257673SChris Cain traceAltitudeErr = true; 89817257673SChris Cain } 89917257673SChris Cain else 90017257673SChris Cain { 90117257673SChris Cain if (traceAltitudeErr) 90217257673SChris Cain { 90317257673SChris Cain traceAltitudeErr = false; 90417257673SChris Cain log<level::DEBUG>( 90517257673SChris Cain fmt::format("Invalid altitude value: {}", sensorVal) 90617257673SChris Cain .c_str()); 90717257673SChris Cain } 90817257673SChris Cain } 90917257673SChris Cain } 91017257673SChris Cain catch (const sdbusplus::exception::exception& e) 91117257673SChris Cain { 91217257673SChris Cain if (traceAltitudeErr) 91317257673SChris Cain { 91417257673SChris Cain traceAltitudeErr = false; 91517257673SChris Cain log<level::INFO>( 91617257673SChris Cain fmt::format("Unable to read Altitude: {}", e.what()).c_str()); 91717257673SChris Cain } 91817257673SChris Cain altitude = 0xFFFF; // not available 91917257673SChris Cain } 92017257673SChris Cain } 92117257673SChris Cain 92217257673SChris Cain // Callback function when ambient temperature changes 92317257673SChris Cain void Manager::ambientCallback(sdbusplus::message::message& msg) 92417257673SChris Cain { 92517257673SChris Cain double currentTemp = 0; 92617257673SChris Cain uint8_t truncatedTemp = 0xFF; 92717257673SChris Cain std::string msgSensor; 92817257673SChris Cain std::map<std::string, std::variant<double>> msgData; 92917257673SChris Cain msg.read(msgSensor, msgData); 93017257673SChris Cain 93117257673SChris Cain auto valPropMap = msgData.find(AMBIENT_PROP); 93217257673SChris Cain if (valPropMap == msgData.end()) 93317257673SChris Cain { 93417257673SChris Cain log<level::DEBUG>("ambientCallback: Unknown ambient property changed"); 93517257673SChris Cain return; 93617257673SChris Cain } 93717257673SChris Cain currentTemp = std::get<double>(valPropMap->second); 93817257673SChris Cain if (std::isnan(currentTemp)) 93917257673SChris Cain { 94017257673SChris Cain truncatedTemp = 0xFF; 94117257673SChris Cain } 94217257673SChris Cain else 94317257673SChris Cain { 94417257673SChris Cain if (currentTemp < 0) 94517257673SChris Cain { 94617257673SChris Cain truncatedTemp = 0; 94717257673SChris Cain } 94817257673SChris Cain else 94917257673SChris Cain { 95017257673SChris Cain // Round to nearest degree C 95117257673SChris Cain truncatedTemp = uint8_t(currentTemp + 0.5); 95217257673SChris Cain } 95317257673SChris Cain } 95417257673SChris Cain 95517257673SChris Cain // If ambient changes, notify OCCs 95617257673SChris Cain if (truncatedTemp != ambient) 95717257673SChris Cain { 95817257673SChris Cain log<level::DEBUG>( 95917257673SChris Cain fmt::format("ambientCallback: Ambient change from {} to {}C", 96017257673SChris Cain ambient, currentTemp) 96117257673SChris Cain .c_str()); 96217257673SChris Cain 96317257673SChris Cain ambient = truncatedTemp; 96417257673SChris Cain if (altitude == 0xFFFF) 96517257673SChris Cain { 96617257673SChris Cain // No altitude yet, try reading again 96717257673SChris Cain readAltitude(); 96817257673SChris Cain } 96917257673SChris Cain 97017257673SChris Cain log<level::DEBUG>( 97117257673SChris Cain fmt::format("ambientCallback: Ambient: {}C, altitude: {}m", ambient, 97217257673SChris Cain altitude) 97317257673SChris Cain .c_str()); 97417257673SChris Cain #ifdef POWER10 97517257673SChris Cain // Send ambient and altitude to all OCCs 97617257673SChris Cain for (auto& obj : statusObjects) 97717257673SChris Cain { 97817257673SChris Cain if (obj->occActive()) 97917257673SChris Cain { 98017257673SChris Cain obj->sendAmbient(ambient, altitude); 98117257673SChris Cain } 98217257673SChris Cain } 98317257673SChris Cain #endif // POWER10 98417257673SChris Cain } 98517257673SChris Cain } 98617257673SChris Cain 98717257673SChris Cain // return the current ambient and altitude readings 98817257673SChris Cain void Manager::getAmbientData(bool& ambientValid, uint8_t& ambientTemp, 98917257673SChris Cain uint16_t& altitudeValue) const 99017257673SChris Cain { 99117257673SChris Cain ambientValid = true; 99217257673SChris Cain ambientTemp = ambient; 99317257673SChris Cain altitudeValue = altitude; 99417257673SChris Cain 99517257673SChris Cain if (ambient == 0xFF) 99617257673SChris Cain { 99717257673SChris Cain ambientValid = false; 99817257673SChris Cain } 99917257673SChris Cain } 100017257673SChris Cain 1001a7b74dc3SChris Cain #ifdef POWER10 1002a7b74dc3SChris Cain void Manager::occsNotAllRunning() 1003a7b74dc3SChris Cain { 10046fa848a9SChris Cain // Function will also gets called when occ-control app gets 10056fa848a9SChris Cain // restarted. (occ active sensors do not change, so the Status 10066fa848a9SChris Cain // object does not call Manager back for all OCCs) 1007a7b74dc3SChris Cain 1008a7b74dc3SChris Cain if (activeCount != statusObjects.size()) 1009a7b74dc3SChris Cain { 1010a7b74dc3SChris Cain // Not all OCCs went active 1011a7b74dc3SChris Cain log<level::WARNING>( 1012a7b74dc3SChris Cain fmt::format( 1013a7b74dc3SChris Cain "occsNotAllRunning: Active OCC count ({}) does not match expected count ({})", 1014a7b74dc3SChris Cain activeCount, statusObjects.size()) 1015a7b74dc3SChris Cain .c_str()); 1016a7b74dc3SChris Cain // Procs may be garded, so may not need reset. 1017a7b74dc3SChris Cain } 1018a7b74dc3SChris Cain 1019a7b74dc3SChris Cain validateOccMaster(); 1020a7b74dc3SChris Cain } 1021a7b74dc3SChris Cain #endif // POWER10 1022a7b74dc3SChris Cain 1023a7b74dc3SChris Cain // Verify single master OCC and start presence monitor 1024a7b74dc3SChris Cain void Manager::validateOccMaster() 1025a7b74dc3SChris Cain { 1026a7b74dc3SChris Cain int masterInstance = -1; 1027a7b74dc3SChris Cain for (auto& obj : statusObjects) 1028a7b74dc3SChris Cain { 1029a7b74dc3SChris Cain obj->addPresenceWatchMaster(); 1030a7b74dc3SChris Cain if (obj->isMasterOcc()) 1031a7b74dc3SChris Cain { 1032a7b74dc3SChris Cain if (masterInstance == -1) 1033a7b74dc3SChris Cain { 1034a7b74dc3SChris Cain masterInstance = obj->getOccInstanceID(); 1035a7b74dc3SChris Cain } 1036a7b74dc3SChris Cain else 1037a7b74dc3SChris Cain { 1038a7b74dc3SChris Cain log<level::ERR>( 1039a7b74dc3SChris Cain fmt::format( 1040a7b74dc3SChris Cain "validateOccMaster: Multiple OCC masters! ({} and {})", 1041a7b74dc3SChris Cain masterInstance, obj->getOccInstanceID()) 1042a7b74dc3SChris Cain .c_str()); 1043a7b74dc3SChris Cain // request reset 1044a7b74dc3SChris Cain obj->deviceError(); 1045a7b74dc3SChris Cain } 1046a7b74dc3SChris Cain } 1047a7b74dc3SChris Cain } 1048a7b74dc3SChris Cain if (masterInstance < 0) 1049a7b74dc3SChris Cain { 1050a7b74dc3SChris Cain log<level::ERR>("validateOccMaster: Master OCC not found!"); 1051a7b74dc3SChris Cain // request reset 1052a7b74dc3SChris Cain statusObjects.front()->deviceError(); 1053a7b74dc3SChris Cain } 1054a7b74dc3SChris Cain else 1055a7b74dc3SChris Cain { 1056a7b74dc3SChris Cain log<level::INFO>( 105736f9cdedSChris Cain fmt::format("validateOccMaster: OCC{} is master of {} OCCs", 105836f9cdedSChris Cain masterInstance, activeCount) 1059a7b74dc3SChris Cain .c_str()); 1060a7b74dc3SChris Cain } 1061a7b74dc3SChris Cain } 1062a7b74dc3SChris Cain 1063dfc7ec73SVishwanatha Subbanna } // namespace occ 1064dfc7ec73SVishwanatha Subbanna } // namespace open_power 1065