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