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