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