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