blob: ada95efd3c232f05340b9b9fd4761ee7aa09ae50 [file] [log] [blame]
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +05301#include "config.h"
2
Gunnar Mills94df8c92018-09-14 14:50:03 -05003#include "occ_manager.hpp"
4
5#include "i2c_occ.hpp"
Chicago Duanbb895cb2021-06-18 19:37:16 +08006#include "occ_dbus.hpp"
Chris Cain4b82f3e2024-04-22 14:44:29 -05007#include "occ_errors.hpp"
Gunnar Mills94df8c92018-09-14 14:50:03 -05008#include "utils.hpp"
9
George Liub5ca1012021-09-10 12:53:11 +080010#include <phosphor-logging/elog-errors.hpp>
11#include <phosphor-logging/log.hpp>
12#include <xyz/openbmc_project/Common/error.hpp>
13
Matt Spinlerd267cec2021-09-01 14:49:19 -050014#include <chrono>
Chicago Duanbb895cb2021-06-18 19:37:16 +080015#include <cmath>
George Liubcef3b42021-09-10 12:39:02 +080016#include <filesystem>
Chris Cain36f9cde2021-11-22 11:18:21 -060017#include <fstream>
Chicago Duanbb895cb2021-06-18 19:37:16 +080018#include <regex>
Gunnar Mills94df8c92018-09-14 14:50:03 -050019
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +053020namespace open_power
21{
22namespace occ
23{
24
Matt Spinler8b8abee2021-08-25 15:18:21 -050025constexpr uint32_t fruTypeNotAvailable = 0xFF;
Matt Spinlera26f1522021-08-25 15:50:20 -050026constexpr auto fruTypeSuffix = "fru_type";
27constexpr auto faultSuffix = "fault";
28constexpr auto inputSuffix = "input";
Matt Spinlerace67d82021-10-18 13:41:57 -050029constexpr auto maxSuffix = "max";
Matt Spinler8b8abee2021-08-25 15:18:21 -050030
Chris Cain1718fd82022-02-16 16:39:50 -060031const auto HOST_ON_FILE = "/run/openbmc/host@0-on";
32
Chris Caina8857c52021-01-27 11:53:05 -060033using namespace phosphor::logging;
Chris Caina7b74dc2021-11-10 17:03:43 -060034using namespace std::literals::chrono_literals;
Chris Caina8857c52021-01-27 11:53:05 -060035
Matt Spinlera26f1522021-08-25 15:50:20 -050036template <typename T>
37T readFile(const std::string& path)
38{
39 std::ifstream ifs;
40 ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit |
41 std::ifstream::eofbit);
42 T data;
43
44 try
45 {
46 ifs.open(path);
47 ifs >> data;
48 ifs.close();
49 }
50 catch (const std::exception& e)
51 {
52 auto err = errno;
53 throw std::system_error(err, std::generic_category());
54 }
55
56 return data;
57}
58
Chris Cainc33171b2024-05-24 16:14:50 -050059// findAndCreateObjects():
60// Takes care of getting the required objects created and
61// finds the available devices/processors.
62// (function is called everytime the discoverTimer expires)
63// - create the PowerMode object to control OCC modes
64// - create statusObjects for each OCC device found
65// - waits for OCC Active sensors PDRs to become available
66// - restart discoverTimer if all data is not available yet
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +053067void Manager::findAndCreateObjects()
68{
Matt Spinlerd267cec2021-09-01 14:49:19 -050069#ifndef POWER10
Deepak Kodihalli370f06b2017-10-25 04:26:07 -050070 for (auto id = 0; id < MAX_CPUS; ++id)
71 {
Deepak Kodihalli30417a12017-12-04 00:54:01 -060072 // Create one occ per cpu
73 auto occ = std::string(OCC_NAME) + std::to_string(id);
74 createObjects(occ);
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +053075 }
Matt Spinlerd267cec2021-09-01 14:49:19 -050076#else
Chris Cain613dc902022-04-08 09:56:22 -050077 if (!pmode)
78 {
79 // Create the power mode object
80 pmode = std::make_unique<powermode::PowerMode>(
81 *this, powermode::PMODE_PATH, powermode::PIPS_PATH, event);
82 }
83
Chris Cain1718fd82022-02-16 16:39:50 -060084 if (!fs::exists(HOST_ON_FILE))
Matt Spinlerd267cec2021-09-01 14:49:19 -050085 {
Chris Cainbae4d072022-02-28 09:46:50 -060086 static bool statusObjCreated = false;
87 if (!statusObjCreated)
Chris Cain1718fd82022-02-16 16:39:50 -060088 {
Chris Cainbae4d072022-02-28 09:46:50 -060089 // Create the OCCs based on on the /dev/occX devices
90 auto occs = findOCCsInDev();
Chris Cain1718fd82022-02-16 16:39:50 -060091
Chris Cainbae4d072022-02-28 09:46:50 -060092 if (occs.empty() || (prevOCCSearch.size() != occs.size()))
Chris Cain1718fd82022-02-16 16:39:50 -060093 {
Chris Cainbae4d072022-02-28 09:46:50 -060094 // Something changed or no OCCs yet, try again in 10s.
95 // Note on the first pass prevOCCSearch will be empty,
96 // so there will be at least one delay to give things
97 // a chance to settle.
98 prevOCCSearch = occs;
99
100 log<level::INFO>(
Patrick Williams48002492024-02-13 21:43:32 -0600101 std::format(
Chris Cainbae4d072022-02-28 09:46:50 -0600102 "Manager::findAndCreateObjects(): Waiting for OCCs (currently {})",
103 occs.size())
104 .c_str());
105
106 discoverTimer->restartOnce(10s);
107 }
108 else
109 {
110 // All OCCs appear to be available, create status objects
111
112 // createObjects requires OCC0 first.
113 std::sort(occs.begin(), occs.end());
114
115 log<level::INFO>(
Patrick Williams48002492024-02-13 21:43:32 -0600116 std::format(
Chris Cainbae4d072022-02-28 09:46:50 -0600117 "Manager::findAndCreateObjects(): Creating {} OCC Status Objects",
118 occs.size())
119 .c_str());
120 for (auto id : occs)
121 {
122 createObjects(std::string(OCC_NAME) + std::to_string(id));
123 }
124 statusObjCreated = true;
Chris Cain6d8f37a2022-04-29 13:46:01 -0500125 waitingForAllOccActiveSensors = true;
Chris Cainc86d80f2023-05-04 15:49:18 -0500126
127 // Find/update the processor path associated with each OCC
128 for (auto& obj : statusObjects)
129 {
130 obj->updateProcAssociation();
131 }
Chris Cainbae4d072022-02-28 09:46:50 -0600132 }
133 }
134
Chris Cain6d8f37a2022-04-29 13:46:01 -0500135 if (statusObjCreated && waitingForAllOccActiveSensors)
Chris Cainbae4d072022-02-28 09:46:50 -0600136 {
137 static bool tracedHostWait = false;
138 if (utils::isHostRunning())
139 {
140 if (tracedHostWait)
141 {
142 log<level::INFO>(
143 "Manager::findAndCreateObjects(): Host is running");
144 tracedHostWait = false;
145 }
Chris Cainbae4d072022-02-28 09:46:50 -0600146 checkAllActiveSensors();
147 }
148 else
149 {
150 if (!tracedHostWait)
151 {
152 log<level::INFO>(
153 "Manager::findAndCreateObjects(): Waiting for host to start");
154 tracedHostWait = true;
155 }
156 discoverTimer->restartOnce(30s);
Chris Cain7651c062024-05-02 14:14:06 -0500157#ifdef PLDM
Chris Cainc33171b2024-05-24 16:14:50 -0500158 if (throttlePldmTraceTimer->isEnabled())
Chris Cain7651c062024-05-02 14:14:06 -0500159 {
160 // Host is no longer running, disable throttle timer and
161 // make sure traces are not throttled
162 log<level::INFO>(
163 "findAndCreateObjects(): disabling sensor timer");
Chris Cainc33171b2024-05-24 16:14:50 -0500164 throttlePldmTraceTimer->setEnabled(false);
Chris Cain7651c062024-05-02 14:14:06 -0500165 pldmHandle->setTraceThrottle(false);
166 }
167#endif
Chris Cain1718fd82022-02-16 16:39:50 -0600168 }
169 }
Matt Spinlerd267cec2021-09-01 14:49:19 -0500170 }
171 else
172 {
Chris Cain1718fd82022-02-16 16:39:50 -0600173 log<level::INFO>(
Patrick Williams48002492024-02-13 21:43:32 -0600174 std::format(
Chris Cain1718fd82022-02-16 16:39:50 -0600175 "Manager::findAndCreateObjects(): Waiting for {} to complete...",
176 HOST_ON_FILE)
177 .c_str());
178 discoverTimer->restartOnce(10s);
Matt Spinlerd267cec2021-09-01 14:49:19 -0500179 }
180#endif
181}
182
Chris Cainbae4d072022-02-28 09:46:50 -0600183#ifdef POWER10
184// Check if all occActive sensors are available
185void Manager::checkAllActiveSensors()
186{
187 static bool allActiveSensorAvailable = false;
188 static bool tracedSensorWait = false;
Chris Cain082a6ca2023-03-21 10:27:26 -0500189 static bool waitingForHost = false;
Chris Cainbae4d072022-02-28 09:46:50 -0600190
Chris Cain082a6ca2023-03-21 10:27:26 -0500191 if (open_power::occ::utils::isHostRunning())
Chris Cainbae4d072022-02-28 09:46:50 -0600192 {
Chris Cain082a6ca2023-03-21 10:27:26 -0500193 if (waitingForHost)
Chris Cainbae4d072022-02-28 09:46:50 -0600194 {
Chris Cain082a6ca2023-03-21 10:27:26 -0500195 waitingForHost = false;
196 log<level::INFO>("checkAllActiveSensors(): Host is now running");
197 }
198
199 // Start with the assumption that all are available
200 allActiveSensorAvailable = true;
201 for (auto& obj : statusObjects)
202 {
203 if ((!obj->occActive()) && (!obj->getPldmSensorReceived()))
Chris Cainbae4d072022-02-28 09:46:50 -0600204 {
Chris Cain7f89e4d2022-05-09 13:27:45 -0500205 auto instance = obj->getOccInstanceID();
206 // Check if sensor was queued while waiting for discovery
207 auto match = queuedActiveState.find(instance);
208 if (match != queuedActiveState.end())
Chris Cainbd551de2022-04-26 13:41:16 -0500209 {
Chris Cain7f89e4d2022-05-09 13:27:45 -0500210 queuedActiveState.erase(match);
Chris Cainbd551de2022-04-26 13:41:16 -0500211 log<level::INFO>(
Patrick Williams48002492024-02-13 21:43:32 -0600212 std::format(
Chris Cain7f89e4d2022-05-09 13:27:45 -0500213 "checkAllActiveSensors(): OCC{} is ACTIVE (queued)",
Chris Cainbd551de2022-04-26 13:41:16 -0500214 instance)
215 .c_str());
Chris Cain7f89e4d2022-05-09 13:27:45 -0500216 obj->occActive(true);
Chris Cainbd551de2022-04-26 13:41:16 -0500217 }
Chris Cain7f89e4d2022-05-09 13:27:45 -0500218 else
219 {
220 allActiveSensorAvailable = false;
221 if (!tracedSensorWait)
222 {
223 log<level::INFO>(
Patrick Williams48002492024-02-13 21:43:32 -0600224 std::format(
Chris Cain7f89e4d2022-05-09 13:27:45 -0500225 "checkAllActiveSensors(): Waiting on OCC{} Active sensor",
226 instance)
227 .c_str());
228 tracedSensorWait = true;
Chris Cain755af102024-02-27 16:09:51 -0600229#ifdef PLDM
Chris Cainc33171b2024-05-24 16:14:50 -0500230 // Make sure PLDM traces are not throttled
Chris Cain755af102024-02-27 16:09:51 -0600231 pldmHandle->setTraceThrottle(false);
Chris Cainc33171b2024-05-24 16:14:50 -0500232 // Start timer to throttle PLDM traces when timer
Chris Cain755af102024-02-27 16:09:51 -0600233 // expires
Chris Cainc33171b2024-05-24 16:14:50 -0500234 onPldmTimeoutCreatePel = false;
235 throttlePldmTraceTimer->restartOnce(5min);
Chris Cain755af102024-02-27 16:09:51 -0600236#endif
Chris Cain7f89e4d2022-05-09 13:27:45 -0500237 }
Patrick Williamsfb0a5c32024-02-28 11:27:00 -0600238#ifdef PLDM
Chris Cain7f89e4d2022-05-09 13:27:45 -0500239 pldmHandle->checkActiveSensor(obj->getOccInstanceID());
Patrick Williamsfb0a5c32024-02-28 11:27:00 -0600240#endif
Chris Cain7f89e4d2022-05-09 13:27:45 -0500241 break;
242 }
Chris Cainbd551de2022-04-26 13:41:16 -0500243 }
Chris Cainbae4d072022-02-28 09:46:50 -0600244 }
245 }
Chris Cain082a6ca2023-03-21 10:27:26 -0500246 else
247 {
248 if (!waitingForHost)
249 {
250 waitingForHost = true;
251 log<level::INFO>(
252 "checkAllActiveSensors(): Waiting for host to start");
Chris Cain7651c062024-05-02 14:14:06 -0500253#ifdef PLDM
Chris Cainc33171b2024-05-24 16:14:50 -0500254 if (throttlePldmTraceTimer->isEnabled())
Chris Cain7651c062024-05-02 14:14:06 -0500255 {
256 // Host is no longer running, disable throttle timer and
257 // make sure traces are not throttled
258 log<level::INFO>(
259 "checkAllActiveSensors(): disabling sensor timer");
Chris Cainc33171b2024-05-24 16:14:50 -0500260 throttlePldmTraceTimer->setEnabled(false);
Chris Cain7651c062024-05-02 14:14:06 -0500261 pldmHandle->setTraceThrottle(false);
262 }
263#endif
Chris Cain082a6ca2023-03-21 10:27:26 -0500264 }
265 }
Chris Cainbae4d072022-02-28 09:46:50 -0600266
267 if (allActiveSensorAvailable)
268 {
269 // All sensors were found, disable the discovery timer
Chris Cain7f89e4d2022-05-09 13:27:45 -0500270 if (discoverTimer->isEnabled())
271 {
Chris Cainf55f91a2022-05-27 13:40:15 -0500272 discoverTimer->setEnabled(false);
Chris Cain7f89e4d2022-05-09 13:27:45 -0500273 }
Chris Cain755af102024-02-27 16:09:51 -0600274#ifdef PLDM
Chris Cainc33171b2024-05-24 16:14:50 -0500275 if (throttlePldmTraceTimer->isEnabled())
Chris Cain755af102024-02-27 16:09:51 -0600276 {
277 // Disable throttle timer and make sure traces are not throttled
Chris Cainc33171b2024-05-24 16:14:50 -0500278 throttlePldmTraceTimer->setEnabled(false);
Chris Cain755af102024-02-27 16:09:51 -0600279 pldmHandle->setTraceThrottle(false);
280 }
281#endif
Chris Cain7f89e4d2022-05-09 13:27:45 -0500282 if (waitingForAllOccActiveSensors)
283 {
284 log<level::INFO>(
285 "checkAllActiveSensors(): OCC Active sensors are available");
286 waitingForAllOccActiveSensors = false;
287 }
288 queuedActiveState.clear();
Chris Cainbae4d072022-02-28 09:46:50 -0600289 tracedSensorWait = false;
290 }
291 else
292 {
293 // Not all sensors were available, so keep waiting
294 if (!tracedSensorWait)
295 {
296 log<level::INFO>(
Chris Cainbd551de2022-04-26 13:41:16 -0500297 "checkAllActiveSensors(): Waiting for OCC Active sensors to become available");
Chris Cainbae4d072022-02-28 09:46:50 -0600298 tracedSensorWait = true;
299 }
Chris Cainf55f91a2022-05-27 13:40:15 -0500300 discoverTimer->restartOnce(10s);
Chris Cainbae4d072022-02-28 09:46:50 -0600301 }
302}
303#endif
304
Matt Spinlerd267cec2021-09-01 14:49:19 -0500305std::vector<int> Manager::findOCCsInDev()
306{
307 std::vector<int> occs;
308 std::regex expr{R"(occ(\d+)$)"};
309
310 for (auto& file : fs::directory_iterator("/dev"))
311 {
312 std::smatch match;
313 std::string path{file.path().string()};
314 if (std::regex_search(path, match, expr))
315 {
316 auto num = std::stoi(match[1].str());
317
318 // /dev numbering starts at 1, ours starts at 0.
319 occs.push_back(num - 1);
320 }
321 }
322
323 return occs;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530324}
325
Patrick Williamsaf408082022-07-22 19:26:54 -0500326int Manager::cpuCreated(sdbusplus::message_t& msg)
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530327{
George Liubcef3b42021-09-10 12:39:02 +0800328 namespace fs = std::filesystem;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530329
330 sdbusplus::message::object_path o;
331 msg.read(o);
332 fs::path cpuPath(std::string(std::move(o)));
333
334 auto name = cpuPath.filename().string();
335 auto index = name.find(CPU_NAME);
336 name.replace(index, std::strlen(CPU_NAME), OCC_NAME);
337
338 createObjects(name);
339
340 return 0;
341}
342
343void Manager::createObjects(const std::string& occ)
344{
345 auto path = fs::path(OCC_CONTROL_ROOT) / occ;
346
Gunnar Mills94df8c92018-09-14 14:50:03 -0500347 statusObjects.emplace_back(std::make_unique<Status>(
George Liuf3b75142021-06-10 11:22:50 +0800348 event, path.c_str(), *this,
Chris Cain36f9cde2021-11-22 11:18:21 -0600349#ifdef POWER10
350 pmode,
351#endif
Gunnar Mills94df8c92018-09-14 14:50:03 -0500352 std::bind(std::mem_fn(&Manager::statusCallBack), this,
Sheldon Bailey373af752022-02-21 15:14:00 -0600353 std::placeholders::_1, std::placeholders::_2)
Tom Joseph00325232020-07-29 17:51:48 +0530354#ifdef PLDM
355 ,
356 std::bind(std::mem_fn(&pldm::Interface::resetOCC), pldmHandle.get(),
357 std::placeholders::_1)
358#endif
359 ));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530360
Chris Cain40501a22022-03-14 17:33:27 -0500361 // Create the power cap monitor object
362 if (!pcap)
363 {
364 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
365 *statusObjects.back());
366 }
367
Chris Cain36f9cde2021-11-22 11:18:21 -0600368 if (statusObjects.back()->isMasterOcc())
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530369 {
Chris Cain36f9cde2021-11-22 11:18:21 -0600370 log<level::INFO>(
Patrick Williams48002492024-02-13 21:43:32 -0600371 std::format("Manager::createObjects(): OCC{} is the master",
Chris Cain36f9cde2021-11-22 11:18:21 -0600372 statusObjects.back()->getOccInstanceID())
373 .c_str());
374 _pollTimer->setEnabled(false);
375
Chris Cain78e86012021-03-04 16:15:31 -0600376#ifdef POWER10
Chris Cain6fa848a2022-01-24 14:54:38 -0600377 // Set the master OCC on the PowerMode object
378 pmode->setMasterOcc(path);
Chris Cain78e86012021-03-04 16:15:31 -0600379#endif
Chris Cain36f9cde2021-11-22 11:18:21 -0600380 }
381
Patrick Williamsd7542c82024-08-16 15:20:28 -0400382 passThroughObjects.emplace_back(std::make_unique<PassThrough>(
383 path.c_str()
Chris Cain36f9cde2021-11-22 11:18:21 -0600384#ifdef POWER10
Patrick Williamsd7542c82024-08-16 15:20:28 -0400385 ,
386 pmode
Chris Cain36f9cde2021-11-22 11:18:21 -0600387#endif
Patrick Williamsd7542c82024-08-16 15:20:28 -0400388 ));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530389}
390
Sheldon Bailey373af752022-02-21 15:14:00 -0600391void Manager::statusCallBack(instanceID instance, bool status)
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530392{
Chris Caina7b74dc2021-11-10 17:03:43 -0600393 if (status == true)
Eddie Jamesdae2d942017-12-20 10:50:03 -0600394 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600395 // OCC went active
396 ++activeCount;
397
398#ifdef POWER10
399 if (activeCount == 1)
Eddie Jamesdae2d942017-12-20 10:50:03 -0600400 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600401 // First OCC went active (allow some time for all OCCs to go active)
Chris Cainbd551de2022-04-26 13:41:16 -0500402 waitForAllOccsTimer->restartOnce(60s);
Matt Spinler53f68142021-08-25 15:47:31 -0500403 }
404#endif
Chris Caina7b74dc2021-11-10 17:03:43 -0600405
406 if (activeCount == statusObjects.size())
407 {
408#ifdef POWER10
409 // All OCCs are now running
410 if (waitForAllOccsTimer->isEnabled())
411 {
412 // stop occ wait timer
413 waitForAllOccsTimer->setEnabled(false);
414 }
415#endif
416
417 // Verify master OCC and start presence monitor
418 validateOccMaster();
419 }
420
421 // Start poll timer if not already started
422 if (!_pollTimer->isEnabled())
423 {
424 log<level::INFO>(
Patrick Williams48002492024-02-13 21:43:32 -0600425 std::format("Manager: OCCs will be polled every {} seconds",
Chris Cain36f9cde2021-11-22 11:18:21 -0600426 pollInterval)
Chris Caina7b74dc2021-11-10 17:03:43 -0600427 .c_str());
428
429 // Send poll and start OCC poll timer
430 pollerTimerExpired();
431 }
432 }
433 else
434 {
435 // OCC went away
Chris Cain082a6ca2023-03-21 10:27:26 -0500436 if (activeCount > 0)
437 {
438 --activeCount;
439 }
440 else
441 {
442 log<level::ERR>(
Patrick Williams48002492024-02-13 21:43:32 -0600443 std::format("OCC{} disabled, but currently no active OCCs",
Chris Cain082a6ca2023-03-21 10:27:26 -0500444 instance)
445 .c_str());
446 }
Chris Caina7b74dc2021-11-10 17:03:43 -0600447
448 if (activeCount == 0)
449 {
450 // No OCCs are running
451
452 // Stop OCC poll timer
453 if (_pollTimer->isEnabled())
454 {
455 log<level::INFO>(
456 "Manager::statusCallBack(): OCCs are not running, stopping poll timer");
457 _pollTimer->setEnabled(false);
458 }
459
460#ifdef POWER10
461 // stop wait timer
462 if (waitForAllOccsTimer->isEnabled())
463 {
464 waitForAllOccsTimer->setEnabled(false);
465 }
466#endif
Chris Caina7b74dc2021-11-10 17:03:43 -0600467 }
Sheldon Bailey373af752022-02-21 15:14:00 -0600468#ifdef READ_OCC_SENSORS
469 // Clear OCC sensors
Sheldon Baileyc8dd4592022-05-12 10:15:14 -0500470 setSensorValueToNaN(instance);
Sheldon Bailey373af752022-02-21 15:14:00 -0600471#endif
Chris Caina8857c52021-01-27 11:53:05 -0600472 }
Chris Cainbae4d072022-02-28 09:46:50 -0600473
474#ifdef POWER10
475 if (waitingForAllOccActiveSensors)
476 {
Chris Cain6d8f37a2022-04-29 13:46:01 -0500477 if (utils::isHostRunning())
478 {
479 checkAllActiveSensors();
480 }
Chris Cainbae4d072022-02-28 09:46:50 -0600481 }
482#endif
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530483}
484
485#ifdef I2C_OCC
486void Manager::initStatusObjects()
487{
488 // Make sure we have a valid path string
489 static_assert(sizeof(DEV_PATH) != 0);
490
491 auto deviceNames = i2c_occ::getOccHwmonDevices(DEV_PATH);
492 for (auto& name : deviceNames)
493 {
494 i2c_occ::i2cToDbus(name);
Lei YUb5259a12017-09-01 16:22:40 +0800495 name = std::string(OCC_NAME) + '_' + name;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530496 auto path = fs::path(OCC_CONTROL_ROOT) / name;
497 statusObjects.emplace_back(
George Liuf3b75142021-06-10 11:22:50 +0800498 std::make_unique<Status>(event, path.c_str(), *this));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530499 }
Chris Cain40501a22022-03-14 17:33:27 -0500500 // The first device is master occ
501 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
502 *statusObjects.front());
Chris Cain78e86012021-03-04 16:15:31 -0600503#ifdef POWER10
Chris Cain5d66a0a2022-02-09 08:52:10 -0600504 pmode = std::make_unique<powermode::PowerMode>(*this, powermode::PMODE_PATH,
505 powermode::PIPS_PATH);
Chris Cain6fa848a2022-01-24 14:54:38 -0600506 // Set the master OCC on the PowerMode object
507 pmode->setMasterOcc(path);
Chris Cain78e86012021-03-04 16:15:31 -0600508#endif
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530509}
510#endif
511
Tom Joseph815f9f52020-07-27 12:12:13 +0530512#ifdef PLDM
Eddie Jamescbad2192021-10-07 09:39:39 -0500513void Manager::sbeTimeout(unsigned int instance)
514{
Eddie James2a751d72022-03-04 09:16:12 -0600515 auto obj = std::find_if(statusObjects.begin(), statusObjects.end(),
516 [instance](const auto& obj) {
Patrick Williamsd7542c82024-08-16 15:20:28 -0400517 return instance == obj->getOccInstanceID();
518 });
Eddie Jamescbad2192021-10-07 09:39:39 -0500519
Eddie Jamescb018da2022-03-05 11:49:37 -0600520 if (obj != statusObjects.end() && (*obj)->occActive())
Eddie James2a751d72022-03-04 09:16:12 -0600521 {
Chris Cainbae4d072022-02-28 09:46:50 -0600522 log<level::INFO>(
Patrick Williams48002492024-02-13 21:43:32 -0600523 std::format("SBE timeout, requesting HRESET (OCC{})", instance)
Chris Cainbae4d072022-02-28 09:46:50 -0600524 .c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500525
Eddie James2a751d72022-03-04 09:16:12 -0600526 setSBEState(instance, SBE_STATE_NOT_USABLE);
527
528 pldmHandle->sendHRESET(instance);
529 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500530}
531
Tom Joseph815f9f52020-07-27 12:12:13 +0530532bool Manager::updateOCCActive(instanceID instance, bool status)
533{
Chris Cain7e374fb2022-04-07 09:47:23 -0500534 auto obj = std::find_if(statusObjects.begin(), statusObjects.end(),
535 [instance](const auto& obj) {
Patrick Williamsd7542c82024-08-16 15:20:28 -0400536 return instance == obj->getOccInstanceID();
537 });
Chris Cain7e374fb2022-04-07 09:47:23 -0500538
Chris Cain082a6ca2023-03-21 10:27:26 -0500539 const bool hostRunning = open_power::occ::utils::isHostRunning();
Chris Cain7e374fb2022-04-07 09:47:23 -0500540 if (obj != statusObjects.end())
541 {
Chris Cain082a6ca2023-03-21 10:27:26 -0500542 if (!hostRunning && (status == true))
543 {
544 log<level::WARNING>(
Patrick Williams48002492024-02-13 21:43:32 -0600545 std::format(
Chris Cain082a6ca2023-03-21 10:27:26 -0500546 "updateOCCActive: Host is not running yet (OCC{} active={}), clearing sensor received",
547 instance, status)
548 .c_str());
549 (*obj)->setPldmSensorReceived(false);
550 if (!waitingForAllOccActiveSensors)
551 {
552 log<level::INFO>(
553 "updateOCCActive: Waiting for Host and all OCC Active Sensors");
554 waitingForAllOccActiveSensors = true;
555 }
Chris Cain755af102024-02-27 16:09:51 -0600556#ifdef POWER10
Chris Cain082a6ca2023-03-21 10:27:26 -0500557 discoverTimer->restartOnce(30s);
Chris Cain755af102024-02-27 16:09:51 -0600558#endif
Chris Cain082a6ca2023-03-21 10:27:26 -0500559 return false;
560 }
561 else
562 {
Chris Cain082a6ca2023-03-21 10:27:26 -0500563 (*obj)->setPldmSensorReceived(true);
564 return (*obj)->occActive(status);
565 }
Chris Cain7e374fb2022-04-07 09:47:23 -0500566 }
567 else
568 {
Chris Cain082a6ca2023-03-21 10:27:26 -0500569 if (hostRunning)
570 {
571 log<level::WARNING>(
Patrick Williams48002492024-02-13 21:43:32 -0600572 std::format(
Chris Cain082a6ca2023-03-21 10:27:26 -0500573 "updateOCCActive: No status object to update for OCC{} (active={})",
574 instance, status)
575 .c_str());
576 }
577 else
578 {
579 if (status == true)
580 {
581 log<level::WARNING>(
Patrick Williams48002492024-02-13 21:43:32 -0600582 std::format(
Chris Cain082a6ca2023-03-21 10:27:26 -0500583 "updateOCCActive: No status objects and Host is not running yet (OCC{} active={})",
584 instance, status)
585 .c_str());
586 }
587 }
Chris Cainbd551de2022-04-26 13:41:16 -0500588 if (status == true)
589 {
590 // OCC went active
591 queuedActiveState.insert(instance);
592 }
593 else
594 {
595 auto match = queuedActiveState.find(instance);
596 if (match != queuedActiveState.end())
597 {
598 // OCC was disabled
599 queuedActiveState.erase(match);
600 }
601 }
Chris Cain7e374fb2022-04-07 09:47:23 -0500602 return false;
603 }
Tom Joseph815f9f52020-07-27 12:12:13 +0530604}
Eddie Jamescbad2192021-10-07 09:39:39 -0500605
Sheldon Bailey31a2f132022-05-20 11:31:52 -0500606// Called upon pldm event To set powermode Safe Mode State for system.
607void Manager::updateOccSafeMode(bool safeMode)
608{
609#ifdef POWER10
610 pmode->updateDbusSafeMode(safeMode);
611#endif
Chris Cainc86d80f2023-05-04 15:49:18 -0500612 // Update the processor throttle status on dbus
613 for (auto& obj : statusObjects)
614 {
615 obj->updateThrottle(safeMode, THROTTLED_SAFE);
616 }
Sheldon Bailey31a2f132022-05-20 11:31:52 -0500617}
618
Eddie Jamescbad2192021-10-07 09:39:39 -0500619void Manager::sbeHRESETResult(instanceID instance, bool success)
620{
621 if (success)
622 {
Chris Cainbae4d072022-02-28 09:46:50 -0600623 log<level::INFO>(
Patrick Williams48002492024-02-13 21:43:32 -0600624 std::format("HRESET succeeded (OCC{})", instance).c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500625
626 setSBEState(instance, SBE_STATE_BOOTED);
627
628 return;
629 }
630
631 setSBEState(instance, SBE_STATE_FAILED);
632
633 if (sbeCanDump(instance))
634 {
Chris Cainbae4d072022-02-28 09:46:50 -0600635 log<level::INFO>(
Patrick Williams48002492024-02-13 21:43:32 -0600636 std::format("HRESET failed (OCC{}), triggering SBE dump", instance)
Chris Cainbae4d072022-02-28 09:46:50 -0600637 .c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500638
639 auto& bus = utils::getBus();
640 uint32_t src6 = instance << 16;
641 uint32_t logId =
642 FFDC::createPEL("org.open_power.Processor.Error.SbeChipOpTimeout",
643 src6, "SBE command timeout");
644
645 try
646 {
George Liuf3a4a692021-12-28 13:59:51 +0800647 constexpr auto interface = "xyz.openbmc_project.Dump.Create";
648 constexpr auto function = "CreateDump";
649
Patrick Williamsd7542c82024-08-16 15:20:28 -0400650 std::string service =
651 utils::getService(OP_DUMP_OBJ_PATH, interface);
Dhruvaraj Subhashchandran1173b2b2024-06-01 11:12:13 -0500652 auto method = bus.new_method_call(service.c_str(), OP_DUMP_OBJ_PATH,
653 interface, function);
Eddie Jamescbad2192021-10-07 09:39:39 -0500654
655 std::map<std::string, std::variant<std::string, uint64_t>>
656 createParams{
657 {"com.ibm.Dump.Create.CreateParameters.ErrorLogId",
658 uint64_t(logId)},
659 {"com.ibm.Dump.Create.CreateParameters.DumpType",
660 "com.ibm.Dump.Create.DumpType.SBE"},
661 {"com.ibm.Dump.Create.CreateParameters.FailingUnitId",
662 uint64_t(instance)},
663 };
664
665 method.append(createParams);
666
667 auto response = bus.call(method);
668 }
Patrick Williamsaf408082022-07-22 19:26:54 -0500669 catch (const sdbusplus::exception_t& e)
Eddie Jamescbad2192021-10-07 09:39:39 -0500670 {
671 constexpr auto ERROR_DUMP_DISABLED =
672 "xyz.openbmc_project.Dump.Create.Error.Disabled";
673 if (e.name() == ERROR_DUMP_DISABLED)
674 {
675 log<level::INFO>("Dump is disabled, skipping");
676 }
677 else
678 {
679 log<level::ERR>("Dump failed");
680 }
681 }
682 }
683}
684
685bool Manager::sbeCanDump(unsigned int instance)
686{
687 struct pdbg_target* proc = getPdbgTarget(instance);
688
689 if (!proc)
690 {
691 // allow the dump in the error case
692 return true;
693 }
694
695 try
696 {
697 if (!openpower::phal::sbe::isDumpAllowed(proc))
698 {
699 return false;
700 }
701
702 if (openpower::phal::pdbg::isSbeVitalAttnActive(proc))
703 {
704 return false;
705 }
706 }
707 catch (openpower::phal::exception::SbeError& e)
708 {
709 log<level::INFO>("Failed to query SBE state");
710 }
711
712 // allow the dump in the error case
713 return true;
714}
715
716void Manager::setSBEState(unsigned int instance, enum sbe_state state)
717{
718 struct pdbg_target* proc = getPdbgTarget(instance);
719
720 if (!proc)
721 {
722 return;
723 }
724
725 try
726 {
727 openpower::phal::sbe::setState(proc, state);
728 }
729 catch (const openpower::phal::exception::SbeError& e)
730 {
Chris Cain358d3962024-08-23 15:29:38 -0500731 log<level::ERR>(
732 std::format("Failed to set SBE state: {}", e.what()).c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500733 }
734}
735
736struct pdbg_target* Manager::getPdbgTarget(unsigned int instance)
737{
738 if (!pdbgInitialized)
739 {
740 try
741 {
742 openpower::phal::pdbg::init();
743 pdbgInitialized = true;
744 }
745 catch (const openpower::phal::exception::PdbgError& e)
746 {
747 log<level::ERR>("pdbg initialization failed");
748 return nullptr;
749 }
750 }
751
752 struct pdbg_target* proc = nullptr;
753 pdbg_for_each_class_target("proc", proc)
754 {
755 if (pdbg_target_index(proc) == instance)
756 {
757 return proc;
758 }
759 }
760
761 log<level::ERR>("Failed to get pdbg target");
762 return nullptr;
763}
Tom Joseph815f9f52020-07-27 12:12:13 +0530764#endif
765
Chris Caina8857c52021-01-27 11:53:05 -0600766void Manager::pollerTimerExpired()
767{
Chris Caina8857c52021-01-27 11:53:05 -0600768 if (!_pollTimer)
769 {
770 log<level::ERR>(
771 "Manager::pollerTimerExpired() ERROR: Timer not defined");
772 return;
773 }
774
775 for (auto& obj : statusObjects)
776 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600777 if (!obj->occActive())
778 {
779 // OCC is not running yet
780#ifdef READ_OCC_SENSORS
Chris Cain5d66a0a2022-02-09 08:52:10 -0600781 auto id = obj->getOccInstanceID();
Sheldon Baileyc8dd4592022-05-12 10:15:14 -0500782 setSensorValueToNaN(id);
Chris Caina7b74dc2021-11-10 17:03:43 -0600783#endif
784 continue;
785 }
786
Chris Caina8857c52021-01-27 11:53:05 -0600787 // Read sysfs to force kernel to poll OCC
788 obj->readOccState();
Chicago Duanbb895cb2021-06-18 19:37:16 +0800789
790#ifdef READ_OCC_SENSORS
791 // Read occ sensor values
Chris Cain5d66a0a2022-02-09 08:52:10 -0600792 getSensorValues(obj);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800793#endif
Chris Caina8857c52021-01-27 11:53:05 -0600794 }
795
Chris Caina7b74dc2021-11-10 17:03:43 -0600796 if (activeCount > 0)
797 {
798 // Restart OCC poll timer
799 _pollTimer->restartOnce(std::chrono::seconds(pollInterval));
800 }
801 else
802 {
803 // No OCCs running, so poll timer will not be restarted
804 log<level::INFO>(
Patrick Williams48002492024-02-13 21:43:32 -0600805 std::format(
Chris Caina7b74dc2021-11-10 17:03:43 -0600806 "Manager::pollerTimerExpired: poll timer will not be restarted")
807 .c_str());
808 }
Chris Caina8857c52021-01-27 11:53:05 -0600809}
810
Chicago Duanbb895cb2021-06-18 19:37:16 +0800811#ifdef READ_OCC_SENSORS
Chris Cainae157b62024-01-23 16:05:12 -0600812void Manager::readTempSensors(const fs::path& path, uint32_t occInstance)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800813{
Matt Spinler818cc8d2023-10-23 11:43:39 -0500814 // There may be more than one sensor with the same FRU type
815 // and label so make two passes: the first to read the temps
816 // from sysfs, and the second to put them on D-Bus after
817 // resolving any conflicts.
818 std::map<std::string, double> sensorData;
819
Chicago Duanbb895cb2021-06-18 19:37:16 +0800820 std::regex expr{"temp\\d+_label$"}; // Example: temp5_label
821 for (auto& file : fs::directory_iterator(path))
822 {
823 if (!std::regex_search(file.path().string(), expr))
824 {
825 continue;
826 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800827
Matt Spinlera26f1522021-08-25 15:50:20 -0500828 uint32_t labelValue{0};
829
830 try
831 {
832 labelValue = readFile<uint32_t>(file.path());
833 }
834 catch (const std::system_error& e)
835 {
836 log<level::DEBUG>(
Patrick Williams48002492024-02-13 21:43:32 -0600837 std::format("readTempSensors: Failed reading {}, errno = {}",
Matt Spinlera26f1522021-08-25 15:50:20 -0500838 file.path().string(), e.code().value())
839 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800840 continue;
841 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800842
843 const std::string& tempLabel = "label";
844 const std::string filePathString = file.path().string().substr(
845 0, file.path().string().length() - tempLabel.length());
Matt Spinlera26f1522021-08-25 15:50:20 -0500846
847 uint32_t fruTypeValue{0};
848 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800849 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500850 fruTypeValue = readFile<uint32_t>(filePathString + fruTypeSuffix);
851 }
852 catch (const std::system_error& e)
853 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800854 log<level::DEBUG>(
Patrick Williams48002492024-02-13 21:43:32 -0600855 std::format("readTempSensors: Failed reading {}, errno = {}",
Matt Spinlera26f1522021-08-25 15:50:20 -0500856 filePathString + fruTypeSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +0800857 .c_str());
858 continue;
859 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800860
Patrick Williamsd7542c82024-08-16 15:20:28 -0400861 std::string sensorPath =
862 OCC_SENSORS_ROOT + std::string("/temperature/");
Chicago Duanbb895cb2021-06-18 19:37:16 +0800863
Matt Spinlerace67d82021-10-18 13:41:57 -0500864 std::string dvfsTempPath;
865
Chicago Duanbb895cb2021-06-18 19:37:16 +0800866 if (fruTypeValue == VRMVdd)
867 {
Patrick Williamsd7542c82024-08-16 15:20:28 -0400868 sensorPath.append(
869 "vrm_vdd" + std::to_string(occInstance) + "_temp");
Chicago Duanbb895cb2021-06-18 19:37:16 +0800870 }
Matt Spinlerace67d82021-10-18 13:41:57 -0500871 else if (fruTypeValue == processorIoRing)
872 {
Patrick Williamsd7542c82024-08-16 15:20:28 -0400873 sensorPath.append(
874 "proc" + std::to_string(occInstance) + "_ioring_temp");
Matt Spinlerace67d82021-10-18 13:41:57 -0500875 dvfsTempPath = std::string{OCC_SENSORS_ROOT} + "/temperature/proc" +
Chris Cainae157b62024-01-23 16:05:12 -0600876 std::to_string(occInstance) + "_ioring_dvfs_temp";
Matt Spinlerace67d82021-10-18 13:41:57 -0500877 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800878 else
879 {
Matt Spinler14d14022021-08-25 15:38:29 -0500880 uint16_t type = (labelValue & 0xFF000000) >> 24;
881 uint16_t instanceID = labelValue & 0x0000FFFF;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800882
883 if (type == OCC_DIMM_TEMP_SENSOR_TYPE)
884 {
Matt Spinler8b8abee2021-08-25 15:18:21 -0500885 if (fruTypeValue == fruTypeNotAvailable)
886 {
887 // Not all DIMM related temps are available to read
888 // (no _input file in this case)
889 continue;
890 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800891 auto iter = dimmTempSensorName.find(fruTypeValue);
892 if (iter == dimmTempSensorName.end())
893 {
George Liub5ca1012021-09-10 12:53:11 +0800894 log<level::ERR>(
Patrick Williams48002492024-02-13 21:43:32 -0600895 std::format(
George Liub5ca1012021-09-10 12:53:11 +0800896 "readTempSensors: Fru type error! fruTypeValue = {}) ",
897 fruTypeValue)
898 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800899 continue;
900 }
901
Patrick Williamsd7542c82024-08-16 15:20:28 -0400902 sensorPath.append(
903 "dimm" + std::to_string(instanceID) + iter->second);
Matt Spinlerad8f4522023-10-25 11:14:46 -0500904
905 dvfsTempPath = std::string{OCC_SENSORS_ROOT} + "/temperature/" +
906 dimmDVFSSensorName.at(fruTypeValue);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800907 }
908 else if (type == OCC_CPU_TEMP_SENSOR_TYPE)
909 {
Matt Spinlerace67d82021-10-18 13:41:57 -0500910 if (fruTypeValue == processorCore)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800911 {
Matt Spinlerace67d82021-10-18 13:41:57 -0500912 // The OCC reports small core temps, of which there are
913 // two per big core. All current P10 systems are in big
914 // core mode, so use a big core name.
915 uint16_t coreNum = instanceID / 2;
916 uint16_t tempNum = instanceID % 2;
Chris Cainae157b62024-01-23 16:05:12 -0600917 sensorPath.append("proc" + std::to_string(occInstance) +
918 "_core" + std::to_string(coreNum) + "_" +
Matt Spinlerace67d82021-10-18 13:41:57 -0500919 std::to_string(tempNum) + "_temp");
920
Chris Cainae157b62024-01-23 16:05:12 -0600921 dvfsTempPath =
922 std::string{OCC_SENSORS_ROOT} + "/temperature/proc" +
923 std::to_string(occInstance) + "_core_dvfs_temp";
Matt Spinlerace67d82021-10-18 13:41:57 -0500924 }
925 else
926 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800927 continue;
928 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800929 }
930 else
931 {
932 continue;
933 }
934 }
935
Matt Spinlerace67d82021-10-18 13:41:57 -0500936 // The dvfs temp file only needs to be read once per chip per type.
937 if (!dvfsTempPath.empty() &&
938 !dbus::OccDBusSensors::getOccDBus().hasDvfsTemp(dvfsTempPath))
939 {
940 try
941 {
942 auto dvfsValue = readFile<double>(filePathString + maxSuffix);
943
944 dbus::OccDBusSensors::getOccDBus().setDvfsTemp(
945 dvfsTempPath, dvfsValue * std::pow(10, -3));
946 }
947 catch (const std::system_error& e)
948 {
949 log<level::DEBUG>(
Patrick Williams48002492024-02-13 21:43:32 -0600950 std::format(
Matt Spinlerace67d82021-10-18 13:41:57 -0500951 "readTempSensors: Failed reading {}, errno = {}",
952 filePathString + maxSuffix, e.code().value())
953 .c_str());
954 }
955 }
956
Matt Spinlera26f1522021-08-25 15:50:20 -0500957 uint32_t faultValue{0};
958 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800959 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500960 faultValue = readFile<uint32_t>(filePathString + faultSuffix);
961 }
962 catch (const std::system_error& e)
963 {
964 log<level::DEBUG>(
Patrick Williams48002492024-02-13 21:43:32 -0600965 std::format("readTempSensors: Failed reading {}, errno = {}",
Matt Spinlera26f1522021-08-25 15:50:20 -0500966 filePathString + faultSuffix, e.code().value())
967 .c_str());
968 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800969 }
970
Chris Cainae157b62024-01-23 16:05:12 -0600971 double tempValue{0};
972 // NOTE: if OCC sends back 0xFF, kernal sets this fault value to 1.
Matt Spinlera26f1522021-08-25 15:50:20 -0500973 if (faultValue != 0)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800974 {
Chris Cainae157b62024-01-23 16:05:12 -0600975 tempValue = std::numeric_limits<double>::quiet_NaN();
Chicago Duanbb895cb2021-06-18 19:37:16 +0800976 }
Chris Cainae157b62024-01-23 16:05:12 -0600977 else
Chicago Duanbb895cb2021-06-18 19:37:16 +0800978 {
Chris Cainae157b62024-01-23 16:05:12 -0600979 // Read the temperature
980 try
Sheldon Baileycd0940b2022-04-26 14:24:05 -0500981 {
Chris Cainae157b62024-01-23 16:05:12 -0600982 tempValue = readFile<double>(filePathString + inputSuffix);
Sheldon Baileycd0940b2022-04-26 14:24:05 -0500983 }
Chris Cainae157b62024-01-23 16:05:12 -0600984 catch (const std::system_error& e)
Sheldon Baileycd0940b2022-04-26 14:24:05 -0500985 {
Chris Cainae157b62024-01-23 16:05:12 -0600986 log<level::DEBUG>(
Patrick Williams48002492024-02-13 21:43:32 -0600987 std::format(
Chris Cainae157b62024-01-23 16:05:12 -0600988 "readTempSensors: Failed reading {}, errno = {}",
989 filePathString + inputSuffix, e.code().value())
990 .c_str());
991
992 // if errno == EAGAIN(Resource temporarily unavailable) then set
993 // temp to 0, to avoid using old temp, and affecting FAN
994 // Control.
995 if (e.code().value() == EAGAIN)
996 {
997 tempValue = 0;
998 }
999 // else the errno would be something like
1000 // EBADF(Bad file descriptor)
1001 // or ENOENT(No such file or directory)
1002 else
1003 {
1004 continue;
1005 }
Sheldon Baileycd0940b2022-04-26 14:24:05 -05001006 }
Matt Spinlera26f1522021-08-25 15:50:20 -05001007 }
1008
Matt Spinler818cc8d2023-10-23 11:43:39 -05001009 // If this object path already has a value, only overwite
1010 // it if the previous one was an NaN or a smaller value.
1011 auto existing = sensorData.find(sensorPath);
1012 if (existing != sensorData.end())
1013 {
Chris Cainae157b62024-01-23 16:05:12 -06001014 // Multiple sensors found for this FRU type
1015 if ((std::isnan(existing->second) && (tempValue == 0)) ||
1016 ((existing->second == 0) && std::isnan(tempValue)))
1017 {
1018 // One of the redundant sensors has failed (0xFF/nan), and the
1019 // other sensor has no reading (0), so set the FRU to NaN to
1020 // force fan increase
1021 tempValue = std::numeric_limits<double>::quiet_NaN();
1022 existing->second = tempValue;
1023 }
Matt Spinler818cc8d2023-10-23 11:43:39 -05001024 if (std::isnan(existing->second) || (tempValue > existing->second))
1025 {
1026 existing->second = tempValue;
1027 }
1028 }
1029 else
1030 {
Chris Cainae157b62024-01-23 16:05:12 -06001031 // First sensor for this FRU type
Matt Spinler818cc8d2023-10-23 11:43:39 -05001032 sensorData[sensorPath] = tempValue;
1033 }
1034 }
Matt Spinlera26f1522021-08-25 15:50:20 -05001035
Matt Spinler818cc8d2023-10-23 11:43:39 -05001036 // Now publish the values on D-Bus.
1037 for (const auto& [objectPath, value] : sensorData)
1038 {
1039 dbus::OccDBusSensors::getOccDBus().setValue(objectPath,
1040 value * std::pow(10, -3));
Matt Spinlera26f1522021-08-25 15:50:20 -05001041
Matt Spinler818cc8d2023-10-23 11:43:39 -05001042 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(
1043 objectPath, !std::isnan(value));
1044
1045 if (existingSensors.find(objectPath) == existingSensors.end())
Chris Cain6fa848a2022-01-24 14:54:38 -06001046 {
Chris Cain5d66a0a2022-02-09 08:52:10 -06001047 dbus::OccDBusSensors::getOccDBus().setChassisAssociation(
Matt Spinler818cc8d2023-10-23 11:43:39 -05001048 objectPath);
Chris Cain6fa848a2022-01-24 14:54:38 -06001049 }
1050
Chris Cainae157b62024-01-23 16:05:12 -06001051 existingSensors[objectPath] = occInstance;
Chicago Duanbb895cb2021-06-18 19:37:16 +08001052 }
Chicago Duanbb895cb2021-06-18 19:37:16 +08001053}
1054
1055std::optional<std::string>
1056 Manager::getPowerLabelFunctionID(const std::string& value)
1057{
1058 // If the value is "system", then the FunctionID is "system".
1059 if (value == "system")
1060 {
1061 return value;
1062 }
1063
1064 // If the value is not "system", then the label value have 3 numbers, of
1065 // which we only care about the middle one:
1066 // <sensor id>_<function id>_<apss channel>
1067 // eg: The value is "0_10_5" , then the FunctionID is "10".
1068 if (value.find("_") == std::string::npos)
1069 {
1070 return std::nullopt;
1071 }
1072
1073 auto powerLabelValue = value.substr((value.find("_") + 1));
1074
1075 if (powerLabelValue.find("_") == std::string::npos)
1076 {
1077 return std::nullopt;
1078 }
1079
1080 return powerLabelValue.substr(0, powerLabelValue.find("_"));
1081}
1082
1083void Manager::readPowerSensors(const fs::path& path, uint32_t id)
1084{
Chicago Duanbb895cb2021-06-18 19:37:16 +08001085 std::regex expr{"power\\d+_label$"}; // Example: power5_label
1086 for (auto& file : fs::directory_iterator(path))
1087 {
1088 if (!std::regex_search(file.path().string(), expr))
1089 {
1090 continue;
1091 }
Chicago Duanbb895cb2021-06-18 19:37:16 +08001092
Matt Spinlera26f1522021-08-25 15:50:20 -05001093 std::string labelValue;
1094 try
1095 {
1096 labelValue = readFile<std::string>(file.path());
1097 }
1098 catch (const std::system_error& e)
1099 {
1100 log<level::DEBUG>(
Patrick Williams48002492024-02-13 21:43:32 -06001101 std::format("readPowerSensors: Failed reading {}, errno = {}",
Matt Spinlera26f1522021-08-25 15:50:20 -05001102 file.path().string(), e.code().value())
1103 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +08001104 continue;
1105 }
Chicago Duanbb895cb2021-06-18 19:37:16 +08001106
1107 auto functionID = getPowerLabelFunctionID(labelValue);
1108 if (functionID == std::nullopt)
1109 {
1110 continue;
1111 }
1112
1113 const std::string& tempLabel = "label";
1114 const std::string filePathString = file.path().string().substr(
1115 0, file.path().string().length() - tempLabel.length());
1116
1117 std::string sensorPath = OCC_SENSORS_ROOT + std::string("/power/");
1118
1119 auto iter = powerSensorName.find(*functionID);
1120 if (iter == powerSensorName.end())
1121 {
1122 continue;
1123 }
1124 sensorPath.append(iter->second);
1125
Matt Spinlera26f1522021-08-25 15:50:20 -05001126 double tempValue{0};
1127
1128 try
Chicago Duanbb895cb2021-06-18 19:37:16 +08001129 {
Matt Spinlera26f1522021-08-25 15:50:20 -05001130 tempValue = readFile<double>(filePathString + inputSuffix);
Chicago Duanbb895cb2021-06-18 19:37:16 +08001131 }
Matt Spinlera26f1522021-08-25 15:50:20 -05001132 catch (const std::system_error& e)
Chicago Duanbb895cb2021-06-18 19:37:16 +08001133 {
Chicago Duanbb895cb2021-06-18 19:37:16 +08001134 log<level::DEBUG>(
Patrick Williams48002492024-02-13 21:43:32 -06001135 std::format("readPowerSensors: Failed reading {}, errno = {}",
Matt Spinlera26f1522021-08-25 15:50:20 -05001136 filePathString + inputSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +08001137 .c_str());
Matt Spinlera26f1522021-08-25 15:50:20 -05001138 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +08001139 }
Matt Spinlera26f1522021-08-25 15:50:20 -05001140
Chris Cain5d66a0a2022-02-09 08:52:10 -06001141 dbus::OccDBusSensors::getOccDBus().setUnit(
Chris Caind84a8332022-01-13 08:58:45 -06001142 sensorPath, "xyz.openbmc_project.Sensor.Value.Unit.Watts");
1143
Chris Cain5d66a0a2022-02-09 08:52:10 -06001144 dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -05001145 sensorPath, tempValue * std::pow(10, -3) * std::pow(10, -3));
1146
Patrick Williamsd7542c82024-08-16 15:20:28 -04001147 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(
1148 sensorPath, true);
Matt Spinlera26f1522021-08-25 15:50:20 -05001149
Matt Spinler5901abd2021-09-23 13:50:03 -05001150 if (existingSensors.find(sensorPath) == existingSensors.end())
1151 {
Chris Cain5d66a0a2022-02-09 08:52:10 -06001152 dbus::OccDBusSensors::getOccDBus().setChassisAssociation(
1153 sensorPath);
Matt Spinler5901abd2021-09-23 13:50:03 -05001154 }
1155
Matt Spinlera26f1522021-08-25 15:50:20 -05001156 existingSensors[sensorPath] = id;
Chicago Duanbb895cb2021-06-18 19:37:16 +08001157 }
1158 return;
1159}
1160
Sheldon Baileyc8dd4592022-05-12 10:15:14 -05001161void Manager::setSensorValueToNaN(uint32_t id) const
Chicago Duanbb895cb2021-06-18 19:37:16 +08001162{
1163 for (const auto& [sensorPath, occId] : existingSensors)
1164 {
1165 if (occId == id)
1166 {
Chris Cain5d66a0a2022-02-09 08:52:10 -06001167 dbus::OccDBusSensors::getOccDBus().setValue(
Chicago Duanbb895cb2021-06-18 19:37:16 +08001168 sensorPath, std::numeric_limits<double>::quiet_NaN());
Sheldon Baileyc8dd4592022-05-12 10:15:14 -05001169
Patrick Williamsd7542c82024-08-16 15:20:28 -04001170 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(
1171 sensorPath, true);
Chicago Duanbb895cb2021-06-18 19:37:16 +08001172 }
1173 }
1174 return;
1175}
1176
Sheldon Bailey373af752022-02-21 15:14:00 -06001177void Manager::setSensorValueToNonFunctional(uint32_t id) const
1178{
1179 for (const auto& [sensorPath, occId] : existingSensors)
1180 {
1181 if (occId == id)
1182 {
1183 dbus::OccDBusSensors::getOccDBus().setValue(
1184 sensorPath, std::numeric_limits<double>::quiet_NaN());
1185
Patrick Williamsd7542c82024-08-16 15:20:28 -04001186 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(
1187 sensorPath, false);
Sheldon Bailey373af752022-02-21 15:14:00 -06001188 }
1189 }
1190 return;
1191}
1192
Chris Cain5d66a0a2022-02-09 08:52:10 -06001193void Manager::getSensorValues(std::unique_ptr<Status>& occ)
Chicago Duanbb895cb2021-06-18 19:37:16 +08001194{
Chris Caine2d0a432022-03-28 11:08:49 -05001195 static bool tracedError[8] = {0};
1196 const fs::path sensorPath = occ->getHwmonPath();
Chris Cain5d66a0a2022-02-09 08:52:10 -06001197 const uint32_t id = occ->getOccInstanceID();
Chicago Duanbb895cb2021-06-18 19:37:16 +08001198
Chris Caine2d0a432022-03-28 11:08:49 -05001199 if (fs::exists(sensorPath))
Chicago Duanbb895cb2021-06-18 19:37:16 +08001200 {
Chris Caine2d0a432022-03-28 11:08:49 -05001201 // Read temperature sensors
1202 readTempSensors(sensorPath, id);
1203
1204 if (occ->isMasterOcc())
1205 {
1206 // Read power sensors
1207 readPowerSensors(sensorPath, id);
1208 }
1209 tracedError[id] = false;
1210 }
1211 else
1212 {
1213 if (!tracedError[id])
1214 {
1215 log<level::ERR>(
Patrick Williams48002492024-02-13 21:43:32 -06001216 std::format(
Chris Caine2d0a432022-03-28 11:08:49 -05001217 "Manager::getSensorValues: OCC{} sensor path missing: {}",
1218 id, sensorPath.c_str())
1219 .c_str());
1220 tracedError[id] = true;
1221 }
Chicago Duanbb895cb2021-06-18 19:37:16 +08001222 }
1223
1224 return;
1225}
1226#endif
Chris Cain17257672021-10-22 13:41:03 -05001227
1228// Read the altitude from DBus
1229void Manager::readAltitude()
1230{
1231 static bool traceAltitudeErr = true;
1232
1233 utils::PropertyValue altitudeProperty{};
1234 try
1235 {
1236 altitudeProperty = utils::getProperty(ALTITUDE_PATH, ALTITUDE_INTERFACE,
1237 ALTITUDE_PROP);
1238 auto sensorVal = std::get<double>(altitudeProperty);
1239 if (sensorVal < 0xFFFF)
1240 {
1241 if (sensorVal < 0)
1242 {
1243 altitude = 0;
1244 }
1245 else
1246 {
1247 // Round to nearest meter
1248 altitude = uint16_t(sensorVal + 0.5);
1249 }
Patrick Williams48002492024-02-13 21:43:32 -06001250 log<level::DEBUG>(std::format("readAltitude: sensor={} ({}m)",
Chris Cain17257672021-10-22 13:41:03 -05001251 sensorVal, altitude)
1252 .c_str());
1253 traceAltitudeErr = true;
1254 }
1255 else
1256 {
1257 if (traceAltitudeErr)
1258 {
1259 traceAltitudeErr = false;
1260 log<level::DEBUG>(
Patrick Williams48002492024-02-13 21:43:32 -06001261 std::format("Invalid altitude value: {}", sensorVal)
Chris Cain17257672021-10-22 13:41:03 -05001262 .c_str());
1263 }
1264 }
1265 }
Patrick Williamsaf408082022-07-22 19:26:54 -05001266 catch (const sdbusplus::exception_t& e)
Chris Cain17257672021-10-22 13:41:03 -05001267 {
1268 if (traceAltitudeErr)
1269 {
1270 traceAltitudeErr = false;
1271 log<level::INFO>(
Patrick Williams48002492024-02-13 21:43:32 -06001272 std::format("Unable to read Altitude: {}", e.what()).c_str());
Chris Cain17257672021-10-22 13:41:03 -05001273 }
1274 altitude = 0xFFFF; // not available
1275 }
1276}
1277
1278// Callback function when ambient temperature changes
Patrick Williamsaf408082022-07-22 19:26:54 -05001279void Manager::ambientCallback(sdbusplus::message_t& msg)
Chris Cain17257672021-10-22 13:41:03 -05001280{
1281 double currentTemp = 0;
1282 uint8_t truncatedTemp = 0xFF;
1283 std::string msgSensor;
1284 std::map<std::string, std::variant<double>> msgData;
1285 msg.read(msgSensor, msgData);
1286
1287 auto valPropMap = msgData.find(AMBIENT_PROP);
1288 if (valPropMap == msgData.end())
1289 {
1290 log<level::DEBUG>("ambientCallback: Unknown ambient property changed");
1291 return;
1292 }
1293 currentTemp = std::get<double>(valPropMap->second);
1294 if (std::isnan(currentTemp))
1295 {
1296 truncatedTemp = 0xFF;
1297 }
1298 else
1299 {
1300 if (currentTemp < 0)
1301 {
1302 truncatedTemp = 0;
1303 }
1304 else
1305 {
1306 // Round to nearest degree C
1307 truncatedTemp = uint8_t(currentTemp + 0.5);
1308 }
1309 }
1310
1311 // If ambient changes, notify OCCs
1312 if (truncatedTemp != ambient)
1313 {
1314 log<level::DEBUG>(
Patrick Williams48002492024-02-13 21:43:32 -06001315 std::format("ambientCallback: Ambient change from {} to {}C",
Chris Cain17257672021-10-22 13:41:03 -05001316 ambient, currentTemp)
1317 .c_str());
1318
1319 ambient = truncatedTemp;
1320 if (altitude == 0xFFFF)
1321 {
1322 // No altitude yet, try reading again
1323 readAltitude();
1324 }
1325
1326 log<level::DEBUG>(
Patrick Williams48002492024-02-13 21:43:32 -06001327 std::format("ambientCallback: Ambient: {}C, altitude: {}m", ambient,
Chris Cain17257672021-10-22 13:41:03 -05001328 altitude)
1329 .c_str());
1330#ifdef POWER10
1331 // Send ambient and altitude to all OCCs
1332 for (auto& obj : statusObjects)
1333 {
1334 if (obj->occActive())
1335 {
1336 obj->sendAmbient(ambient, altitude);
1337 }
1338 }
1339#endif // POWER10
1340 }
1341}
1342
1343// return the current ambient and altitude readings
1344void Manager::getAmbientData(bool& ambientValid, uint8_t& ambientTemp,
1345 uint16_t& altitudeValue) const
1346{
1347 ambientValid = true;
1348 ambientTemp = ambient;
1349 altitudeValue = altitude;
1350
1351 if (ambient == 0xFF)
1352 {
1353 ambientValid = false;
1354 }
1355}
1356
Chris Caina7b74dc2021-11-10 17:03:43 -06001357#ifdef POWER10
Chris Cain7f89e4d2022-05-09 13:27:45 -05001358// Called when waitForAllOccsTimer expires
1359// After the first OCC goes active, this timer will be started (60 seconds)
Chris Caina7b74dc2021-11-10 17:03:43 -06001360void Manager::occsNotAllRunning()
1361{
Chris Caina7b74dc2021-11-10 17:03:43 -06001362 if (activeCount != statusObjects.size())
1363 {
1364 // Not all OCCs went active
1365 log<level::WARNING>(
Patrick Williams48002492024-02-13 21:43:32 -06001366 std::format(
Chris Caina7b74dc2021-11-10 17:03:43 -06001367 "occsNotAllRunning: Active OCC count ({}) does not match expected count ({})",
1368 activeCount, statusObjects.size())
1369 .c_str());
Chris Cain7f89e4d2022-05-09 13:27:45 -05001370 // Procs may be garded, so may be expected
Chris Caina7b74dc2021-11-10 17:03:43 -06001371 }
1372
1373 validateOccMaster();
1374}
Chris Cain755af102024-02-27 16:09:51 -06001375
1376#ifdef PLDM
Chris Cainc33171b2024-05-24 16:14:50 -05001377// Called when throttlePldmTraceTimer expires.
Chris Caina19bd422024-05-24 16:39:01 -05001378// If this timer expires, that indicates there are no OCC active sensor PDRs
Chris Cainc33171b2024-05-24 16:14:50 -05001379// found which will trigger pldm traces to be throttled.
1380// The second time this timer expires, a PEL will get created.
1381void Manager::throttlePldmTraceExpired()
Chris Cain755af102024-02-27 16:09:51 -06001382{
Chris Cain7651c062024-05-02 14:14:06 -05001383 if (utils::isHostRunning())
1384 {
Chris Cainc33171b2024-05-24 16:14:50 -05001385 if (!onPldmTimeoutCreatePel)
1386 {
1387 // Throttle traces
1388 pldmHandle->setTraceThrottle(true);
1389 // Restart timer to log a PEL when timer expires
1390 onPldmTimeoutCreatePel = true;
1391 throttlePldmTraceTimer->restartOnce(40min);
1392 }
1393 else
1394 {
1395 log<level::ERR>(
1396 "throttlePldmTraceExpired(): OCC active sensors still not available!");
1397 // Create PEL
1398 createPldmSensorPEL();
1399 }
Chris Cain7651c062024-05-02 14:14:06 -05001400 }
1401 else
1402 {
1403 // Make sure traces are not throttled
1404 pldmHandle->setTraceThrottle(false);
1405 log<level::INFO>(
Chris Cainc33171b2024-05-24 16:14:50 -05001406 "throttlePldmTraceExpired(): host it not running ignoring sensor timer");
Chris Cain7651c062024-05-02 14:14:06 -05001407 }
Chris Cain4b82f3e2024-04-22 14:44:29 -05001408}
1409
1410void Manager::createPldmSensorPEL()
1411{
1412 Error::Descriptor d = Error::Descriptor(MISSING_OCC_SENSORS_PATH);
1413 std::map<std::string, std::string> additionalData;
1414
1415 additionalData.emplace("_PID", std::to_string(getpid()));
1416
1417 log<level::INFO>(
1418 std::format(
1419 "createPldmSensorPEL(): Unable to find PLDM sensors for the OCCs")
1420 .c_str());
1421
1422 auto& bus = utils::getBus();
1423
1424 try
1425 {
1426 FFDCFiles ffdc;
1427 // Add occ-control journal traces to PEL FFDC
1428 auto occJournalFile =
1429 FFDC::addJournalEntries(ffdc, "openpower-occ-control", 40);
1430
1431 static constexpr auto loggingObjectPath =
1432 "/xyz/openbmc_project/logging";
1433 static constexpr auto opLoggingInterface = "org.open_power.Logging.PEL";
Patrick Williamsd7542c82024-08-16 15:20:28 -04001434 std::string service =
1435 utils::getService(loggingObjectPath, opLoggingInterface);
1436 auto method =
1437 bus.new_method_call(service.c_str(), loggingObjectPath,
1438 opLoggingInterface, "CreatePELWithFFDCFiles");
Chris Cain4b82f3e2024-04-22 14:44:29 -05001439
Chris Cain1c3349e2024-04-24 14:14:11 -05001440 // Set level to Warning (Predictive).
Chris Cain4b82f3e2024-04-22 14:44:29 -05001441 auto level =
1442 sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage(
1443 sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level::
Chris Cain1c3349e2024-04-24 14:14:11 -05001444 Warning);
Chris Cain4b82f3e2024-04-22 14:44:29 -05001445
1446 method.append(d.path, level, additionalData, ffdc);
1447 bus.call(method);
1448 }
1449 catch (const sdbusplus::exception_t& e)
1450 {
1451 log<level::ERR>(
1452 std::format("Failed to create MISSING_OCC_SENSORS PEL: {}",
1453 e.what())
1454 .c_str());
1455 }
Chris Cain755af102024-02-27 16:09:51 -06001456}
1457#endif // PLDM
Chris Caina7b74dc2021-11-10 17:03:43 -06001458#endif // POWER10
1459
1460// Verify single master OCC and start presence monitor
1461void Manager::validateOccMaster()
1462{
1463 int masterInstance = -1;
1464 for (auto& obj : statusObjects)
1465 {
Chris Cainbd551de2022-04-26 13:41:16 -05001466 auto instance = obj->getOccInstanceID();
Chris Cainbae4d072022-02-28 09:46:50 -06001467#ifdef POWER10
1468 if (!obj->occActive())
1469 {
1470 if (utils::isHostRunning())
1471 {
Chris Cainbd551de2022-04-26 13:41:16 -05001472 // Check if sensor was queued while waiting for discovery
1473 auto match = queuedActiveState.find(instance);
1474 if (match != queuedActiveState.end())
Chris Cainbae4d072022-02-28 09:46:50 -06001475 {
Chris Cain7f89e4d2022-05-09 13:27:45 -05001476 queuedActiveState.erase(match);
Chris Cainbae4d072022-02-28 09:46:50 -06001477 log<level::INFO>(
Patrick Williams48002492024-02-13 21:43:32 -06001478 std::format(
Chris Cainbd551de2022-04-26 13:41:16 -05001479 "validateOccMaster: OCC{} is ACTIVE (queued)",
1480 instance)
Chris Cainbae4d072022-02-28 09:46:50 -06001481 .c_str());
Chris Cainbd551de2022-04-26 13:41:16 -05001482 obj->occActive(true);
1483 }
1484 else
1485 {
1486 // OCC does not appear to be active yet, check active sensor
Patrick Williamsfb0a5c32024-02-28 11:27:00 -06001487#ifdef PLDM
Chris Cainbd551de2022-04-26 13:41:16 -05001488 pldmHandle->checkActiveSensor(instance);
Patrick Williamsfb0a5c32024-02-28 11:27:00 -06001489#endif
Chris Cainbd551de2022-04-26 13:41:16 -05001490 if (obj->occActive())
1491 {
1492 log<level::INFO>(
Patrick Williams48002492024-02-13 21:43:32 -06001493 std::format(
Chris Cainbd551de2022-04-26 13:41:16 -05001494 "validateOccMaster: OCC{} is ACTIVE after reading sensor",
1495 instance)
1496 .c_str());
1497 }
Chris Cainbae4d072022-02-28 09:46:50 -06001498 }
1499 }
1500 else
1501 {
1502 log<level::WARNING>(
Patrick Williams48002492024-02-13 21:43:32 -06001503 std::format(
Chris Cainbae4d072022-02-28 09:46:50 -06001504 "validateOccMaster: HOST is not running (OCC{})",
Chris Cainbd551de2022-04-26 13:41:16 -05001505 instance)
Chris Cainbae4d072022-02-28 09:46:50 -06001506 .c_str());
1507 return;
1508 }
1509 }
1510#endif // POWER10
1511
Chris Caina7b74dc2021-11-10 17:03:43 -06001512 if (obj->isMasterOcc())
1513 {
Chris Cain5d66a0a2022-02-09 08:52:10 -06001514 obj->addPresenceWatchMaster();
1515
Chris Caina7b74dc2021-11-10 17:03:43 -06001516 if (masterInstance == -1)
1517 {
Chris Cainbd551de2022-04-26 13:41:16 -05001518 masterInstance = instance;
Chris Caina7b74dc2021-11-10 17:03:43 -06001519 }
1520 else
1521 {
1522 log<level::ERR>(
Patrick Williams48002492024-02-13 21:43:32 -06001523 std::format(
Chris Caina7b74dc2021-11-10 17:03:43 -06001524 "validateOccMaster: Multiple OCC masters! ({} and {})",
Chris Cainbd551de2022-04-26 13:41:16 -05001525 masterInstance, instance)
Chris Caina7b74dc2021-11-10 17:03:43 -06001526 .c_str());
1527 // request reset
Eddie James9789e712022-05-25 15:43:40 -05001528 obj->deviceError(Error::Descriptor(PRESENCE_ERROR_PATH));
Chris Caina7b74dc2021-11-10 17:03:43 -06001529 }
1530 }
1531 }
Chris Cainbae4d072022-02-28 09:46:50 -06001532
Chris Caina7b74dc2021-11-10 17:03:43 -06001533 if (masterInstance < 0)
1534 {
Chris Cainbae4d072022-02-28 09:46:50 -06001535 log<level::ERR>(
Patrick Williams48002492024-02-13 21:43:32 -06001536 std::format("validateOccMaster: Master OCC not found! (of {} OCCs)",
Chris Cainbae4d072022-02-28 09:46:50 -06001537 statusObjects.size())
1538 .c_str());
Chris Caina7b74dc2021-11-10 17:03:43 -06001539 // request reset
Eddie James9789e712022-05-25 15:43:40 -05001540 statusObjects.front()->deviceError(
1541 Error::Descriptor(PRESENCE_ERROR_PATH));
Chris Caina7b74dc2021-11-10 17:03:43 -06001542 }
1543 else
1544 {
1545 log<level::INFO>(
Patrick Williams48002492024-02-13 21:43:32 -06001546 std::format("validateOccMaster: OCC{} is master of {} OCCs",
Chris Cain36f9cde2021-11-22 11:18:21 -06001547 masterInstance, activeCount)
Chris Caina7b74dc2021-11-10 17:03:43 -06001548 .c_str());
Sheldon Bailey31a2f132022-05-20 11:31:52 -05001549#ifdef POWER10
1550 pmode->updateDbusSafeMode(false);
1551#endif
Chris Caina7b74dc2021-11-10 17:03:43 -06001552 }
1553}
1554
Chris Cain40501a22022-03-14 17:33:27 -05001555void Manager::updatePcapBounds() const
1556{
1557 if (pcap)
1558 {
1559 pcap->updatePcapBounds();
1560 }
1561}
1562
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +05301563} // namespace occ
1564} // namespace open_power