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 30a8857c50SChris Cain using namespace phosphor::logging; 31a7b74dc3SChris Cain using namespace std::literals::chrono_literals; 32a8857c50SChris Cain 33a26f1527SMatt Spinler template <typename T> 34a26f1527SMatt Spinler T readFile(const std::string& path) 35a26f1527SMatt Spinler { 36a26f1527SMatt Spinler std::ifstream ifs; 37a26f1527SMatt Spinler ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit | 38a26f1527SMatt Spinler std::ifstream::eofbit); 39a26f1527SMatt Spinler T data; 40a26f1527SMatt Spinler 41a26f1527SMatt Spinler try 42a26f1527SMatt Spinler { 43a26f1527SMatt Spinler ifs.open(path); 44a26f1527SMatt Spinler ifs >> data; 45a26f1527SMatt Spinler ifs.close(); 46a26f1527SMatt Spinler } 47a26f1527SMatt Spinler catch (const std::exception& e) 48a26f1527SMatt Spinler { 49a26f1527SMatt Spinler auto err = errno; 50a26f1527SMatt Spinler throw std::system_error(err, std::generic_category()); 51a26f1527SMatt Spinler } 52a26f1527SMatt Spinler 53a26f1527SMatt Spinler return data; 54a26f1527SMatt Spinler } 55a26f1527SMatt Spinler 56dfc7ec73SVishwanatha Subbanna void Manager::findAndCreateObjects() 57dfc7ec73SVishwanatha Subbanna { 58d267cec2SMatt Spinler #ifndef POWER10 59dfc7ec73SVishwanatha Subbanna for (auto id = 0; id < MAX_CPUS; ++id) 60dfc7ec73SVishwanatha Subbanna { 6130417a15SDeepak Kodihalli // Create one occ per cpu 6230417a15SDeepak Kodihalli auto occ = std::string(OCC_NAME) + std::to_string(id); 63dfc7ec73SVishwanatha Subbanna createObjects(occ); 64dfc7ec73SVishwanatha Subbanna } 65d267cec2SMatt Spinler #else 66d267cec2SMatt Spinler // Create the OCCs based on on the /dev/occX devices 67d267cec2SMatt Spinler auto occs = findOCCsInDev(); 68d267cec2SMatt Spinler 69d267cec2SMatt Spinler if (occs.empty() || (prevOCCSearch.size() != occs.size())) 70d267cec2SMatt Spinler { 71d267cec2SMatt Spinler // Something changed or no OCCs yet, try again in 10s. 72d267cec2SMatt Spinler // Note on the first pass prevOCCSearch will be empty, 73d267cec2SMatt Spinler // so there will be at least one delay to give things 74d267cec2SMatt Spinler // a chance to settle. 75d267cec2SMatt Spinler prevOCCSearch = occs; 76d267cec2SMatt Spinler 77d267cec2SMatt Spinler discoverTimer->restartOnce(10s); 78d267cec2SMatt Spinler } 79d267cec2SMatt Spinler else 80d267cec2SMatt Spinler { 81d267cec2SMatt Spinler discoverTimer.reset(); 82d267cec2SMatt Spinler 83d267cec2SMatt Spinler // createObjects requires OCC0 first. 84d267cec2SMatt Spinler std::sort(occs.begin(), occs.end()); 85d267cec2SMatt Spinler 86d267cec2SMatt Spinler for (auto id : occs) 87d267cec2SMatt Spinler { 88d267cec2SMatt Spinler createObjects(std::string(OCC_NAME) + std::to_string(id)); 89d267cec2SMatt Spinler } 90d267cec2SMatt Spinler } 91d267cec2SMatt Spinler #endif 92d267cec2SMatt Spinler } 93d267cec2SMatt Spinler 94d267cec2SMatt Spinler std::vector<int> Manager::findOCCsInDev() 95d267cec2SMatt Spinler { 96d267cec2SMatt Spinler std::vector<int> occs; 97d267cec2SMatt Spinler std::regex expr{R"(occ(\d+)$)"}; 98d267cec2SMatt Spinler 99d267cec2SMatt Spinler for (auto& file : fs::directory_iterator("/dev")) 100d267cec2SMatt Spinler { 101d267cec2SMatt Spinler std::smatch match; 102d267cec2SMatt Spinler std::string path{file.path().string()}; 103d267cec2SMatt Spinler if (std::regex_search(path, match, expr)) 104d267cec2SMatt Spinler { 105d267cec2SMatt Spinler auto num = std::stoi(match[1].str()); 106d267cec2SMatt Spinler 107d267cec2SMatt Spinler // /dev numbering starts at 1, ours starts at 0. 108d267cec2SMatt Spinler occs.push_back(num - 1); 109d267cec2SMatt Spinler } 110d267cec2SMatt Spinler } 111d267cec2SMatt Spinler 112d267cec2SMatt Spinler return occs; 113dfc7ec73SVishwanatha Subbanna } 114dfc7ec73SVishwanatha Subbanna 115dfc7ec73SVishwanatha Subbanna int Manager::cpuCreated(sdbusplus::message::message& msg) 116dfc7ec73SVishwanatha Subbanna { 117bcef3b48SGeorge Liu namespace fs = std::filesystem; 118dfc7ec73SVishwanatha Subbanna 119dfc7ec73SVishwanatha Subbanna sdbusplus::message::object_path o; 120dfc7ec73SVishwanatha Subbanna msg.read(o); 121dfc7ec73SVishwanatha Subbanna fs::path cpuPath(std::string(std::move(o))); 122dfc7ec73SVishwanatha Subbanna 123dfc7ec73SVishwanatha Subbanna auto name = cpuPath.filename().string(); 124dfc7ec73SVishwanatha Subbanna auto index = name.find(CPU_NAME); 125dfc7ec73SVishwanatha Subbanna name.replace(index, std::strlen(CPU_NAME), OCC_NAME); 126dfc7ec73SVishwanatha Subbanna 127dfc7ec73SVishwanatha Subbanna createObjects(name); 128dfc7ec73SVishwanatha Subbanna 129dfc7ec73SVishwanatha Subbanna return 0; 130dfc7ec73SVishwanatha Subbanna } 131dfc7ec73SVishwanatha Subbanna 132dfc7ec73SVishwanatha Subbanna void Manager::createObjects(const std::string& occ) 133dfc7ec73SVishwanatha Subbanna { 134dfc7ec73SVishwanatha Subbanna auto path = fs::path(OCC_CONTROL_ROOT) / occ; 135dfc7ec73SVishwanatha Subbanna 1366fa848a9SChris Cain #ifdef POWER10 1376fa848a9SChris Cain if (!pmode) 1386fa848a9SChris Cain { 139*1be4337bSChris Cain // Create the power mode object 140*1be4337bSChris Cain pmode = std::make_unique<open_power::occ::powermode::PowerMode>( 141*1be4337bSChris Cain *this, powermode::PMODE_PATH, powermode::PIPS_PATH); 1426fa848a9SChris Cain } 1436fa848a9SChris Cain #endif 1446fa848a9SChris Cain 14594df8c90SGunnar Mills statusObjects.emplace_back(std::make_unique<Status>( 146f3b7514eSGeorge Liu event, path.c_str(), *this, 14736f9cdedSChris Cain #ifdef POWER10 14836f9cdedSChris Cain pmode, 14936f9cdedSChris Cain #endif 15094df8c90SGunnar Mills std::bind(std::mem_fn(&Manager::statusCallBack), this, 15100325238STom Joseph std::placeholders::_1) 15200325238STom Joseph #ifdef PLDM 15300325238STom Joseph , 15400325238STom Joseph std::bind(std::mem_fn(&pldm::Interface::resetOCC), pldmHandle.get(), 15500325238STom Joseph std::placeholders::_1) 15600325238STom Joseph #endif 15700325238STom Joseph )); 158dfc7ec73SVishwanatha Subbanna 15936f9cdedSChris Cain if (statusObjects.back()->isMasterOcc()) 16036f9cdedSChris Cain { 16136f9cdedSChris Cain log<level::INFO>( 16236f9cdedSChris Cain fmt::format("Manager::createObjects(): OCC{} is the master", 16336f9cdedSChris Cain statusObjects.back()->getOccInstanceID()) 16436f9cdedSChris Cain .c_str()); 16536f9cdedSChris Cain _pollTimer->setEnabled(false); 16636f9cdedSChris Cain 16736f9cdedSChris Cain // Create the power cap monitor object for master OCC 168dfc7ec73SVishwanatha Subbanna if (!pcap) 169dfc7ec73SVishwanatha Subbanna { 170dfc7ec73SVishwanatha Subbanna pcap = std::make_unique<open_power::occ::powercap::PowerCap>( 171*1be4337bSChris Cain *statusObjects.back()); 172dfc7ec73SVishwanatha Subbanna } 17378e86012SChris Cain 17478e86012SChris Cain #ifdef POWER10 1756fa848a9SChris Cain // Set the master OCC on the PowerMode object 1766fa848a9SChris Cain pmode->setMasterOcc(path); 17778e86012SChris Cain #endif 178dfc7ec73SVishwanatha Subbanna } 179dfc7ec73SVishwanatha Subbanna 18036f9cdedSChris Cain passThroughObjects.emplace_back(std::make_unique<PassThrough>(path.c_str() 18136f9cdedSChris Cain #ifdef POWER10 18236f9cdedSChris Cain , 18336f9cdedSChris Cain pmode 18436f9cdedSChris Cain #endif 18536f9cdedSChris Cain )); 18636f9cdedSChris Cain } 18736f9cdedSChris Cain 188dfc7ec73SVishwanatha Subbanna void Manager::statusCallBack(bool status) 189dfc7ec73SVishwanatha Subbanna { 19094df8c90SGunnar Mills using InternalFailure = 19194df8c90SGunnar Mills sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 192dfc7ec73SVishwanatha Subbanna 193dfc7ec73SVishwanatha Subbanna // At this time, it won't happen but keeping it 194dfc7ec73SVishwanatha Subbanna // here just in case something changes in the future 195dfc7ec73SVishwanatha Subbanna if ((activeCount == 0) && (!status)) 196dfc7ec73SVishwanatha Subbanna { 197dfc7ec73SVishwanatha Subbanna log<level::ERR>("Invalid update on OCCActive"); 198dfc7ec73SVishwanatha Subbanna elog<InternalFailure>(); 199dfc7ec73SVishwanatha Subbanna } 200dfc7ec73SVishwanatha Subbanna 201a7b74dc3SChris Cain if (status == true) 202a7b74dc3SChris Cain { 203a7b74dc3SChris Cain // OCC went active 204a7b74dc3SChris Cain ++activeCount; 205dae2d940SEddie James 206a7b74dc3SChris Cain #ifdef POWER10 207a7b74dc3SChris Cain if (activeCount == 1) 208a7b74dc3SChris Cain { 209a7b74dc3SChris Cain // First OCC went active (allow some time for all OCCs to go active) 210a7b74dc3SChris Cain waitForAllOccsTimer->restartOnce(30s); 211a7b74dc3SChris Cain } 212a7b74dc3SChris Cain #endif 213a7b74dc3SChris Cain 214dae2d940SEddie James if (activeCount == statusObjects.size()) 215dae2d940SEddie James { 216a7b74dc3SChris Cain #ifdef POWER10 217a7b74dc3SChris Cain // All OCCs are now running 218a7b74dc3SChris Cain if (waitForAllOccsTimer->isEnabled()) 219dae2d940SEddie James { 220a7b74dc3SChris Cain // stop occ wait timer 221a7b74dc3SChris Cain waitForAllOccsTimer->setEnabled(false); 222dae2d940SEddie James } 223a7b74dc3SChris Cain #endif 224a7b74dc3SChris Cain 225a7b74dc3SChris Cain // Verify master OCC and start presence monitor 226a7b74dc3SChris Cain validateOccMaster(); 227dae2d940SEddie James } 228a8857c50SChris Cain 229a7b74dc3SChris Cain // Start poll timer if not already started 230a7b74dc3SChris Cain if (!_pollTimer->isEnabled()) 231a8857c50SChris Cain { 232b5ca1015SGeorge Liu log<level::INFO>( 23336f9cdedSChris Cain fmt::format("Manager: OCCs will be polled every {} seconds", 23436f9cdedSChris Cain pollInterval) 235a8857c50SChris Cain .c_str()); 236a8857c50SChris Cain 237a8857c50SChris Cain // Send poll and start OCC poll timer 238a8857c50SChris Cain pollerTimerExpired(); 239a8857c50SChris Cain } 240a7b74dc3SChris Cain } 241a7b74dc3SChris Cain else 242a8857c50SChris Cain { 243a7b74dc3SChris Cain // OCC went away 244a7b74dc3SChris Cain --activeCount; 245a7b74dc3SChris Cain 246a7b74dc3SChris Cain if (activeCount == 0) 247a7b74dc3SChris Cain { 248a7b74dc3SChris Cain // No OCCs are running 249a7b74dc3SChris Cain 250a8857c50SChris Cain // Stop OCC poll timer 251a7b74dc3SChris Cain if (_pollTimer->isEnabled()) 252a7b74dc3SChris Cain { 253b5ca1015SGeorge Liu log<level::INFO>( 254b5ca1015SGeorge Liu "Manager::statusCallBack(): OCCs are not running, stopping poll timer"); 255a8857c50SChris Cain _pollTimer->setEnabled(false); 256a7b74dc3SChris Cain } 257a7b74dc3SChris Cain 258a7b74dc3SChris Cain #ifdef POWER10 259a7b74dc3SChris Cain // stop wait timer 260a7b74dc3SChris Cain if (waitForAllOccsTimer->isEnabled()) 261a7b74dc3SChris Cain { 262a7b74dc3SChris Cain waitForAllOccsTimer->setEnabled(false); 263a7b74dc3SChris Cain } 264a7b74dc3SChris Cain #endif 26553f68148SMatt Spinler 26653f68148SMatt Spinler #ifdef READ_OCC_SENSORS 267a7b74dc3SChris Cain // Clear OCC sensors 26853f68148SMatt Spinler for (auto& obj : statusObjects) 26953f68148SMatt Spinler { 27053f68148SMatt Spinler setSensorValueToNaN(obj->getOccInstanceID()); 27153f68148SMatt Spinler } 27253f68148SMatt Spinler #endif 273a8857c50SChris Cain } 274dfc7ec73SVishwanatha Subbanna } 275a7b74dc3SChris Cain } 276dfc7ec73SVishwanatha Subbanna 277dfc7ec73SVishwanatha Subbanna #ifdef I2C_OCC 278dfc7ec73SVishwanatha Subbanna void Manager::initStatusObjects() 279dfc7ec73SVishwanatha Subbanna { 280dfc7ec73SVishwanatha Subbanna // Make sure we have a valid path string 281dfc7ec73SVishwanatha Subbanna static_assert(sizeof(DEV_PATH) != 0); 282dfc7ec73SVishwanatha Subbanna 283dfc7ec73SVishwanatha Subbanna auto deviceNames = i2c_occ::getOccHwmonDevices(DEV_PATH); 28441470e56SLei YU auto occMasterName = deviceNames.front(); 285dfc7ec73SVishwanatha Subbanna for (auto& name : deviceNames) 286dfc7ec73SVishwanatha Subbanna { 287dfc7ec73SVishwanatha Subbanna i2c_occ::i2cToDbus(name); 288b5259a1eSLei YU name = std::string(OCC_NAME) + '_' + name; 289dfc7ec73SVishwanatha Subbanna auto path = fs::path(OCC_CONTROL_ROOT) / name; 290dfc7ec73SVishwanatha Subbanna statusObjects.emplace_back( 291f3b7514eSGeorge Liu std::make_unique<Status>(event, path.c_str(), *this)); 292dfc7ec73SVishwanatha Subbanna } 29341470e56SLei YU // The first device is master occ 29441470e56SLei YU pcap = std::make_unique<open_power::occ::powercap::PowerCap>( 295f3b7514eSGeorge Liu *statusObjects.front(), occMasterName); 29678e86012SChris Cain #ifdef POWER10 297*1be4337bSChris Cain pmode = std::make_unique<open_power::occ::powermode::PowerMode>( 298*1be4337bSChris Cain *this, open_power::occ::powermode::PMODE_PATH, 299*1be4337bSChris Cain open_power::occ::powermode::PIPS_PATH); 3006fa848a9SChris Cain // Set the master OCC on the PowerMode object 3016fa848a9SChris Cain pmode->setMasterOcc(path); 30278e86012SChris Cain #endif 303dfc7ec73SVishwanatha Subbanna } 304dfc7ec73SVishwanatha Subbanna #endif 305dfc7ec73SVishwanatha Subbanna 306815f9f55STom Joseph #ifdef PLDM 307cbad219eSEddie James void Manager::sbeTimeout(unsigned int instance) 308cbad219eSEddie James { 309cbad219eSEddie James log<level::INFO>("SBE timeout, requesting HRESET", 310cbad219eSEddie James entry("SBE=%d", instance)); 311cbad219eSEddie James 312cbad219eSEddie James setSBEState(instance, SBE_STATE_NOT_USABLE); 313cbad219eSEddie James 314cbad219eSEddie James pldmHandle->sendHRESET(instance); 315cbad219eSEddie James } 316cbad219eSEddie James 317815f9f55STom Joseph bool Manager::updateOCCActive(instanceID instance, bool status) 318815f9f55STom Joseph { 319815f9f55STom Joseph return (statusObjects[instance])->occActive(status); 320815f9f55STom Joseph } 321cbad219eSEddie James 322cbad219eSEddie James void Manager::sbeHRESETResult(instanceID instance, bool success) 323cbad219eSEddie James { 324cbad219eSEddie James if (success) 325cbad219eSEddie James { 326cbad219eSEddie James log<level::INFO>("HRESET succeeded", entry("SBE=%d", instance)); 327cbad219eSEddie James 328cbad219eSEddie James setSBEState(instance, SBE_STATE_BOOTED); 329cbad219eSEddie James 330cbad219eSEddie James return; 331cbad219eSEddie James } 332cbad219eSEddie James 333cbad219eSEddie James setSBEState(instance, SBE_STATE_FAILED); 334cbad219eSEddie James 335cbad219eSEddie James if (sbeCanDump(instance)) 336cbad219eSEddie James { 337cbad219eSEddie James log<level::INFO>("HRESET failed, triggering SBE dump", 338cbad219eSEddie James entry("SBE=%d", instance)); 339cbad219eSEddie James 340cbad219eSEddie James auto& bus = utils::getBus(); 341cbad219eSEddie James uint32_t src6 = instance << 16; 342cbad219eSEddie James uint32_t logId = 343cbad219eSEddie James FFDC::createPEL("org.open_power.Processor.Error.SbeChipOpTimeout", 344cbad219eSEddie James src6, "SBE command timeout"); 345cbad219eSEddie James 346cbad219eSEddie James try 347cbad219eSEddie James { 348f3a4a69fSGeorge Liu constexpr auto path = "/org/openpower/dump"; 349f3a4a69fSGeorge Liu constexpr auto interface = "xyz.openbmc_project.Dump.Create"; 350f3a4a69fSGeorge Liu constexpr auto function = "CreateDump"; 351f3a4a69fSGeorge Liu 352cbad219eSEddie James std::string service = utils::getService(path, interface); 353cbad219eSEddie James auto method = 354cbad219eSEddie James bus.new_method_call(service.c_str(), path, interface, function); 355cbad219eSEddie James 356cbad219eSEddie James std::map<std::string, std::variant<std::string, uint64_t>> 357cbad219eSEddie James createParams{ 358cbad219eSEddie James {"com.ibm.Dump.Create.CreateParameters.ErrorLogId", 359cbad219eSEddie James uint64_t(logId)}, 360cbad219eSEddie James {"com.ibm.Dump.Create.CreateParameters.DumpType", 361cbad219eSEddie James "com.ibm.Dump.Create.DumpType.SBE"}, 362cbad219eSEddie James {"com.ibm.Dump.Create.CreateParameters.FailingUnitId", 363cbad219eSEddie James uint64_t(instance)}, 364cbad219eSEddie James }; 365cbad219eSEddie James 366cbad219eSEddie James method.append(createParams); 367cbad219eSEddie James 368cbad219eSEddie James auto response = bus.call(method); 369cbad219eSEddie James } 370cbad219eSEddie James catch (const sdbusplus::exception::exception& e) 371cbad219eSEddie James { 372cbad219eSEddie James constexpr auto ERROR_DUMP_DISABLED = 373cbad219eSEddie James "xyz.openbmc_project.Dump.Create.Error.Disabled"; 374cbad219eSEddie James if (e.name() == ERROR_DUMP_DISABLED) 375cbad219eSEddie James { 376cbad219eSEddie James log<level::INFO>("Dump is disabled, skipping"); 377cbad219eSEddie James } 378cbad219eSEddie James else 379cbad219eSEddie James { 380cbad219eSEddie James log<level::ERR>("Dump failed"); 381cbad219eSEddie James } 382cbad219eSEddie James } 383cbad219eSEddie James } 384cbad219eSEddie James } 385cbad219eSEddie James 386cbad219eSEddie James bool Manager::sbeCanDump(unsigned int instance) 387cbad219eSEddie James { 388cbad219eSEddie James struct pdbg_target* proc = getPdbgTarget(instance); 389cbad219eSEddie James 390cbad219eSEddie James if (!proc) 391cbad219eSEddie James { 392cbad219eSEddie James // allow the dump in the error case 393cbad219eSEddie James return true; 394cbad219eSEddie James } 395cbad219eSEddie James 396cbad219eSEddie James try 397cbad219eSEddie James { 398cbad219eSEddie James if (!openpower::phal::sbe::isDumpAllowed(proc)) 399cbad219eSEddie James { 400cbad219eSEddie James return false; 401cbad219eSEddie James } 402cbad219eSEddie James 403cbad219eSEddie James if (openpower::phal::pdbg::isSbeVitalAttnActive(proc)) 404cbad219eSEddie James { 405cbad219eSEddie James return false; 406cbad219eSEddie James } 407cbad219eSEddie James } 408cbad219eSEddie James catch (openpower::phal::exception::SbeError& e) 409cbad219eSEddie James { 410cbad219eSEddie James log<level::INFO>("Failed to query SBE state"); 411cbad219eSEddie James } 412cbad219eSEddie James 413cbad219eSEddie James // allow the dump in the error case 414cbad219eSEddie James return true; 415cbad219eSEddie James } 416cbad219eSEddie James 417cbad219eSEddie James void Manager::setSBEState(unsigned int instance, enum sbe_state state) 418cbad219eSEddie James { 419cbad219eSEddie James struct pdbg_target* proc = getPdbgTarget(instance); 420cbad219eSEddie James 421cbad219eSEddie James if (!proc) 422cbad219eSEddie James { 423cbad219eSEddie James return; 424cbad219eSEddie James } 425cbad219eSEddie James 426cbad219eSEddie James try 427cbad219eSEddie James { 428cbad219eSEddie James openpower::phal::sbe::setState(proc, state); 429cbad219eSEddie James } 430cbad219eSEddie James catch (const openpower::phal::exception::SbeError& e) 431cbad219eSEddie James { 432cbad219eSEddie James log<level::ERR>("Failed to set SBE state"); 433cbad219eSEddie James } 434cbad219eSEddie James } 435cbad219eSEddie James 436cbad219eSEddie James struct pdbg_target* Manager::getPdbgTarget(unsigned int instance) 437cbad219eSEddie James { 438cbad219eSEddie James if (!pdbgInitialized) 439cbad219eSEddie James { 440cbad219eSEddie James try 441cbad219eSEddie James { 442cbad219eSEddie James openpower::phal::pdbg::init(); 443cbad219eSEddie James pdbgInitialized = true; 444cbad219eSEddie James } 445cbad219eSEddie James catch (const openpower::phal::exception::PdbgError& e) 446cbad219eSEddie James { 447cbad219eSEddie James log<level::ERR>("pdbg initialization failed"); 448cbad219eSEddie James return nullptr; 449cbad219eSEddie James } 450cbad219eSEddie James } 451cbad219eSEddie James 452cbad219eSEddie James struct pdbg_target* proc = nullptr; 453cbad219eSEddie James pdbg_for_each_class_target("proc", proc) 454cbad219eSEddie James { 455cbad219eSEddie James if (pdbg_target_index(proc) == instance) 456cbad219eSEddie James { 457cbad219eSEddie James return proc; 458cbad219eSEddie James } 459cbad219eSEddie James } 460cbad219eSEddie James 461cbad219eSEddie James log<level::ERR>("Failed to get pdbg target"); 462cbad219eSEddie James return nullptr; 463cbad219eSEddie James } 464815f9f55STom Joseph #endif 465815f9f55STom Joseph 466a8857c50SChris Cain void Manager::pollerTimerExpired() 467a8857c50SChris Cain { 468a8857c50SChris Cain if (!_pollTimer) 469a8857c50SChris Cain { 470a8857c50SChris Cain log<level::ERR>( 471a8857c50SChris Cain "Manager::pollerTimerExpired() ERROR: Timer not defined"); 472a8857c50SChris Cain return; 473a8857c50SChris Cain } 474a8857c50SChris Cain 475a8857c50SChris Cain for (auto& obj : statusObjects) 476a8857c50SChris Cain { 477a7b74dc3SChris Cain #ifdef READ_OCC_SENSORS 478a7b74dc3SChris Cain auto id = obj->getOccInstanceID(); 479a7b74dc3SChris Cain #endif 480a7b74dc3SChris Cain if (!obj->occActive()) 481a7b74dc3SChris Cain { 482a7b74dc3SChris Cain // OCC is not running yet 483a7b74dc3SChris Cain #ifdef READ_OCC_SENSORS 484a7b74dc3SChris Cain setSensorValueToNaN(id); 485a7b74dc3SChris Cain #endif 486a7b74dc3SChris Cain continue; 487a7b74dc3SChris Cain } 488a7b74dc3SChris Cain 489a8857c50SChris Cain // Read sysfs to force kernel to poll OCC 490a8857c50SChris Cain obj->readOccState(); 491bb895cb8SChicago Duan 492bb895cb8SChicago Duan #ifdef READ_OCC_SENSORS 493bb895cb8SChicago Duan // Read occ sensor values 494bb895cb8SChicago Duan getSensorValues(id, obj->isMasterOcc()); 495bb895cb8SChicago Duan #endif 496a8857c50SChris Cain } 497a8857c50SChris Cain 498a7b74dc3SChris Cain if (activeCount > 0) 499a7b74dc3SChris Cain { 500a8857c50SChris Cain // Restart OCC poll timer 501a8857c50SChris Cain _pollTimer->restartOnce(std::chrono::seconds(pollInterval)); 502a8857c50SChris Cain } 503a7b74dc3SChris Cain else 504a7b74dc3SChris Cain { 505a7b74dc3SChris Cain // No OCCs running, so poll timer will not be restarted 506a7b74dc3SChris Cain log<level::INFO>( 507a7b74dc3SChris Cain fmt::format( 508a7b74dc3SChris Cain "Manager::pollerTimerExpired: poll timer will not be restarted") 509a7b74dc3SChris Cain .c_str()); 510a7b74dc3SChris Cain } 511a7b74dc3SChris Cain } 512a8857c50SChris Cain 513bb895cb8SChicago Duan #ifdef READ_OCC_SENSORS 514bb895cb8SChicago Duan void Manager::readTempSensors(const fs::path& path, uint32_t id) 515bb895cb8SChicago Duan { 516bb895cb8SChicago Duan std::regex expr{"temp\\d+_label$"}; // Example: temp5_label 517bb895cb8SChicago Duan for (auto& file : fs::directory_iterator(path)) 518bb895cb8SChicago Duan { 519bb895cb8SChicago Duan if (!std::regex_search(file.path().string(), expr)) 520bb895cb8SChicago Duan { 521bb895cb8SChicago Duan continue; 522bb895cb8SChicago Duan } 523bb895cb8SChicago Duan 524a26f1527SMatt Spinler uint32_t labelValue{0}; 525a26f1527SMatt Spinler 526a26f1527SMatt Spinler try 527a26f1527SMatt Spinler { 528a26f1527SMatt Spinler labelValue = readFile<uint32_t>(file.path()); 529a26f1527SMatt Spinler } 530a26f1527SMatt Spinler catch (const std::system_error& e) 531a26f1527SMatt Spinler { 532a26f1527SMatt Spinler log<level::DEBUG>( 533a26f1527SMatt Spinler fmt::format("readTempSensors: Failed reading {}, errno = {}", 534a26f1527SMatt Spinler file.path().string(), e.code().value()) 535a26f1527SMatt Spinler .c_str()); 536bb895cb8SChicago Duan continue; 537bb895cb8SChicago Duan } 538bb895cb8SChicago Duan 539bb895cb8SChicago Duan const std::string& tempLabel = "label"; 540bb895cb8SChicago Duan const std::string filePathString = file.path().string().substr( 541bb895cb8SChicago Duan 0, file.path().string().length() - tempLabel.length()); 542a26f1527SMatt Spinler 543a26f1527SMatt Spinler uint32_t fruTypeValue{0}; 544a26f1527SMatt Spinler try 545bb895cb8SChicago Duan { 546a26f1527SMatt Spinler fruTypeValue = readFile<uint32_t>(filePathString + fruTypeSuffix); 547a26f1527SMatt Spinler } 548a26f1527SMatt Spinler catch (const std::system_error& e) 549a26f1527SMatt Spinler { 550bb895cb8SChicago Duan log<level::DEBUG>( 551a26f1527SMatt Spinler fmt::format("readTempSensors: Failed reading {}, errno = {}", 552a26f1527SMatt Spinler filePathString + fruTypeSuffix, e.code().value()) 553bb895cb8SChicago Duan .c_str()); 554bb895cb8SChicago Duan continue; 555bb895cb8SChicago Duan } 556bb895cb8SChicago Duan 557bb895cb8SChicago Duan std::string sensorPath = 558bb895cb8SChicago Duan OCC_SENSORS_ROOT + std::string("/temperature/"); 559bb895cb8SChicago Duan 560ace67d85SMatt Spinler std::string dvfsTempPath; 561ace67d85SMatt Spinler 562bb895cb8SChicago Duan if (fruTypeValue == VRMVdd) 563bb895cb8SChicago Duan { 564bb895cb8SChicago Duan sensorPath.append("vrm_vdd" + std::to_string(id) + "_temp"); 565bb895cb8SChicago Duan } 566ace67d85SMatt Spinler else if (fruTypeValue == processorIoRing) 567ace67d85SMatt Spinler { 568ace67d85SMatt Spinler sensorPath.append("proc" + std::to_string(id) + "_ioring_temp"); 569ace67d85SMatt Spinler dvfsTempPath = std::string{OCC_SENSORS_ROOT} + "/temperature/proc" + 570ace67d85SMatt Spinler std::to_string(id) + "_ioring_dvfs_temp"; 571ace67d85SMatt Spinler } 572bb895cb8SChicago Duan else 573bb895cb8SChicago Duan { 57414d1402dSMatt Spinler uint16_t type = (labelValue & 0xFF000000) >> 24; 57514d1402dSMatt Spinler uint16_t instanceID = labelValue & 0x0000FFFF; 576bb895cb8SChicago Duan 577bb895cb8SChicago Duan if (type == OCC_DIMM_TEMP_SENSOR_TYPE) 578bb895cb8SChicago Duan { 5798b8abeedSMatt Spinler if (fruTypeValue == fruTypeNotAvailable) 5808b8abeedSMatt Spinler { 5818b8abeedSMatt Spinler // Not all DIMM related temps are available to read 5828b8abeedSMatt Spinler // (no _input file in this case) 5838b8abeedSMatt Spinler continue; 5848b8abeedSMatt Spinler } 585bb895cb8SChicago Duan auto iter = dimmTempSensorName.find(fruTypeValue); 586bb895cb8SChicago Duan if (iter == dimmTempSensorName.end()) 587bb895cb8SChicago Duan { 588b5ca1015SGeorge Liu log<level::ERR>( 589b5ca1015SGeorge Liu fmt::format( 590b5ca1015SGeorge Liu "readTempSensors: Fru type error! fruTypeValue = {}) ", 591bb895cb8SChicago Duan fruTypeValue) 592bb895cb8SChicago Duan .c_str()); 593bb895cb8SChicago Duan continue; 594bb895cb8SChicago Duan } 595bb895cb8SChicago Duan 596bb895cb8SChicago Duan sensorPath.append("dimm" + std::to_string(instanceID) + 597bb895cb8SChicago Duan iter->second); 598bb895cb8SChicago Duan } 599bb895cb8SChicago Duan else if (type == OCC_CPU_TEMP_SENSOR_TYPE) 600bb895cb8SChicago Duan { 601ace67d85SMatt Spinler if (fruTypeValue == processorCore) 602bb895cb8SChicago Duan { 603ff7afd98SMatt Spinler // The OCC reports small core temps, of which there are 604ff7afd98SMatt Spinler // two per big core. All current P10 systems are in big 605ff7afd98SMatt Spinler // core mode, so use a big core name. 606ff7afd98SMatt Spinler uint16_t coreNum = instanceID / 2; 607ff7afd98SMatt Spinler uint16_t tempNum = instanceID % 2; 608bb895cb8SChicago Duan sensorPath.append("proc" + std::to_string(id) + "_core" + 609ff7afd98SMatt Spinler std::to_string(coreNum) + "_" + 610ff7afd98SMatt Spinler std::to_string(tempNum) + "_temp"); 611ace67d85SMatt Spinler 612ace67d85SMatt Spinler dvfsTempPath = std::string{OCC_SENSORS_ROOT} + 613ace67d85SMatt Spinler "/temperature/proc" + std::to_string(id) + 614ace67d85SMatt Spinler "_core_dvfs_temp"; 615bb895cb8SChicago Duan } 616bb895cb8SChicago Duan else 617bb895cb8SChicago Duan { 618bb895cb8SChicago Duan continue; 619bb895cb8SChicago Duan } 620bb895cb8SChicago Duan } 621ace67d85SMatt Spinler else 622ace67d85SMatt Spinler { 623ace67d85SMatt Spinler continue; 624ace67d85SMatt Spinler } 625ace67d85SMatt Spinler } 626ace67d85SMatt Spinler 627ace67d85SMatt Spinler // The dvfs temp file only needs to be read once per chip per type. 628ace67d85SMatt Spinler if (!dvfsTempPath.empty() && 629ace67d85SMatt Spinler !dbus::OccDBusSensors::getOccDBus().hasDvfsTemp(dvfsTempPath)) 630ace67d85SMatt Spinler { 631ace67d85SMatt Spinler try 632ace67d85SMatt Spinler { 633ace67d85SMatt Spinler auto dvfsValue = readFile<double>(filePathString + maxSuffix); 634ace67d85SMatt Spinler 635ace67d85SMatt Spinler dbus::OccDBusSensors::getOccDBus().setDvfsTemp( 636ace67d85SMatt Spinler dvfsTempPath, dvfsValue * std::pow(10, -3)); 637ace67d85SMatt Spinler } 638ace67d85SMatt Spinler catch (const std::system_error& e) 639ace67d85SMatt Spinler { 640ace67d85SMatt Spinler log<level::DEBUG>( 641ace67d85SMatt Spinler fmt::format( 642ace67d85SMatt Spinler "readTempSensors: Failed reading {}, errno = {}", 643ace67d85SMatt Spinler filePathString + maxSuffix, e.code().value()) 644ace67d85SMatt Spinler .c_str()); 645ace67d85SMatt Spinler } 646ace67d85SMatt Spinler } 647bb895cb8SChicago Duan 648a26f1527SMatt Spinler uint32_t faultValue{0}; 649a26f1527SMatt Spinler try 650bb895cb8SChicago Duan { 651a26f1527SMatt Spinler faultValue = readFile<uint32_t>(filePathString + faultSuffix); 652a26f1527SMatt Spinler } 653a26f1527SMatt Spinler catch (const std::system_error& e) 654a26f1527SMatt Spinler { 655a26f1527SMatt Spinler log<level::DEBUG>( 656a26f1527SMatt Spinler fmt::format("readTempSensors: Failed reading {}, errno = {}", 657a26f1527SMatt Spinler filePathString + faultSuffix, e.code().value()) 658a26f1527SMatt Spinler .c_str()); 659a26f1527SMatt Spinler continue; 660a26f1527SMatt Spinler } 661bb895cb8SChicago Duan 662bb895cb8SChicago Duan if (faultValue != 0) 663bb895cb8SChicago Duan { 664bb895cb8SChicago Duan open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue( 665bb895cb8SChicago Duan sensorPath, std::numeric_limits<double>::quiet_NaN()); 666bb895cb8SChicago Duan 667bb895cb8SChicago Duan open_power::occ::dbus::OccDBusSensors::getOccDBus() 668bb895cb8SChicago Duan .setOperationalStatus(sensorPath, false); 669bb895cb8SChicago Duan 670bb895cb8SChicago Duan continue; 671bb895cb8SChicago Duan } 672bb895cb8SChicago Duan 673a26f1527SMatt Spinler double tempValue{0}; 674a26f1527SMatt Spinler 675a26f1527SMatt Spinler try 676bb895cb8SChicago Duan { 677a26f1527SMatt Spinler tempValue = readFile<double>(filePathString + inputSuffix); 678a26f1527SMatt Spinler } 679a26f1527SMatt Spinler catch (const std::system_error& e) 680a26f1527SMatt Spinler { 681a26f1527SMatt Spinler log<level::DEBUG>( 682a26f1527SMatt Spinler fmt::format("readTempSensors: Failed reading {}, errno = {}", 683a26f1527SMatt Spinler filePathString + inputSuffix, e.code().value()) 684a26f1527SMatt Spinler .c_str()); 685a26f1527SMatt Spinler continue; 686a26f1527SMatt Spinler } 687bb895cb8SChicago Duan 688bb895cb8SChicago Duan open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue( 689bb895cb8SChicago Duan sensorPath, tempValue * std::pow(10, -3)); 690bb895cb8SChicago Duan 691bb895cb8SChicago Duan open_power::occ::dbus::OccDBusSensors::getOccDBus() 692bb895cb8SChicago Duan .setOperationalStatus(sensorPath, true); 693bb895cb8SChicago Duan 6946fa848a9SChris Cain // At this point, the sensor will be created for sure. 6956fa848a9SChris Cain if (existingSensors.find(sensorPath) == existingSensors.end()) 6966fa848a9SChris Cain { 6976fa848a9SChris Cain open_power::occ::dbus::OccDBusSensors::getOccDBus() 6986fa848a9SChris Cain .setChassisAssociation(sensorPath); 6996fa848a9SChris Cain } 7006fa848a9SChris Cain 701bb895cb8SChicago Duan existingSensors[sensorPath] = id; 702bb895cb8SChicago Duan } 703bb895cb8SChicago Duan return; 704bb895cb8SChicago Duan } 705bb895cb8SChicago Duan 706bb895cb8SChicago Duan std::optional<std::string> 707bb895cb8SChicago Duan Manager::getPowerLabelFunctionID(const std::string& value) 708bb895cb8SChicago Duan { 709bb895cb8SChicago Duan // If the value is "system", then the FunctionID is "system". 710bb895cb8SChicago Duan if (value == "system") 711bb895cb8SChicago Duan { 712bb895cb8SChicago Duan return value; 713bb895cb8SChicago Duan } 714bb895cb8SChicago Duan 715bb895cb8SChicago Duan // If the value is not "system", then the label value have 3 numbers, of 716bb895cb8SChicago Duan // which we only care about the middle one: 717bb895cb8SChicago Duan // <sensor id>_<function id>_<apss channel> 718bb895cb8SChicago Duan // eg: The value is "0_10_5" , then the FunctionID is "10". 719bb895cb8SChicago Duan if (value.find("_") == std::string::npos) 720bb895cb8SChicago Duan { 721bb895cb8SChicago Duan return std::nullopt; 722bb895cb8SChicago Duan } 723bb895cb8SChicago Duan 724bb895cb8SChicago Duan auto powerLabelValue = value.substr((value.find("_") + 1)); 725bb895cb8SChicago Duan 726bb895cb8SChicago Duan if (powerLabelValue.find("_") == std::string::npos) 727bb895cb8SChicago Duan { 728bb895cb8SChicago Duan return std::nullopt; 729bb895cb8SChicago Duan } 730bb895cb8SChicago Duan 731bb895cb8SChicago Duan return powerLabelValue.substr(0, powerLabelValue.find("_")); 732bb895cb8SChicago Duan } 733bb895cb8SChicago Duan 734bb895cb8SChicago Duan void Manager::readPowerSensors(const fs::path& path, uint32_t id) 735bb895cb8SChicago Duan { 736bb895cb8SChicago Duan std::regex expr{"power\\d+_label$"}; // Example: power5_label 737bb895cb8SChicago Duan for (auto& file : fs::directory_iterator(path)) 738bb895cb8SChicago Duan { 739bb895cb8SChicago Duan if (!std::regex_search(file.path().string(), expr)) 740bb895cb8SChicago Duan { 741bb895cb8SChicago Duan continue; 742bb895cb8SChicago Duan } 743bb895cb8SChicago Duan 744a26f1527SMatt Spinler std::string labelValue; 745a26f1527SMatt Spinler try 746a26f1527SMatt Spinler { 747a26f1527SMatt Spinler labelValue = readFile<std::string>(file.path()); 748a26f1527SMatt Spinler } 749a26f1527SMatt Spinler catch (const std::system_error& e) 750a26f1527SMatt Spinler { 751a26f1527SMatt Spinler log<level::DEBUG>( 752a26f1527SMatt Spinler fmt::format("readPowerSensors: Failed reading {}, errno = {}", 753a26f1527SMatt Spinler file.path().string(), e.code().value()) 754a26f1527SMatt Spinler .c_str()); 755bb895cb8SChicago Duan continue; 756bb895cb8SChicago Duan } 757bb895cb8SChicago Duan 758bb895cb8SChicago Duan auto functionID = getPowerLabelFunctionID(labelValue); 759bb895cb8SChicago Duan if (functionID == std::nullopt) 760bb895cb8SChicago Duan { 761bb895cb8SChicago Duan continue; 762bb895cb8SChicago Duan } 763bb895cb8SChicago Duan 764bb895cb8SChicago Duan const std::string& tempLabel = "label"; 765bb895cb8SChicago Duan const std::string filePathString = file.path().string().substr( 766bb895cb8SChicago Duan 0, file.path().string().length() - tempLabel.length()); 767bb895cb8SChicago Duan 768bb895cb8SChicago Duan std::string sensorPath = OCC_SENSORS_ROOT + std::string("/power/"); 769bb895cb8SChicago Duan 770bb895cb8SChicago Duan auto iter = powerSensorName.find(*functionID); 771bb895cb8SChicago Duan if (iter == powerSensorName.end()) 772bb895cb8SChicago Duan { 773bb895cb8SChicago Duan continue; 774bb895cb8SChicago Duan } 775bb895cb8SChicago Duan sensorPath.append(iter->second); 776bb895cb8SChicago Duan 777a26f1527SMatt Spinler double tempValue{0}; 778a26f1527SMatt Spinler 779a26f1527SMatt Spinler try 780bb895cb8SChicago Duan { 781a26f1527SMatt Spinler tempValue = readFile<double>(filePathString + inputSuffix); 782a26f1527SMatt Spinler } 783a26f1527SMatt Spinler catch (const std::system_error& e) 784bb895cb8SChicago Duan { 785a26f1527SMatt Spinler log<level::DEBUG>( 786a26f1527SMatt Spinler fmt::format("readTempSensors: Failed reading {}, errno = {}", 787a26f1527SMatt Spinler filePathString + inputSuffix, e.code().value()) 788a26f1527SMatt Spinler .c_str()); 789bb895cb8SChicago Duan continue; 790bb895cb8SChicago Duan } 791bb895cb8SChicago Duan 792d84a8335SChris Cain open_power::occ::dbus::OccDBusSensors::getOccDBus().setUnit( 793d84a8335SChris Cain sensorPath, "xyz.openbmc_project.Sensor.Value.Unit.Watts"); 794d84a8335SChris Cain 795bb895cb8SChicago Duan open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue( 796bb895cb8SChicago Duan sensorPath, tempValue * std::pow(10, -3) * std::pow(10, -3)); 797bb895cb8SChicago Duan 798bb895cb8SChicago Duan open_power::occ::dbus::OccDBusSensors::getOccDBus() 799bb895cb8SChicago Duan .setOperationalStatus(sensorPath, true); 800bb895cb8SChicago Duan 8015901abdaSMatt Spinler if (existingSensors.find(sensorPath) == existingSensors.end()) 8025901abdaSMatt Spinler { 8035901abdaSMatt Spinler open_power::occ::dbus::OccDBusSensors::getOccDBus() 8045901abdaSMatt Spinler .setChassisAssociation(sensorPath); 8055901abdaSMatt Spinler } 8065901abdaSMatt Spinler 807bb895cb8SChicago Duan existingSensors[sensorPath] = id; 808bb895cb8SChicago Duan } 809bb895cb8SChicago Duan return; 810bb895cb8SChicago Duan } 811bb895cb8SChicago Duan 812bb895cb8SChicago Duan void Manager::setSensorValueToNaN(uint32_t id) 813bb895cb8SChicago Duan { 814bb895cb8SChicago Duan for (const auto& [sensorPath, occId] : existingSensors) 815bb895cb8SChicago Duan { 816bb895cb8SChicago Duan if (occId == id) 817bb895cb8SChicago Duan { 818bb895cb8SChicago Duan open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue( 819bb895cb8SChicago Duan sensorPath, std::numeric_limits<double>::quiet_NaN()); 820bb895cb8SChicago Duan } 821bb895cb8SChicago Duan } 822bb895cb8SChicago Duan return; 823bb895cb8SChicago Duan } 824bb895cb8SChicago Duan 825bb895cb8SChicago Duan void Manager::getSensorValues(uint32_t id, bool masterOcc) 826bb895cb8SChicago Duan { 827bb895cb8SChicago Duan const auto occ = std::string("occ-hwmon.") + std::to_string(id + 1); 828bb895cb8SChicago Duan 829bb895cb8SChicago Duan fs::path fileName{OCC_HWMON_PATH + occ + "/hwmon/"}; 830bb895cb8SChicago Duan 831bb895cb8SChicago Duan // Need to get the hwmonXX directory name, there better only be 1 dir 832bb895cb8SChicago Duan assert(std::distance(fs::directory_iterator(fileName), 833bb895cb8SChicago Duan fs::directory_iterator{}) == 1); 834bb895cb8SChicago Duan // Now set our path to this full path, including this hwmonXX directory 835bb895cb8SChicago Duan fileName = fs::path(*fs::directory_iterator(fileName)); 836bb895cb8SChicago Duan 837bb895cb8SChicago Duan // Read temperature sensors 838bb895cb8SChicago Duan readTempSensors(fileName, id); 839bb895cb8SChicago Duan 840bb895cb8SChicago Duan if (masterOcc) 841bb895cb8SChicago Duan { 842bb895cb8SChicago Duan // Read power sensors 843bb895cb8SChicago Duan readPowerSensors(fileName, id); 844bb895cb8SChicago Duan } 845bb895cb8SChicago Duan 846bb895cb8SChicago Duan return; 847bb895cb8SChicago Duan } 848bb895cb8SChicago Duan #endif 84917257673SChris Cain 85017257673SChris Cain // Read the altitude from DBus 85117257673SChris Cain void Manager::readAltitude() 85217257673SChris Cain { 85317257673SChris Cain static bool traceAltitudeErr = true; 85417257673SChris Cain 85517257673SChris Cain utils::PropertyValue altitudeProperty{}; 85617257673SChris Cain try 85717257673SChris Cain { 85817257673SChris Cain altitudeProperty = utils::getProperty(ALTITUDE_PATH, ALTITUDE_INTERFACE, 85917257673SChris Cain ALTITUDE_PROP); 86017257673SChris Cain auto sensorVal = std::get<double>(altitudeProperty); 86117257673SChris Cain if (sensorVal < 0xFFFF) 86217257673SChris Cain { 86317257673SChris Cain if (sensorVal < 0) 86417257673SChris Cain { 86517257673SChris Cain altitude = 0; 86617257673SChris Cain } 86717257673SChris Cain else 86817257673SChris Cain { 86917257673SChris Cain // Round to nearest meter 87017257673SChris Cain altitude = uint16_t(sensorVal + 0.5); 87117257673SChris Cain } 87217257673SChris Cain log<level::DEBUG>(fmt::format("readAltitude: sensor={} ({}m)", 87317257673SChris Cain sensorVal, altitude) 87417257673SChris Cain .c_str()); 87517257673SChris Cain traceAltitudeErr = true; 87617257673SChris Cain } 87717257673SChris Cain else 87817257673SChris Cain { 87917257673SChris Cain if (traceAltitudeErr) 88017257673SChris Cain { 88117257673SChris Cain traceAltitudeErr = false; 88217257673SChris Cain log<level::DEBUG>( 88317257673SChris Cain fmt::format("Invalid altitude value: {}", sensorVal) 88417257673SChris Cain .c_str()); 88517257673SChris Cain } 88617257673SChris Cain } 88717257673SChris Cain } 88817257673SChris Cain catch (const sdbusplus::exception::exception& e) 88917257673SChris Cain { 89017257673SChris Cain if (traceAltitudeErr) 89117257673SChris Cain { 89217257673SChris Cain traceAltitudeErr = false; 89317257673SChris Cain log<level::INFO>( 89417257673SChris Cain fmt::format("Unable to read Altitude: {}", e.what()).c_str()); 89517257673SChris Cain } 89617257673SChris Cain altitude = 0xFFFF; // not available 89717257673SChris Cain } 89817257673SChris Cain } 89917257673SChris Cain 90017257673SChris Cain // Callback function when ambient temperature changes 90117257673SChris Cain void Manager::ambientCallback(sdbusplus::message::message& msg) 90217257673SChris Cain { 90317257673SChris Cain double currentTemp = 0; 90417257673SChris Cain uint8_t truncatedTemp = 0xFF; 90517257673SChris Cain std::string msgSensor; 90617257673SChris Cain std::map<std::string, std::variant<double>> msgData; 90717257673SChris Cain msg.read(msgSensor, msgData); 90817257673SChris Cain 90917257673SChris Cain auto valPropMap = msgData.find(AMBIENT_PROP); 91017257673SChris Cain if (valPropMap == msgData.end()) 91117257673SChris Cain { 91217257673SChris Cain log<level::DEBUG>("ambientCallback: Unknown ambient property changed"); 91317257673SChris Cain return; 91417257673SChris Cain } 91517257673SChris Cain currentTemp = std::get<double>(valPropMap->second); 91617257673SChris Cain if (std::isnan(currentTemp)) 91717257673SChris Cain { 91817257673SChris Cain truncatedTemp = 0xFF; 91917257673SChris Cain } 92017257673SChris Cain else 92117257673SChris Cain { 92217257673SChris Cain if (currentTemp < 0) 92317257673SChris Cain { 92417257673SChris Cain truncatedTemp = 0; 92517257673SChris Cain } 92617257673SChris Cain else 92717257673SChris Cain { 92817257673SChris Cain // Round to nearest degree C 92917257673SChris Cain truncatedTemp = uint8_t(currentTemp + 0.5); 93017257673SChris Cain } 93117257673SChris Cain } 93217257673SChris Cain 93317257673SChris Cain // If ambient changes, notify OCCs 93417257673SChris Cain if (truncatedTemp != ambient) 93517257673SChris Cain { 93617257673SChris Cain log<level::DEBUG>( 93717257673SChris Cain fmt::format("ambientCallback: Ambient change from {} to {}C", 93817257673SChris Cain ambient, currentTemp) 93917257673SChris Cain .c_str()); 94017257673SChris Cain 94117257673SChris Cain ambient = truncatedTemp; 94217257673SChris Cain if (altitude == 0xFFFF) 94317257673SChris Cain { 94417257673SChris Cain // No altitude yet, try reading again 94517257673SChris Cain readAltitude(); 94617257673SChris Cain } 94717257673SChris Cain 94817257673SChris Cain log<level::DEBUG>( 94917257673SChris Cain fmt::format("ambientCallback: Ambient: {}C, altitude: {}m", ambient, 95017257673SChris Cain altitude) 95117257673SChris Cain .c_str()); 95217257673SChris Cain #ifdef POWER10 95317257673SChris Cain // Send ambient and altitude to all OCCs 95417257673SChris Cain for (auto& obj : statusObjects) 95517257673SChris Cain { 95617257673SChris Cain if (obj->occActive()) 95717257673SChris Cain { 95817257673SChris Cain obj->sendAmbient(ambient, altitude); 95917257673SChris Cain } 96017257673SChris Cain } 96117257673SChris Cain #endif // POWER10 96217257673SChris Cain } 96317257673SChris Cain } 96417257673SChris Cain 96517257673SChris Cain // return the current ambient and altitude readings 96617257673SChris Cain void Manager::getAmbientData(bool& ambientValid, uint8_t& ambientTemp, 96717257673SChris Cain uint16_t& altitudeValue) const 96817257673SChris Cain { 96917257673SChris Cain ambientValid = true; 97017257673SChris Cain ambientTemp = ambient; 97117257673SChris Cain altitudeValue = altitude; 97217257673SChris Cain 97317257673SChris Cain if (ambient == 0xFF) 97417257673SChris Cain { 97517257673SChris Cain ambientValid = false; 97617257673SChris Cain } 97717257673SChris Cain } 97817257673SChris Cain 979a7b74dc3SChris Cain #ifdef POWER10 980a7b74dc3SChris Cain void Manager::occsNotAllRunning() 981a7b74dc3SChris Cain { 9826fa848a9SChris Cain // Function will also gets called when occ-control app gets 9836fa848a9SChris Cain // restarted. (occ active sensors do not change, so the Status 9846fa848a9SChris Cain // object does not call Manager back for all OCCs) 985a7b74dc3SChris Cain 986a7b74dc3SChris Cain if (activeCount != statusObjects.size()) 987a7b74dc3SChris Cain { 988a7b74dc3SChris Cain // Not all OCCs went active 989a7b74dc3SChris Cain log<level::WARNING>( 990a7b74dc3SChris Cain fmt::format( 991a7b74dc3SChris Cain "occsNotAllRunning: Active OCC count ({}) does not match expected count ({})", 992a7b74dc3SChris Cain activeCount, statusObjects.size()) 993a7b74dc3SChris Cain .c_str()); 994a7b74dc3SChris Cain // Procs may be garded, so may not need reset. 995a7b74dc3SChris Cain } 996a7b74dc3SChris Cain 997a7b74dc3SChris Cain validateOccMaster(); 998a7b74dc3SChris Cain } 999a7b74dc3SChris Cain #endif // POWER10 1000a7b74dc3SChris Cain 1001a7b74dc3SChris Cain // Verify single master OCC and start presence monitor 1002a7b74dc3SChris Cain void Manager::validateOccMaster() 1003a7b74dc3SChris Cain { 1004a7b74dc3SChris Cain int masterInstance = -1; 1005a7b74dc3SChris Cain for (auto& obj : statusObjects) 1006a7b74dc3SChris Cain { 1007a7b74dc3SChris Cain obj->addPresenceWatchMaster(); 1008a7b74dc3SChris Cain if (obj->isMasterOcc()) 1009a7b74dc3SChris Cain { 1010a7b74dc3SChris Cain if (masterInstance == -1) 1011a7b74dc3SChris Cain { 1012a7b74dc3SChris Cain masterInstance = obj->getOccInstanceID(); 1013a7b74dc3SChris Cain } 1014a7b74dc3SChris Cain else 1015a7b74dc3SChris Cain { 1016a7b74dc3SChris Cain log<level::ERR>( 1017a7b74dc3SChris Cain fmt::format( 1018a7b74dc3SChris Cain "validateOccMaster: Multiple OCC masters! ({} and {})", 1019a7b74dc3SChris Cain masterInstance, obj->getOccInstanceID()) 1020a7b74dc3SChris Cain .c_str()); 1021a7b74dc3SChris Cain // request reset 1022a7b74dc3SChris Cain obj->deviceError(); 1023a7b74dc3SChris Cain } 1024a7b74dc3SChris Cain } 1025a7b74dc3SChris Cain } 1026a7b74dc3SChris Cain if (masterInstance < 0) 1027a7b74dc3SChris Cain { 1028a7b74dc3SChris Cain log<level::ERR>("validateOccMaster: Master OCC not found!"); 1029a7b74dc3SChris Cain // request reset 1030a7b74dc3SChris Cain statusObjects.front()->deviceError(); 1031a7b74dc3SChris Cain } 1032a7b74dc3SChris Cain else 1033a7b74dc3SChris Cain { 1034a7b74dc3SChris Cain log<level::INFO>( 103536f9cdedSChris Cain fmt::format("validateOccMaster: OCC{} is master of {} OCCs", 103636f9cdedSChris Cain masterInstance, activeCount) 1037a7b74dc3SChris Cain .c_str()); 1038a7b74dc3SChris Cain } 1039a7b74dc3SChris Cain } 1040a7b74dc3SChris Cain 1041dfc7ec73SVishwanatha Subbanna } // namespace occ 1042dfc7ec73SVishwanatha Subbanna } // namespace open_power 1043