1dfc7ec73SVishwanatha Subbanna #include "config.h"
2dfc7ec73SVishwanatha Subbanna
394df8c90SGunnar Mills #include "occ_manager.hpp"
494df8c90SGunnar Mills
594df8c90SGunnar Mills #include "i2c_occ.hpp"
6bb895cb8SChicago Duan #include "occ_dbus.hpp"
74b82f3e3SChris Cain #include "occ_errors.hpp"
894df8c90SGunnar Mills #include "utils.hpp"
994df8c90SGunnar Mills
10b5ca1015SGeorge Liu #include <phosphor-logging/elog-errors.hpp>
1137abe9beSChris Cain #include <phosphor-logging/lg2.hpp>
12b5ca1015SGeorge Liu #include <xyz/openbmc_project/Common/error.hpp>
13b5ca1015SGeorge Liu
14d267cec2SMatt Spinler #include <chrono>
15bb895cb8SChicago Duan #include <cmath>
16bcef3b48SGeorge Liu #include <filesystem>
1736f9cdedSChris Cain #include <fstream>
18bb895cb8SChicago Duan #include <regex>
1994df8c90SGunnar Mills
20dfc7ec73SVishwanatha Subbanna namespace open_power
21dfc7ec73SVishwanatha Subbanna {
22dfc7ec73SVishwanatha Subbanna namespace occ
23dfc7ec73SVishwanatha Subbanna {
24dfc7ec73SVishwanatha Subbanna
258b8abeedSMatt Spinler constexpr uint32_t fruTypeNotAvailable = 0xFF;
26a26f1527SMatt Spinler constexpr auto fruTypeSuffix = "fru_type";
27a26f1527SMatt Spinler constexpr auto faultSuffix = "fault";
28a26f1527SMatt Spinler constexpr auto inputSuffix = "input";
29ace67d85SMatt Spinler constexpr auto maxSuffix = "max";
308b8abeedSMatt Spinler
311718fd8bSChris Cain const auto HOST_ON_FILE = "/run/openbmc/host@0-on";
321718fd8bSChris Cain
33a8857c50SChris Cain using namespace phosphor::logging;
34a7b74dc3SChris Cain using namespace std::literals::chrono_literals;
35a8857c50SChris Cain
36a26f1527SMatt Spinler template <typename T>
readFile(const std::string & path)37a26f1527SMatt Spinler T readFile(const std::string& path)
38a26f1527SMatt Spinler {
39a26f1527SMatt Spinler std::ifstream ifs;
40a26f1527SMatt Spinler ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit |
41a26f1527SMatt Spinler std::ifstream::eofbit);
42a26f1527SMatt Spinler T data;
43a26f1527SMatt Spinler
44a26f1527SMatt Spinler try
45a26f1527SMatt Spinler {
46a26f1527SMatt Spinler ifs.open(path);
47a26f1527SMatt Spinler ifs >> data;
48a26f1527SMatt Spinler ifs.close();
49a26f1527SMatt Spinler }
50a26f1527SMatt Spinler catch (const std::exception& e)
51a26f1527SMatt Spinler {
52a26f1527SMatt Spinler auto err = errno;
53a26f1527SMatt Spinler throw std::system_error(err, std::generic_category());
54a26f1527SMatt Spinler }
55a26f1527SMatt Spinler
56a26f1527SMatt Spinler return data;
57a26f1527SMatt Spinler }
58a26f1527SMatt Spinler
createPldmHandle()59720a3841SChris Cain void Manager::createPldmHandle()
60720a3841SChris Cain {
61720a3841SChris Cain #ifdef PLDM
62720a3841SChris Cain pldmHandle = std::make_unique<pldm::Interface>(
63720a3841SChris Cain std::bind(std::mem_fn(&Manager::updateOCCActive), this,
64720a3841SChris Cain std::placeholders::_1, std::placeholders::_2),
65720a3841SChris Cain std::bind(std::mem_fn(&Manager::sbeHRESETResult), this,
66720a3841SChris Cain std::placeholders::_1, std::placeholders::_2),
67720a3841SChris Cain std::bind(std::mem_fn(&Manager::updateOccSafeMode), this,
68720a3841SChris Cain std::placeholders::_1),
69*c488bac1SChris Cain std::bind(std::mem_fn(&Manager::hostPoweredOff), this), event);
70720a3841SChris Cain #endif
71720a3841SChris Cain }
72720a3841SChris Cain
73c33171bbSChris Cain // findAndCreateObjects():
74c33171bbSChris Cain // Takes care of getting the required objects created and
75c33171bbSChris Cain // finds the available devices/processors.
76c33171bbSChris Cain // (function is called everytime the discoverTimer expires)
77c33171bbSChris Cain // - create the PowerMode object to control OCC modes
78c33171bbSChris Cain // - create statusObjects for each OCC device found
79c33171bbSChris Cain // - waits for OCC Active sensors PDRs to become available
80c33171bbSChris Cain // - restart discoverTimer if all data is not available yet
findAndCreateObjects()81dfc7ec73SVishwanatha Subbanna void Manager::findAndCreateObjects()
82dfc7ec73SVishwanatha Subbanna {
83d267cec2SMatt Spinler #ifndef POWER10
84dfc7ec73SVishwanatha Subbanna for (auto id = 0; id < MAX_CPUS; ++id)
85dfc7ec73SVishwanatha Subbanna {
8630417a15SDeepak Kodihalli // Create one occ per cpu
8730417a15SDeepak Kodihalli auto occ = std::string(OCC_NAME) + std::to_string(id);
88dfc7ec73SVishwanatha Subbanna createObjects(occ);
89dfc7ec73SVishwanatha Subbanna }
90d267cec2SMatt Spinler #else
91613dc90dSChris Cain if (!pmode)
92613dc90dSChris Cain {
93613dc90dSChris Cain // Create the power mode object
94613dc90dSChris Cain pmode = std::make_unique<powermode::PowerMode>(
95613dc90dSChris Cain *this, powermode::PMODE_PATH, powermode::PIPS_PATH, event);
96613dc90dSChris Cain }
97613dc90dSChris Cain
981718fd8bSChris Cain if (!fs::exists(HOST_ON_FILE))
991718fd8bSChris Cain {
100bae4d07eSChris Cain static bool statusObjCreated = false;
101bae4d07eSChris Cain if (!statusObjCreated)
102bae4d07eSChris Cain {
103d267cec2SMatt Spinler // Create the OCCs based on on the /dev/occX devices
104d267cec2SMatt Spinler auto occs = findOCCsInDev();
105d267cec2SMatt Spinler
106d267cec2SMatt Spinler if (occs.empty() || (prevOCCSearch.size() != occs.size()))
107d267cec2SMatt Spinler {
108d267cec2SMatt Spinler // Something changed or no OCCs yet, try again in 10s.
109d267cec2SMatt Spinler // Note on the first pass prevOCCSearch will be empty,
110d267cec2SMatt Spinler // so there will be at least one delay to give things
111d267cec2SMatt Spinler // a chance to settle.
112d267cec2SMatt Spinler prevOCCSearch = occs;
113d267cec2SMatt Spinler
11437abe9beSChris Cain lg2::info(
11537abe9beSChris Cain "Manager::findAndCreateObjects(): Waiting for OCCs (currently {QTY})",
11637abe9beSChris Cain "QTY", occs.size());
117bae4d07eSChris Cain
118d267cec2SMatt Spinler discoverTimer->restartOnce(10s);
119d267cec2SMatt Spinler }
120d267cec2SMatt Spinler else
121d267cec2SMatt Spinler {
122bae4d07eSChris Cain // All OCCs appear to be available, create status objects
123d267cec2SMatt Spinler
124d267cec2SMatt Spinler // createObjects requires OCC0 first.
125d267cec2SMatt Spinler std::sort(occs.begin(), occs.end());
126d267cec2SMatt Spinler
12737abe9beSChris Cain lg2::info(
12837abe9beSChris Cain "Manager::findAndCreateObjects(): Creating {QTY} OCC Status Objects",
12937abe9beSChris Cain "QTY", occs.size());
130d267cec2SMatt Spinler for (auto id : occs)
131d267cec2SMatt Spinler {
132d267cec2SMatt Spinler createObjects(std::string(OCC_NAME) + std::to_string(id));
133d267cec2SMatt Spinler }
134bae4d07eSChris Cain statusObjCreated = true;
1356d8f37a2SChris Cain waitingForAllOccActiveSensors = true;
136c86d80faSChris Cain
137c86d80faSChris Cain // Find/update the processor path associated with each OCC
138c86d80faSChris Cain for (auto& obj : statusObjects)
139c86d80faSChris Cain {
140c86d80faSChris Cain obj->updateProcAssociation();
141c86d80faSChris Cain }
142bae4d07eSChris Cain }
143bae4d07eSChris Cain }
144bae4d07eSChris Cain
1456d8f37a2SChris Cain if (statusObjCreated && waitingForAllOccActiveSensors)
146bae4d07eSChris Cain {
147bae4d07eSChris Cain static bool tracedHostWait = false;
148bae4d07eSChris Cain if (utils::isHostRunning())
149bae4d07eSChris Cain {
150bae4d07eSChris Cain if (tracedHostWait)
151bae4d07eSChris Cain {
15237abe9beSChris Cain lg2::info(
153bae4d07eSChris Cain "Manager::findAndCreateObjects(): Host is running");
154bae4d07eSChris Cain tracedHostWait = false;
155bae4d07eSChris Cain }
156bae4d07eSChris Cain checkAllActiveSensors();
157bae4d07eSChris Cain }
158bae4d07eSChris Cain else
159bae4d07eSChris Cain {
160bae4d07eSChris Cain if (!tracedHostWait)
161bae4d07eSChris Cain {
16237abe9beSChris Cain lg2::info(
163bae4d07eSChris Cain "Manager::findAndCreateObjects(): Waiting for host to start");
164bae4d07eSChris Cain tracedHostWait = true;
165bae4d07eSChris Cain }
166bae4d07eSChris Cain discoverTimer->restartOnce(30s);
1677651c06bSChris Cain #ifdef PLDM
168c33171bbSChris Cain if (throttlePldmTraceTimer->isEnabled())
1697651c06bSChris Cain {
1707651c06bSChris Cain // Host is no longer running, disable throttle timer and
1717651c06bSChris Cain // make sure traces are not throttled
17237abe9beSChris Cain lg2::info("findAndCreateObjects(): disabling sensor timer");
173c33171bbSChris Cain throttlePldmTraceTimer->setEnabled(false);
1747651c06bSChris Cain pldmHandle->setTraceThrottle(false);
1757651c06bSChris Cain }
1767651c06bSChris Cain #endif
177bae4d07eSChris Cain }
178d267cec2SMatt Spinler }
1791718fd8bSChris Cain }
1801718fd8bSChris Cain else
1811718fd8bSChris Cain {
18237abe9beSChris Cain lg2::info(
18337abe9beSChris Cain "Manager::findAndCreateObjects(): Waiting for {FILE} to complete...",
18437abe9beSChris Cain "FILE", HOST_ON_FILE);
1851718fd8bSChris Cain discoverTimer->restartOnce(10s);
1861718fd8bSChris Cain }
187d267cec2SMatt Spinler #endif
188d267cec2SMatt Spinler }
189d267cec2SMatt Spinler
190bae4d07eSChris Cain #ifdef POWER10
191bae4d07eSChris Cain // Check if all occActive sensors are available
checkAllActiveSensors()192bae4d07eSChris Cain void Manager::checkAllActiveSensors()
193bae4d07eSChris Cain {
194bae4d07eSChris Cain static bool allActiveSensorAvailable = false;
195bae4d07eSChris Cain static bool tracedSensorWait = false;
196082a6ca7SChris Cain static bool waitingForHost = false;
197082a6ca7SChris Cain
198082a6ca7SChris Cain if (open_power::occ::utils::isHostRunning())
199082a6ca7SChris Cain {
200082a6ca7SChris Cain if (waitingForHost)
201082a6ca7SChris Cain {
202082a6ca7SChris Cain waitingForHost = false;
20337abe9beSChris Cain lg2::info("checkAllActiveSensors(): Host is now running");
204082a6ca7SChris Cain }
205bae4d07eSChris Cain
206bae4d07eSChris Cain // Start with the assumption that all are available
207bae4d07eSChris Cain allActiveSensorAvailable = true;
208bae4d07eSChris Cain for (auto& obj : statusObjects)
209bae4d07eSChris Cain {
210082a6ca7SChris Cain if ((!obj->occActive()) && (!obj->getPldmSensorReceived()))
211bae4d07eSChris Cain {
212bd551de3SChris Cain auto instance = obj->getOccInstanceID();
213bd551de3SChris Cain // Check if sensor was queued while waiting for discovery
214bd551de3SChris Cain auto match = queuedActiveState.find(instance);
215bd551de3SChris Cain if (match != queuedActiveState.end())
216bd551de3SChris Cain {
2177f89e4d1SChris Cain queuedActiveState.erase(match);
21837abe9beSChris Cain lg2::info(
21937abe9beSChris Cain "checkAllActiveSensors(): OCC{INST} is ACTIVE (queued)",
22037abe9beSChris Cain "INST", instance);
221bd551de3SChris Cain obj->occActive(true);
222bd551de3SChris Cain }
223bd551de3SChris Cain else
224bd551de3SChris Cain {
225bae4d07eSChris Cain allActiveSensorAvailable = false;
226bae4d07eSChris Cain if (!tracedSensorWait)
227bae4d07eSChris Cain {
22837abe9beSChris Cain lg2::info(
22937abe9beSChris Cain "checkAllActiveSensors(): Waiting on OCC{INST} Active sensor",
23037abe9beSChris Cain "INST", instance);
231bae4d07eSChris Cain tracedSensorWait = true;
232755af102SChris Cain #ifdef PLDM
233c33171bbSChris Cain // Make sure PLDM traces are not throttled
234755af102SChris Cain pldmHandle->setTraceThrottle(false);
235c33171bbSChris Cain // Start timer to throttle PLDM traces when timer
236755af102SChris Cain // expires
237c33171bbSChris Cain onPldmTimeoutCreatePel = false;
238c33171bbSChris Cain throttlePldmTraceTimer->restartOnce(5min);
239755af102SChris Cain #endif
240bae4d07eSChris Cain }
241fb0a5c3cSPatrick Williams #ifdef PLDM
242f0295f52SChris Cain // Ignore active sensor check if the OCCs are being reset
243f0295f52SChris Cain if (!resetInProgress)
244f0295f52SChris Cain {
245bae4d07eSChris Cain pldmHandle->checkActiveSensor(obj->getOccInstanceID());
246f0295f52SChris Cain }
247fb0a5c3cSPatrick Williams #endif
248bae4d07eSChris Cain break;
249bae4d07eSChris Cain }
250bae4d07eSChris Cain }
251bd551de3SChris Cain }
2527f89e4d1SChris Cain }
253082a6ca7SChris Cain else
254082a6ca7SChris Cain {
255082a6ca7SChris Cain if (!waitingForHost)
256082a6ca7SChris Cain {
257082a6ca7SChris Cain waitingForHost = true;
25837abe9beSChris Cain lg2::info("checkAllActiveSensors(): Waiting for host to start");
2597651c06bSChris Cain #ifdef PLDM
260c33171bbSChris Cain if (throttlePldmTraceTimer->isEnabled())
2617651c06bSChris Cain {
2627651c06bSChris Cain // Host is no longer running, disable throttle timer and
2637651c06bSChris Cain // make sure traces are not throttled
26437abe9beSChris Cain lg2::info("checkAllActiveSensors(): disabling sensor timer");
265c33171bbSChris Cain throttlePldmTraceTimer->setEnabled(false);
2667651c06bSChris Cain pldmHandle->setTraceThrottle(false);
2677651c06bSChris Cain }
2687651c06bSChris Cain #endif
269082a6ca7SChris Cain }
270082a6ca7SChris Cain }
271bae4d07eSChris Cain
272bae4d07eSChris Cain if (allActiveSensorAvailable)
273bae4d07eSChris Cain {
274bae4d07eSChris Cain // All sensors were found, disable the discovery timer
2757f89e4d1SChris Cain if (discoverTimer->isEnabled())
2767f89e4d1SChris Cain {
277f55f91acSChris Cain discoverTimer->setEnabled(false);
2787f89e4d1SChris Cain }
279755af102SChris Cain #ifdef PLDM
280c33171bbSChris Cain if (throttlePldmTraceTimer->isEnabled())
281755af102SChris Cain {
282755af102SChris Cain // Disable throttle timer and make sure traces are not throttled
283c33171bbSChris Cain throttlePldmTraceTimer->setEnabled(false);
284755af102SChris Cain pldmHandle->setTraceThrottle(false);
285755af102SChris Cain }
286755af102SChris Cain #endif
2877f89e4d1SChris Cain if (waitingForAllOccActiveSensors)
2887f89e4d1SChris Cain {
28937abe9beSChris Cain lg2::info(
290bd551de3SChris Cain "checkAllActiveSensors(): OCC Active sensors are available");
2917f89e4d1SChris Cain waitingForAllOccActiveSensors = false;
292f0295f52SChris Cain
293f0295f52SChris Cain if (resetRequired)
294f0295f52SChris Cain {
295f0295f52SChris Cain initiateOccRequest(resetInstance);
296f0295f52SChris Cain
297f0295f52SChris Cain if (!waitForAllOccsTimer->isEnabled())
298f0295f52SChris Cain {
29937abe9beSChris Cain lg2::warning(
300f0295f52SChris Cain "occsNotAllRunning: Restarting waitForAllOccTimer");
301f0295f52SChris Cain // restart occ wait timer to check status after reset
302f0295f52SChris Cain // completes
303f0295f52SChris Cain waitForAllOccsTimer->restartOnce(60s);
304f0295f52SChris Cain }
305f0295f52SChris Cain }
3067f89e4d1SChris Cain }
3077f89e4d1SChris Cain queuedActiveState.clear();
308bae4d07eSChris Cain tracedSensorWait = false;
309bae4d07eSChris Cain }
310bae4d07eSChris Cain else
311bae4d07eSChris Cain {
312bae4d07eSChris Cain // Not all sensors were available, so keep waiting
313bae4d07eSChris Cain if (!tracedSensorWait)
314bae4d07eSChris Cain {
31537abe9beSChris Cain lg2::info(
316bd551de3SChris Cain "checkAllActiveSensors(): Waiting for OCC Active sensors to become available");
317bae4d07eSChris Cain tracedSensorWait = true;
318bae4d07eSChris Cain }
319bd551de3SChris Cain discoverTimer->restartOnce(10s);
320bae4d07eSChris Cain }
321bae4d07eSChris Cain }
322bae4d07eSChris Cain #endif
323bae4d07eSChris Cain
findOCCsInDev()324d267cec2SMatt Spinler std::vector<int> Manager::findOCCsInDev()
325d267cec2SMatt Spinler {
326d267cec2SMatt Spinler std::vector<int> occs;
327d267cec2SMatt Spinler std::regex expr{R"(occ(\d+)$)"};
328d267cec2SMatt Spinler
329d267cec2SMatt Spinler for (auto& file : fs::directory_iterator("/dev"))
330d267cec2SMatt Spinler {
331d267cec2SMatt Spinler std::smatch match;
332d267cec2SMatt Spinler std::string path{file.path().string()};
333d267cec2SMatt Spinler if (std::regex_search(path, match, expr))
334d267cec2SMatt Spinler {
335d267cec2SMatt Spinler auto num = std::stoi(match[1].str());
336d267cec2SMatt Spinler
337d267cec2SMatt Spinler // /dev numbering starts at 1, ours starts at 0.
338d267cec2SMatt Spinler occs.push_back(num - 1);
339d267cec2SMatt Spinler }
340d267cec2SMatt Spinler }
341d267cec2SMatt Spinler
342d267cec2SMatt Spinler return occs;
343dfc7ec73SVishwanatha Subbanna }
344dfc7ec73SVishwanatha Subbanna
cpuCreated(sdbusplus::message_t & msg)345af40808fSPatrick Williams int Manager::cpuCreated(sdbusplus::message_t& msg)
346dfc7ec73SVishwanatha Subbanna {
347bcef3b48SGeorge Liu namespace fs = std::filesystem;
348dfc7ec73SVishwanatha Subbanna
349dfc7ec73SVishwanatha Subbanna sdbusplus::message::object_path o;
350dfc7ec73SVishwanatha Subbanna msg.read(o);
351dfc7ec73SVishwanatha Subbanna fs::path cpuPath(std::string(std::move(o)));
352dfc7ec73SVishwanatha Subbanna
353dfc7ec73SVishwanatha Subbanna auto name = cpuPath.filename().string();
354dfc7ec73SVishwanatha Subbanna auto index = name.find(CPU_NAME);
355dfc7ec73SVishwanatha Subbanna name.replace(index, std::strlen(CPU_NAME), OCC_NAME);
356dfc7ec73SVishwanatha Subbanna
357dfc7ec73SVishwanatha Subbanna createObjects(name);
358dfc7ec73SVishwanatha Subbanna
359dfc7ec73SVishwanatha Subbanna return 0;
360dfc7ec73SVishwanatha Subbanna }
361dfc7ec73SVishwanatha Subbanna
createObjects(const std::string & occ)362dfc7ec73SVishwanatha Subbanna void Manager::createObjects(const std::string& occ)
363dfc7ec73SVishwanatha Subbanna {
364dfc7ec73SVishwanatha Subbanna auto path = fs::path(OCC_CONTROL_ROOT) / occ;
365dfc7ec73SVishwanatha Subbanna
36694df8c90SGunnar Mills statusObjects.emplace_back(std::make_unique<Status>(
367f3b7514eSGeorge Liu event, path.c_str(), *this,
36836f9cdedSChris Cain #ifdef POWER10
36936f9cdedSChris Cain pmode,
37036f9cdedSChris Cain #endif
37194df8c90SGunnar Mills std::bind(std::mem_fn(&Manager::statusCallBack), this,
372373af757SSheldon Bailey std::placeholders::_1, std::placeholders::_2)
37300325238STom Joseph #ifdef PLDM
37400325238STom Joseph ,
375f0295f52SChris Cain // Callback will set flag indicating reset needs to be done
376f0295f52SChris Cain // instead of immediately issuing a reset via PLDM.
377f0295f52SChris Cain std::bind(std::mem_fn(&Manager::resetOccRequest), this,
37800325238STom Joseph std::placeholders::_1)
37900325238STom Joseph #endif
38000325238STom Joseph ));
381dfc7ec73SVishwanatha Subbanna
38240501a23SChris Cain // Create the power cap monitor object
38340501a23SChris Cain if (!pcap)
38440501a23SChris Cain {
38540501a23SChris Cain pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
38640501a23SChris Cain *statusObjects.back());
38740501a23SChris Cain }
38840501a23SChris Cain
38936f9cdedSChris Cain if (statusObjects.back()->isMasterOcc())
39036f9cdedSChris Cain {
39137abe9beSChris Cain lg2::info("Manager::createObjects(): OCC{INST} is the master", "INST",
39237abe9beSChris Cain statusObjects.back()->getOccInstanceID());
39336f9cdedSChris Cain _pollTimer->setEnabled(false);
39436f9cdedSChris Cain
39578e86012SChris Cain #ifdef POWER10
3966fa848a9SChris Cain // Set the master OCC on the PowerMode object
3976fa848a9SChris Cain pmode->setMasterOcc(path);
39878e86012SChris Cain #endif
399dfc7ec73SVishwanatha Subbanna }
400dfc7ec73SVishwanatha Subbanna
401d7542c83SPatrick Williams passThroughObjects.emplace_back(std::make_unique<PassThrough>(
402d7542c83SPatrick Williams path.c_str()
40336f9cdedSChris Cain #ifdef POWER10
40436f9cdedSChris Cain ,
40536f9cdedSChris Cain pmode
40636f9cdedSChris Cain #endif
40736f9cdedSChris Cain ));
40836f9cdedSChris Cain }
40936f9cdedSChris Cain
410f0295f52SChris Cain // If a reset is not already outstanding, set a flag to indicate that a reset is
411f0295f52SChris Cain // needed.
resetOccRequest(instanceID instance)412f0295f52SChris Cain void Manager::resetOccRequest(instanceID instance)
413f0295f52SChris Cain {
414f0295f52SChris Cain if (!resetRequired)
415f0295f52SChris Cain {
416f0295f52SChris Cain resetRequired = true;
417f0295f52SChris Cain resetInstance = instance;
41837abe9beSChris Cain lg2::error(
41937abe9beSChris Cain "resetOccRequest: PM Complex reset was requested due to OCC{INST}",
42037abe9beSChris Cain "INST", instance);
421f0295f52SChris Cain }
422f0295f52SChris Cain else if (instance != resetInstance)
423f0295f52SChris Cain {
42437abe9beSChris Cain lg2::warning(
42537abe9beSChris Cain "resetOccRequest: Ignoring PM Complex reset request for OCC{INST}, because reset already outstanding for OCC{RINST}",
42637abe9beSChris Cain "INST", instance, "RINST", resetInstance);
427f0295f52SChris Cain }
428f0295f52SChris Cain }
429f0295f52SChris Cain
430f0295f52SChris Cain // If a reset has not been started, initiate an OCC reset via PLDM
initiateOccRequest(instanceID instance)431f0295f52SChris Cain void Manager::initiateOccRequest(instanceID instance)
432f0295f52SChris Cain {
433f0295f52SChris Cain if (!resetInProgress)
434f0295f52SChris Cain {
435f0295f52SChris Cain resetInProgress = true;
436f0295f52SChris Cain resetInstance = instance;
43737abe9beSChris Cain lg2::error(
43837abe9beSChris Cain "initiateOccRequest: Initiating PM Complex reset due to OCC{INST}",
43937abe9beSChris Cain "INST", instance);
440f0295f52SChris Cain #ifdef PLDM
441f0295f52SChris Cain pldmHandle->resetOCC(instance);
442f0295f52SChris Cain #endif
443f0295f52SChris Cain resetRequired = false;
444f0295f52SChris Cain }
445f0295f52SChris Cain else
446f0295f52SChris Cain {
44737abe9beSChris Cain lg2::warning(
44837abe9beSChris Cain "initiateOccRequest: Ignoring PM Complex reset request for OCC{INST}, because reset already in process for OCC{RINST}",
44937abe9beSChris Cain "INST", instance, "RINST", resetInstance);
450f0295f52SChris Cain }
451f0295f52SChris Cain }
452f0295f52SChris Cain
statusCallBack(instanceID instance,bool status)453373af757SSheldon Bailey void Manager::statusCallBack(instanceID instance, bool status)
454dfc7ec73SVishwanatha Subbanna {
455a7b74dc3SChris Cain if (status == true)
456a7b74dc3SChris Cain {
457f0295f52SChris Cain if (resetInProgress)
458f0295f52SChris Cain {
45937abe9beSChris Cain lg2::info(
46092dfb271SChris Cain "statusCallBack: Ignoring OCC{INST} activate because a reset has been initiated due to OCC{RINST}",
46137abe9beSChris Cain "INST", instance, "RINST", resetInstance);
462f0295f52SChris Cain return;
463f0295f52SChris Cain }
464f0295f52SChris Cain
465a7b74dc3SChris Cain // OCC went active
466a7b74dc3SChris Cain ++activeCount;
467dae2d940SEddie James
468a7b74dc3SChris Cain #ifdef POWER10
469a7b74dc3SChris Cain if (activeCount == 1)
470a7b74dc3SChris Cain {
471a7b74dc3SChris Cain // First OCC went active (allow some time for all OCCs to go active)
472bd551de3SChris Cain waitForAllOccsTimer->restartOnce(60s);
473a7b74dc3SChris Cain }
474a7b74dc3SChris Cain #endif
475a7b74dc3SChris Cain
476dae2d940SEddie James if (activeCount == statusObjects.size())
477dae2d940SEddie James {
478a7b74dc3SChris Cain #ifdef POWER10
479a7b74dc3SChris Cain // All OCCs are now running
480a7b74dc3SChris Cain if (waitForAllOccsTimer->isEnabled())
481dae2d940SEddie James {
482a7b74dc3SChris Cain // stop occ wait timer
483a7b74dc3SChris Cain waitForAllOccsTimer->setEnabled(false);
484dae2d940SEddie James }
485a7b74dc3SChris Cain
486f0295f52SChris Cain // All OCCs have been found, check if we need a reset
487f0295f52SChris Cain if (resetRequired)
488f0295f52SChris Cain {
489f0295f52SChris Cain initiateOccRequest(resetInstance);
490f0295f52SChris Cain
491f0295f52SChris Cain if (!waitForAllOccsTimer->isEnabled())
492f0295f52SChris Cain {
49337abe9beSChris Cain lg2::warning(
494f0295f52SChris Cain "occsNotAllRunning: Restarting waitForAllOccTimer");
495f0295f52SChris Cain // restart occ wait timer
496f0295f52SChris Cain waitForAllOccsTimer->restartOnce(60s);
497f0295f52SChris Cain }
498f0295f52SChris Cain }
499f0295f52SChris Cain else
500f0295f52SChris Cain {
501a7b74dc3SChris Cain // Verify master OCC and start presence monitor
502a7b74dc3SChris Cain validateOccMaster();
503dae2d940SEddie James }
504f0295f52SChris Cain #else
505f0295f52SChris Cain // Verify master OCC and start presence monitor
506f0295f52SChris Cain validateOccMaster();
507f0295f52SChris Cain #endif
508f0295f52SChris Cain }
509a8857c50SChris Cain
510a7b74dc3SChris Cain // Start poll timer if not already started
511a7b74dc3SChris Cain if (!_pollTimer->isEnabled())
512a8857c50SChris Cain {
51337abe9beSChris Cain lg2::info("Manager: OCCs will be polled every {TIME} seconds",
51437abe9beSChris Cain "TIME", pollInterval);
515a8857c50SChris Cain
516a8857c50SChris Cain // Send poll and start OCC poll timer
517a8857c50SChris Cain pollerTimerExpired();
518a8857c50SChris Cain }
519a7b74dc3SChris Cain }
520a7b74dc3SChris Cain else
521a8857c50SChris Cain {
522a7b74dc3SChris Cain // OCC went away
523082a6ca7SChris Cain if (activeCount > 0)
524082a6ca7SChris Cain {
525a7b74dc3SChris Cain --activeCount;
526082a6ca7SChris Cain }
527082a6ca7SChris Cain else
528082a6ca7SChris Cain {
529b89d619cSSheldon Bailey lg2::info("OCC{INST} disabled, and no other OCCs are active",
53037abe9beSChris Cain "INST", instance);
531082a6ca7SChris Cain }
532a7b74dc3SChris Cain
533a7b74dc3SChris Cain if (activeCount == 0)
534a7b74dc3SChris Cain {
535a7b74dc3SChris Cain // No OCCs are running
536a7b74dc3SChris Cain
537f0295f52SChris Cain if (resetInProgress)
538f0295f52SChris Cain {
539f0295f52SChris Cain // All OCC active sensors are clear (reset should be in
540f0295f52SChris Cain // progress)
54137abe9beSChris Cain lg2::info(
54237abe9beSChris Cain "statusCallBack: Clearing resetInProgress (activeCount={COUNT}, OCC{INST}, status={STATUS})",
54337abe9beSChris Cain "COUNT", activeCount, "INST", instance, "STATUS", status);
544f0295f52SChris Cain resetInProgress = false;
545f0295f52SChris Cain resetInstance = 255;
546f0295f52SChris Cain }
547f0295f52SChris Cain
548a8857c50SChris Cain // Stop OCC poll timer
549a7b74dc3SChris Cain if (_pollTimer->isEnabled())
550a7b74dc3SChris Cain {
55137abe9beSChris Cain lg2::info(
552b5ca1015SGeorge Liu "Manager::statusCallBack(): OCCs are not running, stopping poll timer");
553a8857c50SChris Cain _pollTimer->setEnabled(false);
554a7b74dc3SChris Cain }
555a7b74dc3SChris Cain
556a7b74dc3SChris Cain #ifdef POWER10
557a7b74dc3SChris Cain // stop wait timer
558a7b74dc3SChris Cain if (waitForAllOccsTimer->isEnabled())
559a7b74dc3SChris Cain {
560a7b74dc3SChris Cain waitForAllOccsTimer->setEnabled(false);
561a7b74dc3SChris Cain }
562a7b74dc3SChris Cain #endif
563373af757SSheldon Bailey }
564f0295f52SChris Cain else if (resetInProgress)
565f0295f52SChris Cain {
56637abe9beSChris Cain lg2::info(
56737abe9beSChris Cain "statusCallBack: Skipping clear of resetInProgress (activeCount={COUNT}, OCC{INST}, status={STATUS})",
56837abe9beSChris Cain "COUNT", activeCount, "INST", instance, "STATUS", status);
569f0295f52SChris Cain }
57053f68148SMatt Spinler #ifdef READ_OCC_SENSORS
571a7b74dc3SChris Cain // Clear OCC sensors
572c8dd4599SSheldon Bailey setSensorValueToNaN(instance);
57353f68148SMatt Spinler #endif
574a8857c50SChris Cain }
575bae4d07eSChris Cain
576bae4d07eSChris Cain #ifdef POWER10
577bae4d07eSChris Cain if (waitingForAllOccActiveSensors)
578bae4d07eSChris Cain {
5796d8f37a2SChris Cain if (utils::isHostRunning())
5806d8f37a2SChris Cain {
581bae4d07eSChris Cain checkAllActiveSensors();
582bae4d07eSChris Cain }
5836d8f37a2SChris Cain }
584bae4d07eSChris Cain #endif
585dfc7ec73SVishwanatha Subbanna }
586dfc7ec73SVishwanatha Subbanna
587dfc7ec73SVishwanatha Subbanna #ifdef I2C_OCC
initStatusObjects()588dfc7ec73SVishwanatha Subbanna void Manager::initStatusObjects()
589dfc7ec73SVishwanatha Subbanna {
590dfc7ec73SVishwanatha Subbanna // Make sure we have a valid path string
591dfc7ec73SVishwanatha Subbanna static_assert(sizeof(DEV_PATH) != 0);
592dfc7ec73SVishwanatha Subbanna
593dfc7ec73SVishwanatha Subbanna auto deviceNames = i2c_occ::getOccHwmonDevices(DEV_PATH);
594dfc7ec73SVishwanatha Subbanna for (auto& name : deviceNames)
595dfc7ec73SVishwanatha Subbanna {
596dfc7ec73SVishwanatha Subbanna i2c_occ::i2cToDbus(name);
597b5259a1eSLei YU name = std::string(OCC_NAME) + '_' + name;
598dfc7ec73SVishwanatha Subbanna auto path = fs::path(OCC_CONTROL_ROOT) / name;
599dfc7ec73SVishwanatha Subbanna statusObjects.emplace_back(
600f3b7514eSGeorge Liu std::make_unique<Status>(event, path.c_str(), *this));
601dfc7ec73SVishwanatha Subbanna }
60240501a23SChris Cain // The first device is master occ
60340501a23SChris Cain pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
60440501a23SChris Cain *statusObjects.front());
60578e86012SChris Cain #ifdef POWER10
6065d66a0aaSChris Cain pmode = std::make_unique<powermode::PowerMode>(*this, powermode::PMODE_PATH,
6075d66a0aaSChris Cain powermode::PIPS_PATH);
6086fa848a9SChris Cain // Set the master OCC on the PowerMode object
6096fa848a9SChris Cain pmode->setMasterOcc(path);
61078e86012SChris Cain #endif
611dfc7ec73SVishwanatha Subbanna }
612dfc7ec73SVishwanatha Subbanna #endif
613dfc7ec73SVishwanatha Subbanna
614815f9f55STom Joseph #ifdef PLDM
sbeTimeout(unsigned int instance)615cbad219eSEddie James void Manager::sbeTimeout(unsigned int instance)
616cbad219eSEddie James {
6172a751d70SEddie James auto obj = std::find_if(statusObjects.begin(), statusObjects.end(),
6182a751d70SEddie James [instance](const auto& obj) {
6192a751d70SEddie James return instance == obj->getOccInstanceID();
6202a751d70SEddie James });
6212a751d70SEddie James
622cb018dafSEddie James if (obj != statusObjects.end() && (*obj)->occActive())
6232a751d70SEddie James {
62437abe9beSChris Cain lg2::info("SBE timeout, requesting HRESET (OCC{INST})", "INST",
62537abe9beSChris Cain instance);
626cbad219eSEddie James
627720a3841SChris Cain #ifdef PHAL_SUPPORT
628cbad219eSEddie James setSBEState(instance, SBE_STATE_NOT_USABLE);
629720a3841SChris Cain #endif
630cbad219eSEddie James
63192dfb271SChris Cain // Stop communication with this OCC
63292dfb271SChris Cain (*obj)->occActive(false);
63392dfb271SChris Cain
634cbad219eSEddie James pldmHandle->sendHRESET(instance);
635cbad219eSEddie James }
6362a751d70SEddie James }
637cbad219eSEddie James
updateOCCActive(instanceID instance,bool status)638815f9f55STom Joseph bool Manager::updateOCCActive(instanceID instance, bool status)
639815f9f55STom Joseph {
6407e374fb4SChris Cain auto obj = std::find_if(statusObjects.begin(), statusObjects.end(),
6417e374fb4SChris Cain [instance](const auto& obj) {
6427e374fb4SChris Cain return instance == obj->getOccInstanceID();
6437e374fb4SChris Cain });
6447e374fb4SChris Cain
645082a6ca7SChris Cain const bool hostRunning = open_power::occ::utils::isHostRunning();
6467e374fb4SChris Cain if (obj != statusObjects.end())
6477e374fb4SChris Cain {
648082a6ca7SChris Cain if (!hostRunning && (status == true))
6497e374fb4SChris Cain {
65037abe9beSChris Cain lg2::warning(
65137abe9beSChris Cain "updateOCCActive: Host is not running yet (OCC{INST} active={STAT}), clearing sensor received",
65237abe9beSChris Cain "INST", instance, "STAT", status);
653082a6ca7SChris Cain (*obj)->setPldmSensorReceived(false);
654082a6ca7SChris Cain if (!waitingForAllOccActiveSensors)
655082a6ca7SChris Cain {
65637abe9beSChris Cain lg2::info(
657082a6ca7SChris Cain "updateOCCActive: Waiting for Host and all OCC Active Sensors");
658082a6ca7SChris Cain waitingForAllOccActiveSensors = true;
659082a6ca7SChris Cain }
660755af102SChris Cain #ifdef POWER10
661082a6ca7SChris Cain discoverTimer->restartOnce(30s);
662755af102SChris Cain #endif
663082a6ca7SChris Cain return false;
664082a6ca7SChris Cain }
665082a6ca7SChris Cain else
666082a6ca7SChris Cain {
667082a6ca7SChris Cain (*obj)->setPldmSensorReceived(true);
668082a6ca7SChris Cain return (*obj)->occActive(status);
669082a6ca7SChris Cain }
670082a6ca7SChris Cain }
671082a6ca7SChris Cain else
672082a6ca7SChris Cain {
673082a6ca7SChris Cain if (hostRunning)
674082a6ca7SChris Cain {
67537abe9beSChris Cain lg2::warning(
67637abe9beSChris Cain "updateOCCActive: No status object to update for OCC{INST} (active={STAT})",
67737abe9beSChris Cain "INST", instance, "STAT", status);
678082a6ca7SChris Cain }
679082a6ca7SChris Cain else
680082a6ca7SChris Cain {
681082a6ca7SChris Cain if (status == true)
682082a6ca7SChris Cain {
68337abe9beSChris Cain lg2::warning(
68437abe9beSChris Cain "updateOCCActive: No status objects and Host is not running yet (OCC{INST} active={STAT})",
68537abe9beSChris Cain "INST", instance, "STAT", status);
686082a6ca7SChris Cain }
687082a6ca7SChris Cain }
688bd551de3SChris Cain if (status == true)
689bd551de3SChris Cain {
690bd551de3SChris Cain // OCC went active
691bd551de3SChris Cain queuedActiveState.insert(instance);
692bd551de3SChris Cain }
693bd551de3SChris Cain else
694bd551de3SChris Cain {
695bd551de3SChris Cain auto match = queuedActiveState.find(instance);
696bd551de3SChris Cain if (match != queuedActiveState.end())
697bd551de3SChris Cain {
698bd551de3SChris Cain // OCC was disabled
699bd551de3SChris Cain queuedActiveState.erase(match);
700bd551de3SChris Cain }
701bd551de3SChris Cain }
7027e374fb4SChris Cain return false;
7037e374fb4SChris Cain }
704815f9f55STom Joseph }
705cbad219eSEddie James
70631a2f13aSSheldon Bailey // Called upon pldm event To set powermode Safe Mode State for system.
updateOccSafeMode(bool safeMode)70731a2f13aSSheldon Bailey void Manager::updateOccSafeMode(bool safeMode)
70831a2f13aSSheldon Bailey {
70931a2f13aSSheldon Bailey #ifdef POWER10
71031a2f13aSSheldon Bailey pmode->updateDbusSafeMode(safeMode);
71131a2f13aSSheldon Bailey #endif
712c86d80faSChris Cain // Update the processor throttle status on dbus
713c86d80faSChris Cain for (auto& obj : statusObjects)
714c86d80faSChris Cain {
715c86d80faSChris Cain obj->updateThrottle(safeMode, THROTTLED_SAFE);
716c86d80faSChris Cain }
71731a2f13aSSheldon Bailey }
71831a2f13aSSheldon Bailey
sbeHRESETResult(instanceID instance,bool success)719cbad219eSEddie James void Manager::sbeHRESETResult(instanceID instance, bool success)
720cbad219eSEddie James {
721cbad219eSEddie James if (success)
722cbad219eSEddie James {
72337abe9beSChris Cain lg2::info("HRESET succeeded (OCC{INST})", "INST", instance);
724cbad219eSEddie James
725720a3841SChris Cain #ifdef PHAL_SUPPORT
726cbad219eSEddie James setSBEState(instance, SBE_STATE_BOOTED);
727720a3841SChris Cain #endif
728cbad219eSEddie James
72992dfb271SChris Cain // Re-enable communication with this OCC
73092dfb271SChris Cain auto obj = std::find_if(statusObjects.begin(), statusObjects.end(),
73192dfb271SChris Cain [instance](const auto& obj) {
73292dfb271SChris Cain return instance == obj->getOccInstanceID();
73392dfb271SChris Cain });
73492dfb271SChris Cain if (obj != statusObjects.end() && (!(*obj)->occActive()))
73592dfb271SChris Cain {
73692dfb271SChris Cain (*obj)->occActive(true);
73792dfb271SChris Cain }
73892dfb271SChris Cain
739cbad219eSEddie James return;
740cbad219eSEddie James }
741cbad219eSEddie James
742720a3841SChris Cain #ifdef PHAL_SUPPORT
743cbad219eSEddie James setSBEState(instance, SBE_STATE_FAILED);
744cbad219eSEddie James
745cbad219eSEddie James if (sbeCanDump(instance))
746cbad219eSEddie James {
74737abe9beSChris Cain lg2::info("HRESET failed (OCC{INST}), triggering SBE dump", "INST",
74837abe9beSChris Cain instance);
749cbad219eSEddie James
750cbad219eSEddie James auto& bus = utils::getBus();
751cbad219eSEddie James uint32_t src6 = instance << 16;
752cbad219eSEddie James uint32_t logId =
753cbad219eSEddie James FFDC::createPEL("org.open_power.Processor.Error.SbeChipOpTimeout",
754cbad219eSEddie James src6, "SBE command timeout");
755cbad219eSEddie James
756cbad219eSEddie James try
757cbad219eSEddie James {
758f3a4a69fSGeorge Liu constexpr auto interface = "xyz.openbmc_project.Dump.Create";
759f3a4a69fSGeorge Liu constexpr auto function = "CreateDump";
760f3a4a69fSGeorge Liu
761d7542c83SPatrick Williams std::string service =
762d7542c83SPatrick Williams utils::getService(OP_DUMP_OBJ_PATH, interface);
7631173b2b1SDhruvaraj Subhashchandran auto method = bus.new_method_call(service.c_str(), OP_DUMP_OBJ_PATH,
7641173b2b1SDhruvaraj Subhashchandran interface, function);
765cbad219eSEddie James
766cbad219eSEddie James std::map<std::string, std::variant<std::string, uint64_t>>
767cbad219eSEddie James createParams{
768cbad219eSEddie James {"com.ibm.Dump.Create.CreateParameters.ErrorLogId",
769cbad219eSEddie James uint64_t(logId)},
770cbad219eSEddie James {"com.ibm.Dump.Create.CreateParameters.DumpType",
771cbad219eSEddie James "com.ibm.Dump.Create.DumpType.SBE"},
772cbad219eSEddie James {"com.ibm.Dump.Create.CreateParameters.FailingUnitId",
773cbad219eSEddie James uint64_t(instance)},
774cbad219eSEddie James };
775cbad219eSEddie James
776cbad219eSEddie James method.append(createParams);
777cbad219eSEddie James
778cbad219eSEddie James auto response = bus.call(method);
779cbad219eSEddie James }
780af40808fSPatrick Williams catch (const sdbusplus::exception_t& e)
781cbad219eSEddie James {
782cbad219eSEddie James constexpr auto ERROR_DUMP_DISABLED =
783cbad219eSEddie James "xyz.openbmc_project.Dump.Create.Error.Disabled";
784cbad219eSEddie James if (e.name() == ERROR_DUMP_DISABLED)
785cbad219eSEddie James {
78637abe9beSChris Cain lg2::info("Dump is disabled, skipping");
787cbad219eSEddie James }
788cbad219eSEddie James else
789cbad219eSEddie James {
79037abe9beSChris Cain lg2::error("Dump failed");
791cbad219eSEddie James }
792cbad219eSEddie James }
793cbad219eSEddie James }
794720a3841SChris Cain #endif
795f0295f52SChris Cain
796f0295f52SChris Cain // SBE Reset failed, try PM Complex reset
79737abe9beSChris Cain lg2::error("sbeHRESETResult: Forcing PM Complex reset");
798f0295f52SChris Cain resetOccRequest(instance);
799cbad219eSEddie James }
800cbad219eSEddie James
801720a3841SChris Cain #ifdef PHAL_SUPPORT
sbeCanDump(unsigned int instance)802cbad219eSEddie James bool Manager::sbeCanDump(unsigned int instance)
803cbad219eSEddie James {
804cbad219eSEddie James struct pdbg_target* proc = getPdbgTarget(instance);
805cbad219eSEddie James
806cbad219eSEddie James if (!proc)
807cbad219eSEddie James {
808cbad219eSEddie James // allow the dump in the error case
809cbad219eSEddie James return true;
810cbad219eSEddie James }
811cbad219eSEddie James
812cbad219eSEddie James try
813cbad219eSEddie James {
814cbad219eSEddie James if (!openpower::phal::sbe::isDumpAllowed(proc))
815cbad219eSEddie James {
816cbad219eSEddie James return false;
817cbad219eSEddie James }
818cbad219eSEddie James
819cbad219eSEddie James if (openpower::phal::pdbg::isSbeVitalAttnActive(proc))
820cbad219eSEddie James {
821cbad219eSEddie James return false;
822cbad219eSEddie James }
823cbad219eSEddie James }
824cbad219eSEddie James catch (openpower::phal::exception::SbeError& e)
825cbad219eSEddie James {
82637abe9beSChris Cain lg2::info("Failed to query SBE state");
827cbad219eSEddie James }
828cbad219eSEddie James
829cbad219eSEddie James // allow the dump in the error case
830cbad219eSEddie James return true;
831cbad219eSEddie James }
832cbad219eSEddie James
setSBEState(unsigned int instance,enum sbe_state state)833cbad219eSEddie James void Manager::setSBEState(unsigned int instance, enum sbe_state state)
834cbad219eSEddie James {
835cbad219eSEddie James struct pdbg_target* proc = getPdbgTarget(instance);
836cbad219eSEddie James
837cbad219eSEddie James if (!proc)
838cbad219eSEddie James {
839cbad219eSEddie James return;
840cbad219eSEddie James }
841cbad219eSEddie James
842cbad219eSEddie James try
843cbad219eSEddie James {
844cbad219eSEddie James openpower::phal::sbe::setState(proc, state);
845cbad219eSEddie James }
846cbad219eSEddie James catch (const openpower::phal::exception::SbeError& e)
847cbad219eSEddie James {
84837abe9beSChris Cain lg2::error("Failed to set SBE state: {ERROR}", "ERROR", e.what());
849cbad219eSEddie James }
850cbad219eSEddie James }
851cbad219eSEddie James
getPdbgTarget(unsigned int instance)852cbad219eSEddie James struct pdbg_target* Manager::getPdbgTarget(unsigned int instance)
853cbad219eSEddie James {
854cbad219eSEddie James if (!pdbgInitialized)
855cbad219eSEddie James {
856cbad219eSEddie James try
857cbad219eSEddie James {
858cbad219eSEddie James openpower::phal::pdbg::init();
859cbad219eSEddie James pdbgInitialized = true;
860cbad219eSEddie James }
861cbad219eSEddie James catch (const openpower::phal::exception::PdbgError& e)
862cbad219eSEddie James {
86337abe9beSChris Cain lg2::error("pdbg initialization failed");
864cbad219eSEddie James return nullptr;
865cbad219eSEddie James }
866cbad219eSEddie James }
867cbad219eSEddie James
868cbad219eSEddie James struct pdbg_target* proc = nullptr;
869cbad219eSEddie James pdbg_for_each_class_target("proc", proc)
870cbad219eSEddie James {
871cbad219eSEddie James if (pdbg_target_index(proc) == instance)
872cbad219eSEddie James {
873cbad219eSEddie James return proc;
874cbad219eSEddie James }
875cbad219eSEddie James }
876cbad219eSEddie James
87737abe9beSChris Cain lg2::error("Failed to get pdbg target");
878cbad219eSEddie James return nullptr;
879cbad219eSEddie James }
880815f9f55STom Joseph #endif
881720a3841SChris Cain #endif
882815f9f55STom Joseph
pollerTimerExpired()883a8857c50SChris Cain void Manager::pollerTimerExpired()
884a8857c50SChris Cain {
885a8857c50SChris Cain if (!_pollTimer)
886a8857c50SChris Cain {
88737abe9beSChris Cain lg2::error("pollerTimerExpired() ERROR: Timer not defined");
888a8857c50SChris Cain return;
889a8857c50SChris Cain }
890a8857c50SChris Cain
891f0295f52SChris Cain #ifdef POWER10
892f0295f52SChris Cain if (resetRequired)
893f0295f52SChris Cain {
89437abe9beSChris Cain lg2::error("pollerTimerExpired() - Initiating PM Complex reset");
895f0295f52SChris Cain initiateOccRequest(resetInstance);
896f0295f52SChris Cain
897f0295f52SChris Cain if (!waitForAllOccsTimer->isEnabled())
898f0295f52SChris Cain {
89937abe9beSChris Cain lg2::warning("pollerTimerExpired: Restarting waitForAllOccTimer");
900f0295f52SChris Cain // restart occ wait timer
901f0295f52SChris Cain waitForAllOccsTimer->restartOnce(60s);
902f0295f52SChris Cain }
903f0295f52SChris Cain return;
904f0295f52SChris Cain }
905f0295f52SChris Cain #endif
906f0295f52SChris Cain
907a8857c50SChris Cain for (auto& obj : statusObjects)
908a8857c50SChris Cain {
909a7b74dc3SChris Cain if (!obj->occActive())
910a7b74dc3SChris Cain {
911a7b74dc3SChris Cain // OCC is not running yet
912a7b74dc3SChris Cain #ifdef READ_OCC_SENSORS
9135d66a0aaSChris Cain auto id = obj->getOccInstanceID();
914c8dd4599SSheldon Bailey setSensorValueToNaN(id);
915a7b74dc3SChris Cain #endif
916a7b74dc3SChris Cain continue;
917a7b74dc3SChris Cain }
918a7b74dc3SChris Cain
919a8857c50SChris Cain // Read sysfs to force kernel to poll OCC
920a8857c50SChris Cain obj->readOccState();
921bb895cb8SChicago Duan
922bb895cb8SChicago Duan #ifdef READ_OCC_SENSORS
923bb895cb8SChicago Duan // Read occ sensor values
9245d66a0aaSChris Cain getSensorValues(obj);
925bb895cb8SChicago Duan #endif
926a8857c50SChris Cain }
927a8857c50SChris Cain
928a7b74dc3SChris Cain if (activeCount > 0)
929a7b74dc3SChris Cain {
930a8857c50SChris Cain // Restart OCC poll timer
931a8857c50SChris Cain _pollTimer->restartOnce(std::chrono::seconds(pollInterval));
932a8857c50SChris Cain }
933a7b74dc3SChris Cain else
934a7b74dc3SChris Cain {
935a7b74dc3SChris Cain // No OCCs running, so poll timer will not be restarted
93637abe9beSChris Cain lg2::info(
93737abe9beSChris Cain "Manager::pollerTimerExpired: poll timer will not be restarted");
938a7b74dc3SChris Cain }
939a7b74dc3SChris Cain }
940a8857c50SChris Cain
941bb895cb8SChicago Duan #ifdef READ_OCC_SENSORS
readTempSensors(const fs::path & path,uint32_t occInstance)942ae157b68SChris Cain void Manager::readTempSensors(const fs::path& path, uint32_t occInstance)
943bb895cb8SChicago Duan {
944818cc8d7SMatt Spinler // There may be more than one sensor with the same FRU type
945818cc8d7SMatt Spinler // and label so make two passes: the first to read the temps
946818cc8d7SMatt Spinler // from sysfs, and the second to put them on D-Bus after
947818cc8d7SMatt Spinler // resolving any conflicts.
948818cc8d7SMatt Spinler std::map<std::string, double> sensorData;
949818cc8d7SMatt Spinler
950bb895cb8SChicago Duan std::regex expr{"temp\\d+_label$"}; // Example: temp5_label
951bb895cb8SChicago Duan for (auto& file : fs::directory_iterator(path))
952bb895cb8SChicago Duan {
953bb895cb8SChicago Duan if (!std::regex_search(file.path().string(), expr))
954bb895cb8SChicago Duan {
955bb895cb8SChicago Duan continue;
956bb895cb8SChicago Duan }
957bb895cb8SChicago Duan
958a26f1527SMatt Spinler uint32_t labelValue{0};
959a26f1527SMatt Spinler
960a26f1527SMatt Spinler try
961a26f1527SMatt Spinler {
962a26f1527SMatt Spinler labelValue = readFile<uint32_t>(file.path());
963a26f1527SMatt Spinler }
964a26f1527SMatt Spinler catch (const std::system_error& e)
965a26f1527SMatt Spinler {
96637abe9beSChris Cain lg2::debug(
96737abe9beSChris Cain "readTempSensors: Failed reading {PATH}, errno = {ERROR}",
96837abe9beSChris Cain "PATH", file.path().string(), "ERROR", e.code().value());
969bb895cb8SChicago Duan continue;
970bb895cb8SChicago Duan }
971bb895cb8SChicago Duan
972bb895cb8SChicago Duan const std::string& tempLabel = "label";
973bb895cb8SChicago Duan const std::string filePathString = file.path().string().substr(
974bb895cb8SChicago Duan 0, file.path().string().length() - tempLabel.length());
975a26f1527SMatt Spinler
976a26f1527SMatt Spinler uint32_t fruTypeValue{0};
977a26f1527SMatt Spinler try
978bb895cb8SChicago Duan {
979a26f1527SMatt Spinler fruTypeValue = readFile<uint32_t>(filePathString + fruTypeSuffix);
980a26f1527SMatt Spinler }
981a26f1527SMatt Spinler catch (const std::system_error& e)
982a26f1527SMatt Spinler {
98337abe9beSChris Cain lg2::debug(
98437abe9beSChris Cain "readTempSensors: Failed reading {PATH}, errno = {ERROR}",
98537abe9beSChris Cain "PATH", filePathString + fruTypeSuffix, "ERROR",
98637abe9beSChris Cain e.code().value());
987bb895cb8SChicago Duan continue;
988bb895cb8SChicago Duan }
989bb895cb8SChicago Duan
990d7542c83SPatrick Williams std::string sensorPath =
991d7542c83SPatrick Williams OCC_SENSORS_ROOT + std::string("/temperature/");
992bb895cb8SChicago Duan
993ace67d85SMatt Spinler std::string dvfsTempPath;
994ace67d85SMatt Spinler
995bb895cb8SChicago Duan if (fruTypeValue == VRMVdd)
996bb895cb8SChicago Duan {
997d7542c83SPatrick Williams sensorPath.append(
998d7542c83SPatrick Williams "vrm_vdd" + std::to_string(occInstance) + "_temp");
999bb895cb8SChicago Duan }
1000ace67d85SMatt Spinler else if (fruTypeValue == processorIoRing)
1001ace67d85SMatt Spinler {
1002d7542c83SPatrick Williams sensorPath.append(
1003d7542c83SPatrick Williams "proc" + std::to_string(occInstance) + "_ioring_temp");
1004ace67d85SMatt Spinler dvfsTempPath = std::string{OCC_SENSORS_ROOT} + "/temperature/proc" +
1005ae157b68SChris Cain std::to_string(occInstance) + "_ioring_dvfs_temp";
1006ace67d85SMatt Spinler }
1007bb895cb8SChicago Duan else
1008bb895cb8SChicago Duan {
100914d1402dSMatt Spinler uint16_t type = (labelValue & 0xFF000000) >> 24;
101014d1402dSMatt Spinler uint16_t instanceID = labelValue & 0x0000FFFF;
1011bb895cb8SChicago Duan
1012bb895cb8SChicago Duan if (type == OCC_DIMM_TEMP_SENSOR_TYPE)
1013bb895cb8SChicago Duan {
10148b8abeedSMatt Spinler if (fruTypeValue == fruTypeNotAvailable)
10158b8abeedSMatt Spinler {
10168b8abeedSMatt Spinler // Not all DIMM related temps are available to read
10178b8abeedSMatt Spinler // (no _input file in this case)
10188b8abeedSMatt Spinler continue;
10198b8abeedSMatt Spinler }
1020bb895cb8SChicago Duan auto iter = dimmTempSensorName.find(fruTypeValue);
1021bb895cb8SChicago Duan if (iter == dimmTempSensorName.end())
1022bb895cb8SChicago Duan {
102337abe9beSChris Cain lg2::error(
102437abe9beSChris Cain "readTempSensors: Fru type error! fruTypeValue = {FRU}) ",
102537abe9beSChris Cain "FRU", fruTypeValue);
1026bb895cb8SChicago Duan continue;
1027bb895cb8SChicago Duan }
1028bb895cb8SChicago Duan
1029d7542c83SPatrick Williams sensorPath.append(
1030d7542c83SPatrick Williams "dimm" + std::to_string(instanceID) + iter->second);
1031ad8f4524SMatt Spinler
1032ad8f4524SMatt Spinler dvfsTempPath = std::string{OCC_SENSORS_ROOT} + "/temperature/" +
1033ad8f4524SMatt Spinler dimmDVFSSensorName.at(fruTypeValue);
1034bb895cb8SChicago Duan }
1035bb895cb8SChicago Duan else if (type == OCC_CPU_TEMP_SENSOR_TYPE)
1036bb895cb8SChicago Duan {
1037ace67d85SMatt Spinler if (fruTypeValue == processorCore)
1038bb895cb8SChicago Duan {
1039ff7afd98SMatt Spinler // The OCC reports small core temps, of which there are
1040ff7afd98SMatt Spinler // two per big core. All current P10 systems are in big
1041ff7afd98SMatt Spinler // core mode, so use a big core name.
1042ff7afd98SMatt Spinler uint16_t coreNum = instanceID / 2;
1043ff7afd98SMatt Spinler uint16_t tempNum = instanceID % 2;
1044ae157b68SChris Cain sensorPath.append("proc" + std::to_string(occInstance) +
1045ae157b68SChris Cain "_core" + std::to_string(coreNum) + "_" +
1046ff7afd98SMatt Spinler std::to_string(tempNum) + "_temp");
1047ace67d85SMatt Spinler
1048ae157b68SChris Cain dvfsTempPath =
1049ae157b68SChris Cain std::string{OCC_SENSORS_ROOT} + "/temperature/proc" +
1050ae157b68SChris Cain std::to_string(occInstance) + "_core_dvfs_temp";
1051bb895cb8SChicago Duan }
1052bb895cb8SChicago Duan else
1053bb895cb8SChicago Duan {
1054bb895cb8SChicago Duan continue;
1055bb895cb8SChicago Duan }
1056bb895cb8SChicago Duan }
1057ace67d85SMatt Spinler else
1058ace67d85SMatt Spinler {
1059ace67d85SMatt Spinler continue;
1060ace67d85SMatt Spinler }
1061ace67d85SMatt Spinler }
1062ace67d85SMatt Spinler
1063ace67d85SMatt Spinler // The dvfs temp file only needs to be read once per chip per type.
1064ace67d85SMatt Spinler if (!dvfsTempPath.empty() &&
1065ace67d85SMatt Spinler !dbus::OccDBusSensors::getOccDBus().hasDvfsTemp(dvfsTempPath))
1066ace67d85SMatt Spinler {
1067ace67d85SMatt Spinler try
1068ace67d85SMatt Spinler {
1069ace67d85SMatt Spinler auto dvfsValue = readFile<double>(filePathString + maxSuffix);
1070ace67d85SMatt Spinler
1071ace67d85SMatt Spinler dbus::OccDBusSensors::getOccDBus().setDvfsTemp(
1072ace67d85SMatt Spinler dvfsTempPath, dvfsValue * std::pow(10, -3));
1073ace67d85SMatt Spinler }
1074ace67d85SMatt Spinler catch (const std::system_error& e)
1075ace67d85SMatt Spinler {
107637abe9beSChris Cain lg2::debug(
107737abe9beSChris Cain "readTempSensors: Failed reading {PATH}, errno = {ERROR}",
107837abe9beSChris Cain "PATH", filePathString + maxSuffix, "ERROR",
107937abe9beSChris Cain e.code().value());
1080ace67d85SMatt Spinler }
1081ace67d85SMatt Spinler }
1082bb895cb8SChicago Duan
1083a26f1527SMatt Spinler uint32_t faultValue{0};
1084a26f1527SMatt Spinler try
1085bb895cb8SChicago Duan {
1086a26f1527SMatt Spinler faultValue = readFile<uint32_t>(filePathString + faultSuffix);
1087a26f1527SMatt Spinler }
1088a26f1527SMatt Spinler catch (const std::system_error& e)
1089a26f1527SMatt Spinler {
109037abe9beSChris Cain lg2::debug(
109137abe9beSChris Cain "readTempSensors: Failed reading {PATH}, errno = {ERROR}",
109237abe9beSChris Cain "PATH", filePathString + faultSuffix, "ERROR",
109337abe9beSChris Cain e.code().value());
1094a26f1527SMatt Spinler continue;
1095a26f1527SMatt Spinler }
1096bb895cb8SChicago Duan
1097ae157b68SChris Cain double tempValue{0};
1098ae157b68SChris Cain // NOTE: if OCC sends back 0xFF, kernal sets this fault value to 1.
1099bb895cb8SChicago Duan if (faultValue != 0)
1100bb895cb8SChicago Duan {
1101ae157b68SChris Cain tempValue = std::numeric_limits<double>::quiet_NaN();
1102ae157b68SChris Cain }
1103ae157b68SChris Cain else
1104818cc8d7SMatt Spinler {
1105ae157b68SChris Cain // Read the temperature
1106a26f1527SMatt Spinler try
1107bb895cb8SChicago Duan {
1108a26f1527SMatt Spinler tempValue = readFile<double>(filePathString + inputSuffix);
1109a26f1527SMatt Spinler }
1110a26f1527SMatt Spinler catch (const std::system_error& e)
1111a26f1527SMatt Spinler {
111237abe9beSChris Cain lg2::debug(
111337abe9beSChris Cain "readTempSensors: Failed reading {PATH}, errno = {ERROR}",
111437abe9beSChris Cain "PATH", filePathString + inputSuffix, "ERROR",
111537abe9beSChris Cain e.code().value());
1116cd0940b5SSheldon Bailey
1117cd0940b5SSheldon Bailey // if errno == EAGAIN(Resource temporarily unavailable) then set
1118ae157b68SChris Cain // temp to 0, to avoid using old temp, and affecting FAN
1119ae157b68SChris Cain // Control.
1120cd0940b5SSheldon Bailey if (e.code().value() == EAGAIN)
1121cd0940b5SSheldon Bailey {
1122cd0940b5SSheldon Bailey tempValue = 0;
1123cd0940b5SSheldon Bailey }
1124cd0940b5SSheldon Bailey // else the errno would be something like
1125cd0940b5SSheldon Bailey // EBADF(Bad file descriptor)
1126cd0940b5SSheldon Bailey // or ENOENT(No such file or directory)
1127cd0940b5SSheldon Bailey else
1128cd0940b5SSheldon Bailey {
1129a26f1527SMatt Spinler continue;
1130a26f1527SMatt Spinler }
1131cd0940b5SSheldon Bailey }
1132ae157b68SChris Cain }
1133bb895cb8SChicago Duan
1134818cc8d7SMatt Spinler // If this object path already has a value, only overwite
1135818cc8d7SMatt Spinler // it if the previous one was an NaN or a smaller value.
1136818cc8d7SMatt Spinler auto existing = sensorData.find(sensorPath);
1137818cc8d7SMatt Spinler if (existing != sensorData.end())
1138818cc8d7SMatt Spinler {
1139ae157b68SChris Cain // Multiple sensors found for this FRU type
1140ae157b68SChris Cain if ((std::isnan(existing->second) && (tempValue == 0)) ||
1141ae157b68SChris Cain ((existing->second == 0) && std::isnan(tempValue)))
1142ae157b68SChris Cain {
1143ae157b68SChris Cain // One of the redundant sensors has failed (0xFF/nan), and the
1144ae157b68SChris Cain // other sensor has no reading (0), so set the FRU to NaN to
1145ae157b68SChris Cain // force fan increase
1146ae157b68SChris Cain tempValue = std::numeric_limits<double>::quiet_NaN();
1147ae157b68SChris Cain existing->second = tempValue;
1148ae157b68SChris Cain }
1149818cc8d7SMatt Spinler if (std::isnan(existing->second) || (tempValue > existing->second))
1150818cc8d7SMatt Spinler {
1151818cc8d7SMatt Spinler existing->second = tempValue;
1152818cc8d7SMatt Spinler }
1153818cc8d7SMatt Spinler }
1154818cc8d7SMatt Spinler else
1155818cc8d7SMatt Spinler {
1156ae157b68SChris Cain // First sensor for this FRU type
1157818cc8d7SMatt Spinler sensorData[sensorPath] = tempValue;
1158818cc8d7SMatt Spinler }
1159818cc8d7SMatt Spinler }
1160bb895cb8SChicago Duan
1161818cc8d7SMatt Spinler // Now publish the values on D-Bus.
1162818cc8d7SMatt Spinler for (const auto& [objectPath, value] : sensorData)
1163818cc8d7SMatt Spinler {
1164818cc8d7SMatt Spinler dbus::OccDBusSensors::getOccDBus().setValue(objectPath,
1165818cc8d7SMatt Spinler value * std::pow(10, -3));
1166bb895cb8SChicago Duan
1167818cc8d7SMatt Spinler dbus::OccDBusSensors::getOccDBus().setOperationalStatus(
1168818cc8d7SMatt Spinler objectPath, !std::isnan(value));
1169818cc8d7SMatt Spinler
1170818cc8d7SMatt Spinler if (existingSensors.find(objectPath) == existingSensors.end())
11716fa848a9SChris Cain {
11725d66a0aaSChris Cain dbus::OccDBusSensors::getOccDBus().setChassisAssociation(
11733523cc00SChris Cain objectPath, {"all_sensors"});
11746fa848a9SChris Cain }
1175ae157b68SChris Cain existingSensors[objectPath] = occInstance;
1176bb895cb8SChicago Duan }
1177bb895cb8SChicago Duan }
1178bb895cb8SChicago Duan
getPowerLabelFunctionID(const std::string & value)11792d6ec909SPatrick Williams std::optional<std::string> Manager::getPowerLabelFunctionID(
11802d6ec909SPatrick Williams const std::string& value)
1181bb895cb8SChicago Duan {
1182bb895cb8SChicago Duan // If the value is "system", then the FunctionID is "system".
1183bb895cb8SChicago Duan if (value == "system")
1184bb895cb8SChicago Duan {
1185bb895cb8SChicago Duan return value;
1186bb895cb8SChicago Duan }
1187bb895cb8SChicago Duan
1188bb895cb8SChicago Duan // If the value is not "system", then the label value have 3 numbers, of
1189bb895cb8SChicago Duan // which we only care about the middle one:
1190bb895cb8SChicago Duan // <sensor id>_<function id>_<apss channel>
1191bb895cb8SChicago Duan // eg: The value is "0_10_5" , then the FunctionID is "10".
1192bb895cb8SChicago Duan if (value.find("_") == std::string::npos)
1193bb895cb8SChicago Duan {
1194bb895cb8SChicago Duan return std::nullopt;
1195bb895cb8SChicago Duan }
1196bb895cb8SChicago Duan
1197bb895cb8SChicago Duan auto powerLabelValue = value.substr((value.find("_") + 1));
1198bb895cb8SChicago Duan
1199bb895cb8SChicago Duan if (powerLabelValue.find("_") == std::string::npos)
1200bb895cb8SChicago Duan {
1201bb895cb8SChicago Duan return std::nullopt;
1202bb895cb8SChicago Duan }
1203bb895cb8SChicago Duan
1204bb895cb8SChicago Duan return powerLabelValue.substr(0, powerLabelValue.find("_"));
1205bb895cb8SChicago Duan }
1206bb895cb8SChicago Duan
readPowerSensors(const fs::path & path,uint32_t id)1207bb895cb8SChicago Duan void Manager::readPowerSensors(const fs::path& path, uint32_t id)
1208bb895cb8SChicago Duan {
1209bb895cb8SChicago Duan std::regex expr{"power\\d+_label$"}; // Example: power5_label
1210bb895cb8SChicago Duan for (auto& file : fs::directory_iterator(path))
1211bb895cb8SChicago Duan {
1212bb895cb8SChicago Duan if (!std::regex_search(file.path().string(), expr))
1213bb895cb8SChicago Duan {
1214bb895cb8SChicago Duan continue;
1215bb895cb8SChicago Duan }
1216bb895cb8SChicago Duan
1217a26f1527SMatt Spinler std::string labelValue;
1218a26f1527SMatt Spinler try
1219a26f1527SMatt Spinler {
1220a26f1527SMatt Spinler labelValue = readFile<std::string>(file.path());
1221a26f1527SMatt Spinler }
1222a26f1527SMatt Spinler catch (const std::system_error& e)
1223a26f1527SMatt Spinler {
122437abe9beSChris Cain lg2::debug(
122537abe9beSChris Cain "readPowerSensors: Failed reading {PATH}, errno = {ERROR}",
122637abe9beSChris Cain "PATH", file.path().string(), "ERROR", e.code().value());
1227bb895cb8SChicago Duan continue;
1228bb895cb8SChicago Duan }
1229bb895cb8SChicago Duan
1230bb895cb8SChicago Duan auto functionID = getPowerLabelFunctionID(labelValue);
1231bb895cb8SChicago Duan if (functionID == std::nullopt)
1232bb895cb8SChicago Duan {
1233bb895cb8SChicago Duan continue;
1234bb895cb8SChicago Duan }
1235bb895cb8SChicago Duan
1236bb895cb8SChicago Duan const std::string& tempLabel = "label";
1237bb895cb8SChicago Duan const std::string filePathString = file.path().string().substr(
1238bb895cb8SChicago Duan 0, file.path().string().length() - tempLabel.length());
1239bb895cb8SChicago Duan
1240bb895cb8SChicago Duan std::string sensorPath = OCC_SENSORS_ROOT + std::string("/power/");
1241bb895cb8SChicago Duan
1242bb895cb8SChicago Duan auto iter = powerSensorName.find(*functionID);
1243bb895cb8SChicago Duan if (iter == powerSensorName.end())
1244bb895cb8SChicago Duan {
1245bb895cb8SChicago Duan continue;
1246bb895cb8SChicago Duan }
1247bb895cb8SChicago Duan sensorPath.append(iter->second);
1248bb895cb8SChicago Duan
1249a26f1527SMatt Spinler double tempValue{0};
1250a26f1527SMatt Spinler
1251a26f1527SMatt Spinler try
1252bb895cb8SChicago Duan {
1253a26f1527SMatt Spinler tempValue = readFile<double>(filePathString + inputSuffix);
1254a26f1527SMatt Spinler }
1255a26f1527SMatt Spinler catch (const std::system_error& e)
1256bb895cb8SChicago Duan {
125737abe9beSChris Cain lg2::debug(
125837abe9beSChris Cain "readPowerSensors: Failed reading {PATH}, errno = {ERROR}",
125937abe9beSChris Cain "PATH", filePathString + inputSuffix, "ERROR",
126037abe9beSChris Cain e.code().value());
1261bb895cb8SChicago Duan continue;
1262bb895cb8SChicago Duan }
1263bb895cb8SChicago Duan
12645d66a0aaSChris Cain dbus::OccDBusSensors::getOccDBus().setUnit(
1265d84a8335SChris Cain sensorPath, "xyz.openbmc_project.Sensor.Value.Unit.Watts");
1266d84a8335SChris Cain
12675d66a0aaSChris Cain dbus::OccDBusSensors::getOccDBus().setValue(
1268bb895cb8SChicago Duan sensorPath, tempValue * std::pow(10, -3) * std::pow(10, -3));
1269bb895cb8SChicago Duan
1270d7542c83SPatrick Williams dbus::OccDBusSensors::getOccDBus().setOperationalStatus(
1271d7542c83SPatrick Williams sensorPath, true);
1272bb895cb8SChicago Duan
12735901abdaSMatt Spinler if (existingSensors.find(sensorPath) == existingSensors.end())
12745901abdaSMatt Spinler {
12753523cc00SChris Cain std::vector<std::string> fTypeList = {"all_sensors"};
12763523cc00SChris Cain if (iter->second == "total_power")
12773523cc00SChris Cain {
1278ff0ce409SChris Cain // Set sensor purpose as TotalPower
1279ff0ce409SChris Cain dbus::OccDBusSensors::getOccDBus().setPurpose(
1280ff0ce409SChris Cain sensorPath,
1281ff0ce409SChris Cain "xyz.openbmc_project.Sensor.Purpose.SensorPurpose.TotalPower");
12823523cc00SChris Cain }
12835d66a0aaSChris Cain dbus::OccDBusSensors::getOccDBus().setChassisAssociation(
12843523cc00SChris Cain sensorPath, fTypeList);
12855901abdaSMatt Spinler }
1286bb895cb8SChicago Duan existingSensors[sensorPath] = id;
1287bb895cb8SChicago Duan }
1288bb895cb8SChicago Duan return;
1289bb895cb8SChicago Duan }
1290bb895cb8SChicago Duan
readExtnSensors(const fs::path & path,uint32_t id)1291d2b044f9SSheldon Bailey void Manager::readExtnSensors(const fs::path& path, uint32_t id)
1292d2b044f9SSheldon Bailey {
1293d2b044f9SSheldon Bailey std::regex expr{"extn\\d+_label$"}; // Example: extn5_label
1294d2b044f9SSheldon Bailey for (auto& file : fs::directory_iterator(path))
1295d2b044f9SSheldon Bailey {
1296d2b044f9SSheldon Bailey if (!std::regex_search(file.path().string(), expr))
1297d2b044f9SSheldon Bailey {
1298d2b044f9SSheldon Bailey continue;
1299d2b044f9SSheldon Bailey }
1300d2b044f9SSheldon Bailey
1301d2b044f9SSheldon Bailey // Read in Label value of the sensor from file.
1302d2b044f9SSheldon Bailey std::string labelValue;
1303d2b044f9SSheldon Bailey try
1304d2b044f9SSheldon Bailey {
1305d2b044f9SSheldon Bailey labelValue = readFile<std::string>(file.path());
1306d2b044f9SSheldon Bailey }
1307d2b044f9SSheldon Bailey catch (const std::system_error& e)
1308d2b044f9SSheldon Bailey {
1309d2b044f9SSheldon Bailey lg2::debug(
1310d2b044f9SSheldon Bailey "readExtnSensors:label Failed reading {PATH}, errno = {ERROR}",
1311d2b044f9SSheldon Bailey "PATH", file.path().string(), "ERROR", e.code().value());
1312d2b044f9SSheldon Bailey continue;
1313d2b044f9SSheldon Bailey }
1314d2b044f9SSheldon Bailey const std::string& tempLabel = "label";
1315d2b044f9SSheldon Bailey const std::string filePathString = file.path().string().substr(
1316d2b044f9SSheldon Bailey 0, file.path().string().length() - tempLabel.length());
1317d2b044f9SSheldon Bailey
1318d2b044f9SSheldon Bailey std::string sensorPath = OCC_SENSORS_ROOT + std::string("/power/");
1319d2b044f9SSheldon Bailey
1320d2b044f9SSheldon Bailey // Labels of EXTN sections from OCC interface Document
1321d2b044f9SSheldon Bailey // have different formats.
1322d2b044f9SSheldon Bailey // 0x464d494e : FMIN 0x46444953 : FDIS
1323d2b044f9SSheldon Bailey // 0x46424153 : FBAS 0x46555400 : FUT
1324d2b044f9SSheldon Bailey // 0x464d4158 : FMAX 0x434c4950 : CLIP
1325d2b044f9SSheldon Bailey // 0x4d4f4445 : MODE 0x574f4643 : WOFC
1326d2b044f9SSheldon Bailey // 0x574f4649 : WOFI 0x5057524d : PWRM
1327d2b044f9SSheldon Bailey // 0x50575250 : PWRP 0x45525248 : ERRH
1328d2b044f9SSheldon Bailey // Label indicating byte 5 and 6 is the current (mem,proc) power in
1329d2b044f9SSheldon Bailey // Watts.
1330d2b044f9SSheldon Bailey if ((labelValue == EXTN_LABEL_PWRM_MEMORY_POWER) ||
1331d2b044f9SSheldon Bailey (labelValue == EXTN_LABEL_PWRP_PROCESSOR_POWER))
1332d2b044f9SSheldon Bailey {
1333d2b044f9SSheldon Bailey // Build the dbus String for this chiplet power asset.
1334d2b044f9SSheldon Bailey if (labelValue == EXTN_LABEL_PWRP_PROCESSOR_POWER)
1335d2b044f9SSheldon Bailey {
1336d2b044f9SSheldon Bailey labelValue = "_power";
1337d2b044f9SSheldon Bailey }
1338d2b044f9SSheldon Bailey else // else EXTN_LABEL_PWRM_MEMORY_POWER
1339d2b044f9SSheldon Bailey {
1340d2b044f9SSheldon Bailey labelValue = "_mem_power";
1341d2b044f9SSheldon Bailey }
1342d2b044f9SSheldon Bailey sensorPath.append("chiplet" + std::to_string(id) + labelValue);
1343d2b044f9SSheldon Bailey
1344d2b044f9SSheldon Bailey // Read in data value of the sensor from file.
1345d2b044f9SSheldon Bailey // Read in as string due to different format of data in sensors.
1346d2b044f9SSheldon Bailey std::string extnValue;
1347d2b044f9SSheldon Bailey try
1348d2b044f9SSheldon Bailey {
1349d2b044f9SSheldon Bailey extnValue = readFile<std::string>(filePathString + inputSuffix);
1350d2b044f9SSheldon Bailey }
1351d2b044f9SSheldon Bailey catch (const std::system_error& e)
1352d2b044f9SSheldon Bailey {
1353d2b044f9SSheldon Bailey lg2::debug(
1354d2b044f9SSheldon Bailey "readExtnSensors:value Failed reading {PATH}, errno = {ERROR}",
1355d2b044f9SSheldon Bailey "PATH", filePathString + inputSuffix, "ERROR",
1356d2b044f9SSheldon Bailey e.code().value());
1357d2b044f9SSheldon Bailey continue;
1358d2b044f9SSheldon Bailey }
1359d2b044f9SSheldon Bailey
1360d2b044f9SSheldon Bailey // For Power field, Convert last 4 bytes of hex string into number
1361d2b044f9SSheldon Bailey // value.
1362d2b044f9SSheldon Bailey std::stringstream ssData;
1363d2b044f9SSheldon Bailey ssData << std::hex << extnValue.substr(extnValue.length() - 4);
1364d2b044f9SSheldon Bailey uint16_t MyHexNumber;
1365d2b044f9SSheldon Bailey ssData >> MyHexNumber;
1366d2b044f9SSheldon Bailey
1367d2b044f9SSheldon Bailey // Convert output/DC power to input/AC power in Watts (round up)
1368d2b044f9SSheldon Bailey MyHexNumber =
1369d2b044f9SSheldon Bailey std::round(((MyHexNumber / (PS_DERATING_FACTOR / 100.0))));
1370d2b044f9SSheldon Bailey
1371d2b044f9SSheldon Bailey dbus::OccDBusSensors::getOccDBus().setUnit(
1372d2b044f9SSheldon Bailey sensorPath, "xyz.openbmc_project.Sensor.Value.Unit.Watts");
1373d2b044f9SSheldon Bailey
1374d2b044f9SSheldon Bailey dbus::OccDBusSensors::getOccDBus().setValue(sensorPath,
1375d2b044f9SSheldon Bailey MyHexNumber);
1376d2b044f9SSheldon Bailey
1377d2b044f9SSheldon Bailey dbus::OccDBusSensors::getOccDBus().setOperationalStatus(
1378d2b044f9SSheldon Bailey sensorPath, true);
1379d2b044f9SSheldon Bailey
1380d2b044f9SSheldon Bailey if (existingSensors.find(sensorPath) == existingSensors.end())
1381d2b044f9SSheldon Bailey {
1382d2b044f9SSheldon Bailey dbus::OccDBusSensors::getOccDBus().setChassisAssociation(
1383d2b044f9SSheldon Bailey sensorPath, {"all_sensors"});
1384d2b044f9SSheldon Bailey }
1385d2b044f9SSheldon Bailey
1386d2b044f9SSheldon Bailey existingSensors[sensorPath] = id;
1387b89d619cSSheldon Bailey } // End Extended Power Sensors.
1388d2b044f9SSheldon Bailey } // End For loop on files for Extended Sensors.
1389d2b044f9SSheldon Bailey return;
1390d2b044f9SSheldon Bailey }
1391d2b044f9SSheldon Bailey
setSensorValueToNaN(uint32_t id) const1392c8dd4599SSheldon Bailey void Manager::setSensorValueToNaN(uint32_t id) const
1393bb895cb8SChicago Duan {
1394bb895cb8SChicago Duan for (const auto& [sensorPath, occId] : existingSensors)
1395bb895cb8SChicago Duan {
1396bb895cb8SChicago Duan if (occId == id)
1397bb895cb8SChicago Duan {
13985d66a0aaSChris Cain dbus::OccDBusSensors::getOccDBus().setValue(
1399bb895cb8SChicago Duan sensorPath, std::numeric_limits<double>::quiet_NaN());
1400c8dd4599SSheldon Bailey
1401d7542c83SPatrick Williams dbus::OccDBusSensors::getOccDBus().setOperationalStatus(
1402d7542c83SPatrick Williams sensorPath, true);
1403bb895cb8SChicago Duan }
1404bb895cb8SChicago Duan }
1405bb895cb8SChicago Duan return;
1406bb895cb8SChicago Duan }
1407bb895cb8SChicago Duan
setSensorValueToNonFunctional(uint32_t id) const1408373af757SSheldon Bailey void Manager::setSensorValueToNonFunctional(uint32_t id) const
1409373af757SSheldon Bailey {
1410373af757SSheldon Bailey for (const auto& [sensorPath, occId] : existingSensors)
1411373af757SSheldon Bailey {
1412373af757SSheldon Bailey if (occId == id)
1413373af757SSheldon Bailey {
1414373af757SSheldon Bailey dbus::OccDBusSensors::getOccDBus().setValue(
1415373af757SSheldon Bailey sensorPath, std::numeric_limits<double>::quiet_NaN());
1416373af757SSheldon Bailey
1417d7542c83SPatrick Williams dbus::OccDBusSensors::getOccDBus().setOperationalStatus(
1418d7542c83SPatrick Williams sensorPath, false);
1419373af757SSheldon Bailey }
1420373af757SSheldon Bailey }
1421373af757SSheldon Bailey return;
1422373af757SSheldon Bailey }
1423373af757SSheldon Bailey
getSensorValues(std::unique_ptr<Status> & occ)14245d66a0aaSChris Cain void Manager::getSensorValues(std::unique_ptr<Status>& occ)
1425bb895cb8SChicago Duan {
1426e2d0a43cSChris Cain static bool tracedError[8] = {0};
1427e2d0a43cSChris Cain const fs::path sensorPath = occ->getHwmonPath();
14285d66a0aaSChris Cain const uint32_t id = occ->getOccInstanceID();
1429bb895cb8SChicago Duan
1430e2d0a43cSChris Cain if (fs::exists(sensorPath))
1431e2d0a43cSChris Cain {
1432bb895cb8SChicago Duan // Read temperature sensors
1433e2d0a43cSChris Cain readTempSensors(sensorPath, id);
1434b89d619cSSheldon Bailey // Read Extended sensors
1435d2b044f9SSheldon Bailey readExtnSensors(sensorPath, id);
1436bb895cb8SChicago Duan
14375d66a0aaSChris Cain if (occ->isMasterOcc())
1438bb895cb8SChicago Duan {
1439bb895cb8SChicago Duan // Read power sensors
1440e2d0a43cSChris Cain readPowerSensors(sensorPath, id);
1441e2d0a43cSChris Cain }
1442e2d0a43cSChris Cain tracedError[id] = false;
1443e2d0a43cSChris Cain }
1444e2d0a43cSChris Cain else
1445e2d0a43cSChris Cain {
1446e2d0a43cSChris Cain if (!tracedError[id])
1447e2d0a43cSChris Cain {
144837abe9beSChris Cain lg2::error(
144937abe9beSChris Cain "Manager::getSensorValues: OCC{INST} sensor path missing: {PATH}",
145037abe9beSChris Cain "INST", id, "PATH", sensorPath);
1451e2d0a43cSChris Cain tracedError[id] = true;
1452e2d0a43cSChris Cain }
1453bb895cb8SChicago Duan }
1454bb895cb8SChicago Duan
1455bb895cb8SChicago Duan return;
1456bb895cb8SChicago Duan }
1457bb895cb8SChicago Duan #endif
145817257673SChris Cain
145917257673SChris Cain // Read the altitude from DBus
readAltitude()146017257673SChris Cain void Manager::readAltitude()
146117257673SChris Cain {
146217257673SChris Cain static bool traceAltitudeErr = true;
146317257673SChris Cain
146417257673SChris Cain utils::PropertyValue altitudeProperty{};
146517257673SChris Cain try
146617257673SChris Cain {
146717257673SChris Cain altitudeProperty = utils::getProperty(ALTITUDE_PATH, ALTITUDE_INTERFACE,
146817257673SChris Cain ALTITUDE_PROP);
146917257673SChris Cain auto sensorVal = std::get<double>(altitudeProperty);
147017257673SChris Cain if (sensorVal < 0xFFFF)
147117257673SChris Cain {
147217257673SChris Cain if (sensorVal < 0)
147317257673SChris Cain {
147417257673SChris Cain altitude = 0;
147517257673SChris Cain }
147617257673SChris Cain else
147717257673SChris Cain {
147817257673SChris Cain // Round to nearest meter
147917257673SChris Cain altitude = uint16_t(sensorVal + 0.5);
148017257673SChris Cain }
148137abe9beSChris Cain lg2::debug("readAltitude: sensor={VALUE} ({ALT}m)", "VALUE",
148237abe9beSChris Cain sensorVal, "ALT", altitude);
148317257673SChris Cain traceAltitudeErr = true;
148417257673SChris Cain }
148517257673SChris Cain else
148617257673SChris Cain {
148717257673SChris Cain if (traceAltitudeErr)
148817257673SChris Cain {
148917257673SChris Cain traceAltitudeErr = false;
149037abe9beSChris Cain lg2::debug("Invalid altitude value: {ALT}", "ALT", sensorVal);
149117257673SChris Cain }
149217257673SChris Cain }
149317257673SChris Cain }
1494af40808fSPatrick Williams catch (const sdbusplus::exception_t& e)
149517257673SChris Cain {
149617257673SChris Cain if (traceAltitudeErr)
149717257673SChris Cain {
149817257673SChris Cain traceAltitudeErr = false;
149937abe9beSChris Cain lg2::info("Unable to read Altitude: {ERROR}", "ERROR", e.what());
150017257673SChris Cain }
150117257673SChris Cain altitude = 0xFFFF; // not available
150217257673SChris Cain }
150317257673SChris Cain }
150417257673SChris Cain
150517257673SChris Cain // Callback function when ambient temperature changes
ambientCallback(sdbusplus::message_t & msg)1506af40808fSPatrick Williams void Manager::ambientCallback(sdbusplus::message_t& msg)
150717257673SChris Cain {
150817257673SChris Cain double currentTemp = 0;
150917257673SChris Cain uint8_t truncatedTemp = 0xFF;
151017257673SChris Cain std::string msgSensor;
151117257673SChris Cain std::map<std::string, std::variant<double>> msgData;
151217257673SChris Cain msg.read(msgSensor, msgData);
151317257673SChris Cain
151417257673SChris Cain auto valPropMap = msgData.find(AMBIENT_PROP);
151517257673SChris Cain if (valPropMap == msgData.end())
151617257673SChris Cain {
151737abe9beSChris Cain lg2::debug("ambientCallback: Unknown ambient property changed");
151817257673SChris Cain return;
151917257673SChris Cain }
152017257673SChris Cain currentTemp = std::get<double>(valPropMap->second);
152117257673SChris Cain if (std::isnan(currentTemp))
152217257673SChris Cain {
152317257673SChris Cain truncatedTemp = 0xFF;
152417257673SChris Cain }
152517257673SChris Cain else
152617257673SChris Cain {
152717257673SChris Cain if (currentTemp < 0)
152817257673SChris Cain {
152917257673SChris Cain truncatedTemp = 0;
153017257673SChris Cain }
153117257673SChris Cain else
153217257673SChris Cain {
153317257673SChris Cain // Round to nearest degree C
153417257673SChris Cain truncatedTemp = uint8_t(currentTemp + 0.5);
153517257673SChris Cain }
153617257673SChris Cain }
153717257673SChris Cain
153817257673SChris Cain // If ambient changes, notify OCCs
153917257673SChris Cain if (truncatedTemp != ambient)
154017257673SChris Cain {
154137abe9beSChris Cain lg2::debug("ambientCallback: Ambient change from {OLD} to {NEW}C",
154237abe9beSChris Cain "OLD", ambient, "NEW", currentTemp);
154317257673SChris Cain
154417257673SChris Cain ambient = truncatedTemp;
154517257673SChris Cain if (altitude == 0xFFFF)
154617257673SChris Cain {
154717257673SChris Cain // No altitude yet, try reading again
154817257673SChris Cain readAltitude();
154917257673SChris Cain }
155017257673SChris Cain
155137abe9beSChris Cain lg2::debug("ambientCallback: Ambient: {TEMP}C, altitude: {ALT}m",
155237abe9beSChris Cain "TEMP", ambient, "ALT", altitude);
155317257673SChris Cain #ifdef POWER10
155417257673SChris Cain // Send ambient and altitude to all OCCs
155517257673SChris Cain for (auto& obj : statusObjects)
155617257673SChris Cain {
155717257673SChris Cain if (obj->occActive())
155817257673SChris Cain {
155917257673SChris Cain obj->sendAmbient(ambient, altitude);
156017257673SChris Cain }
156117257673SChris Cain }
156217257673SChris Cain #endif // POWER10
156317257673SChris Cain }
156417257673SChris Cain }
156517257673SChris Cain
156617257673SChris Cain // return the current ambient and altitude readings
getAmbientData(bool & ambientValid,uint8_t & ambientTemp,uint16_t & altitudeValue) const156717257673SChris Cain void Manager::getAmbientData(bool& ambientValid, uint8_t& ambientTemp,
156817257673SChris Cain uint16_t& altitudeValue) const
156917257673SChris Cain {
157017257673SChris Cain ambientValid = true;
157117257673SChris Cain ambientTemp = ambient;
157217257673SChris Cain altitudeValue = altitude;
157317257673SChris Cain
157417257673SChris Cain if (ambient == 0xFF)
157517257673SChris Cain {
157617257673SChris Cain ambientValid = false;
157717257673SChris Cain }
157817257673SChris Cain }
157917257673SChris Cain
1580a7b74dc3SChris Cain #ifdef POWER10
15817f89e4d1SChris Cain // Called when waitForAllOccsTimer expires
15827f89e4d1SChris Cain // After the first OCC goes active, this timer will be started (60 seconds)
occsNotAllRunning()1583a7b74dc3SChris Cain void Manager::occsNotAllRunning()
1584a7b74dc3SChris Cain {
1585f0295f52SChris Cain if (resetInProgress)
1586f0295f52SChris Cain {
158737abe9beSChris Cain lg2::warning(
1588f0295f52SChris Cain "occsNotAllRunning: Ignoring waitForAllOccsTimer because reset is in progress");
1589f0295f52SChris Cain return;
1590f0295f52SChris Cain }
1591a7b74dc3SChris Cain if (activeCount != statusObjects.size())
1592a7b74dc3SChris Cain {
1593a7b74dc3SChris Cain // Not all OCCs went active
159437abe9beSChris Cain lg2::warning(
159537abe9beSChris Cain "occsNotAllRunning: Active OCC count ({COUNT}) does not match expected count ({EXP})",
159637abe9beSChris Cain "COUNT", activeCount, "EXP", statusObjects.size());
15977f89e4d1SChris Cain // Procs may be garded, so may be expected
1598a7b74dc3SChris Cain }
1599a7b74dc3SChris Cain
1600f0295f52SChris Cain if (resetRequired)
1601f0295f52SChris Cain {
1602f0295f52SChris Cain initiateOccRequest(resetInstance);
1603f0295f52SChris Cain
1604f0295f52SChris Cain if (!waitForAllOccsTimer->isEnabled())
1605f0295f52SChris Cain {
160637abe9beSChris Cain lg2::warning("occsNotAllRunning: Restarting waitForAllOccTimer");
1607f0295f52SChris Cain // restart occ wait timer
1608f0295f52SChris Cain waitForAllOccsTimer->restartOnce(60s);
1609f0295f52SChris Cain }
1610f0295f52SChris Cain }
1611f0295f52SChris Cain else
1612f0295f52SChris Cain {
1613a7b74dc3SChris Cain validateOccMaster();
1614a7b74dc3SChris Cain }
1615f0295f52SChris Cain }
1616755af102SChris Cain
1617755af102SChris Cain #ifdef PLDM
1618c33171bbSChris Cain // Called when throttlePldmTraceTimer expires.
1619a19bd428SChris Cain // If this timer expires, that indicates there are no OCC active sensor PDRs
1620c33171bbSChris Cain // found which will trigger pldm traces to be throttled.
1621c33171bbSChris Cain // The second time this timer expires, a PEL will get created.
throttlePldmTraceExpired()1622c33171bbSChris Cain void Manager::throttlePldmTraceExpired()
1623755af102SChris Cain {
16247651c06bSChris Cain if (utils::isHostRunning())
16257651c06bSChris Cain {
1626c33171bbSChris Cain if (!onPldmTimeoutCreatePel)
1627c33171bbSChris Cain {
1628755af102SChris Cain // Throttle traces
1629755af102SChris Cain pldmHandle->setTraceThrottle(true);
1630c33171bbSChris Cain // Restart timer to log a PEL when timer expires
1631c33171bbSChris Cain onPldmTimeoutCreatePel = true;
1632c33171bbSChris Cain throttlePldmTraceTimer->restartOnce(40min);
1633c33171bbSChris Cain }
1634c33171bbSChris Cain else
1635c33171bbSChris Cain {
163637abe9beSChris Cain lg2::error(
1637c33171bbSChris Cain "throttlePldmTraceExpired(): OCC active sensors still not available!");
16384b82f3e3SChris Cain // Create PEL
16394b82f3e3SChris Cain createPldmSensorPEL();
16404b82f3e3SChris Cain }
1641c33171bbSChris Cain }
16427651c06bSChris Cain else
16437651c06bSChris Cain {
16447651c06bSChris Cain // Make sure traces are not throttled
16457651c06bSChris Cain pldmHandle->setTraceThrottle(false);
164637abe9beSChris Cain lg2::info(
1647c33171bbSChris Cain "throttlePldmTraceExpired(): host it not running ignoring sensor timer");
16487651c06bSChris Cain }
16497651c06bSChris Cain }
16504b82f3e3SChris Cain
createPldmSensorPEL()16514b82f3e3SChris Cain void Manager::createPldmSensorPEL()
16524b82f3e3SChris Cain {
16534b82f3e3SChris Cain Error::Descriptor d = Error::Descriptor(MISSING_OCC_SENSORS_PATH);
16544b82f3e3SChris Cain std::map<std::string, std::string> additionalData;
16554b82f3e3SChris Cain
16564b82f3e3SChris Cain additionalData.emplace("_PID", std::to_string(getpid()));
16574b82f3e3SChris Cain
165837abe9beSChris Cain lg2::info(
165937abe9beSChris Cain "createPldmSensorPEL(): Unable to find PLDM sensors for the OCCs");
16604b82f3e3SChris Cain
16614b82f3e3SChris Cain auto& bus = utils::getBus();
16624b82f3e3SChris Cain
16634b82f3e3SChris Cain try
16644b82f3e3SChris Cain {
16654b82f3e3SChris Cain FFDCFiles ffdc;
16664b82f3e3SChris Cain // Add occ-control journal traces to PEL FFDC
16674b82f3e3SChris Cain auto occJournalFile =
16684b82f3e3SChris Cain FFDC::addJournalEntries(ffdc, "openpower-occ-control", 40);
16694b82f3e3SChris Cain
16704b82f3e3SChris Cain static constexpr auto loggingObjectPath =
16714b82f3e3SChris Cain "/xyz/openbmc_project/logging";
16724b82f3e3SChris Cain static constexpr auto opLoggingInterface = "org.open_power.Logging.PEL";
1673d7542c83SPatrick Williams std::string service =
1674d7542c83SPatrick Williams utils::getService(loggingObjectPath, opLoggingInterface);
1675d7542c83SPatrick Williams auto method =
1676d7542c83SPatrick Williams bus.new_method_call(service.c_str(), loggingObjectPath,
1677d7542c83SPatrick Williams opLoggingInterface, "CreatePELWithFFDCFiles");
16784b82f3e3SChris Cain
16791c3349e4SChris Cain // Set level to Warning (Predictive).
16804b82f3e3SChris Cain auto level =
16814b82f3e3SChris Cain sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage(
16824b82f3e3SChris Cain sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level::
16831c3349e4SChris Cain Warning);
16844b82f3e3SChris Cain
16854b82f3e3SChris Cain method.append(d.path, level, additionalData, ffdc);
16864b82f3e3SChris Cain bus.call(method);
16874b82f3e3SChris Cain }
16884b82f3e3SChris Cain catch (const sdbusplus::exception_t& e)
16894b82f3e3SChris Cain {
169037abe9beSChris Cain lg2::error("Failed to create MISSING_OCC_SENSORS PEL: {ERROR}", "ERROR",
169137abe9beSChris Cain e.what());
16924b82f3e3SChris Cain }
1693755af102SChris Cain }
1694755af102SChris Cain #endif // PLDM
1695a7b74dc3SChris Cain #endif // POWER10
1696a7b74dc3SChris Cain
1697a7b74dc3SChris Cain // Verify single master OCC and start presence monitor
validateOccMaster()1698a7b74dc3SChris Cain void Manager::validateOccMaster()
1699a7b74dc3SChris Cain {
1700a7b74dc3SChris Cain int masterInstance = -1;
1701a7b74dc3SChris Cain for (auto& obj : statusObjects)
1702a7b74dc3SChris Cain {
1703bd551de3SChris Cain auto instance = obj->getOccInstanceID();
1704bae4d07eSChris Cain #ifdef POWER10
1705bae4d07eSChris Cain if (!obj->occActive())
1706bae4d07eSChris Cain {
1707bae4d07eSChris Cain if (utils::isHostRunning())
1708bae4d07eSChris Cain {
1709bd551de3SChris Cain // Check if sensor was queued while waiting for discovery
1710bd551de3SChris Cain auto match = queuedActiveState.find(instance);
1711bd551de3SChris Cain if (match != queuedActiveState.end())
1712bd551de3SChris Cain {
17137f89e4d1SChris Cain queuedActiveState.erase(match);
171437abe9beSChris Cain lg2::info("validateOccMaster: OCC{INST} is ACTIVE (queued)",
171537abe9beSChris Cain "INST", instance);
1716bd551de3SChris Cain obj->occActive(true);
1717bd551de3SChris Cain }
1718bd551de3SChris Cain else
1719bd551de3SChris Cain {
1720bae4d07eSChris Cain // OCC does not appear to be active yet, check active sensor
1721fb0a5c3cSPatrick Williams #ifdef PLDM
1722bd551de3SChris Cain pldmHandle->checkActiveSensor(instance);
1723fb0a5c3cSPatrick Williams #endif
1724bae4d07eSChris Cain if (obj->occActive())
1725bae4d07eSChris Cain {
172637abe9beSChris Cain lg2::info(
172737abe9beSChris Cain "validateOccMaster: OCC{INST} is ACTIVE after reading sensor",
172837abe9beSChris Cain "INST", instance);
1729bae4d07eSChris Cain }
1730bae4d07eSChris Cain }
1731bd551de3SChris Cain }
1732bae4d07eSChris Cain else
1733bae4d07eSChris Cain {
173437abe9beSChris Cain lg2::warning(
173537abe9beSChris Cain "validateOccMaster: HOST is not running (OCC{INST})",
173637abe9beSChris Cain "INST", instance);
1737bae4d07eSChris Cain return;
1738bae4d07eSChris Cain }
1739bae4d07eSChris Cain }
1740bae4d07eSChris Cain #endif // POWER10
1741bae4d07eSChris Cain
1742a7b74dc3SChris Cain if (obj->isMasterOcc())
1743a7b74dc3SChris Cain {
17445d66a0aaSChris Cain obj->addPresenceWatchMaster();
17455d66a0aaSChris Cain
1746a7b74dc3SChris Cain if (masterInstance == -1)
1747a7b74dc3SChris Cain {
1748bd551de3SChris Cain masterInstance = instance;
1749a7b74dc3SChris Cain }
1750a7b74dc3SChris Cain else
1751a7b74dc3SChris Cain {
175237abe9beSChris Cain lg2::error(
175337abe9beSChris Cain "validateOccMaster: Multiple OCC masters! ({MAST1} and {MAST2})",
175437abe9beSChris Cain "MAST1", masterInstance, "MAST2", instance);
1755a7b74dc3SChris Cain // request reset
17569789e71fSEddie James obj->deviceError(Error::Descriptor(PRESENCE_ERROR_PATH));
1757a7b74dc3SChris Cain }
1758a7b74dc3SChris Cain }
1759a7b74dc3SChris Cain }
1760bae4d07eSChris Cain
1761a7b74dc3SChris Cain if (masterInstance < 0)
1762a7b74dc3SChris Cain {
176337abe9beSChris Cain lg2::error("validateOccMaster: Master OCC not found! (of {NUM} OCCs)",
176437abe9beSChris Cain "NUM", statusObjects.size());
1765a7b74dc3SChris Cain // request reset
17669789e71fSEddie James statusObjects.front()->deviceError(
17679789e71fSEddie James Error::Descriptor(PRESENCE_ERROR_PATH));
1768a7b74dc3SChris Cain }
1769a7b74dc3SChris Cain else
1770a7b74dc3SChris Cain {
177137abe9beSChris Cain lg2::info("validateOccMaster: OCC{INST} is master of {COUNT} OCCs",
177237abe9beSChris Cain "INST", masterInstance, "COUNT", activeCount);
177331a2f13aSSheldon Bailey #ifdef POWER10
177431a2f13aSSheldon Bailey pmode->updateDbusSafeMode(false);
177531a2f13aSSheldon Bailey #endif
1776a7b74dc3SChris Cain }
1777a7b74dc3SChris Cain }
1778a7b74dc3SChris Cain
updatePcapBounds() const177940501a23SChris Cain void Manager::updatePcapBounds() const
178040501a23SChris Cain {
178140501a23SChris Cain if (pcap)
178240501a23SChris Cain {
178340501a23SChris Cain pcap->updatePcapBounds();
178440501a23SChris Cain }
178540501a23SChris Cain }
178640501a23SChris Cain
1787*c488bac1SChris Cain // Clean up any variables since the OCC is no longer running.
1788*c488bac1SChris Cain // Called when pldm receives an event indicating host is powered off.
hostPoweredOff()1789*c488bac1SChris Cain void Manager::hostPoweredOff()
1790*c488bac1SChris Cain {
1791*c488bac1SChris Cain if (resetRequired)
1792*c488bac1SChris Cain {
1793*c488bac1SChris Cain lg2::info("hostPoweredOff: Clearing resetRequired for OCC{INST}",
1794*c488bac1SChris Cain "INST", resetInstance);
1795*c488bac1SChris Cain resetRequired = false;
1796*c488bac1SChris Cain }
1797*c488bac1SChris Cain if (resetInProgress)
1798*c488bac1SChris Cain {
1799*c488bac1SChris Cain lg2::info("hostPoweredOff: Clearing resetInProgress for OCC{INST}",
1800*c488bac1SChris Cain "INST", resetInstance);
1801*c488bac1SChris Cain resetInProgress = false;
1802*c488bac1SChris Cain }
1803*c488bac1SChris Cain resetInstance = 255;
1804*c488bac1SChris Cain }
1805*c488bac1SChris Cain
1806dfc7ec73SVishwanatha Subbanna } // namespace occ
1807dfc7ec73SVishwanatha Subbanna } // namespace open_power
1808