blob: 932b05257e85caca315a4a7f6333849b7525ae4c [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 {
Patrick Williams48002492024-02-13 21:43:32 -0600563 log<level::INFO>(std::format("updateOCCActive: OCC{} active={}",
Chris Cain082a6ca2023-03-21 10:27:26 -0500564 instance, status)
565 .c_str());
566 (*obj)->setPldmSensorReceived(true);
567 return (*obj)->occActive(status);
568 }
Chris Cain7e374fb2022-04-07 09:47:23 -0500569 }
570 else
571 {
Chris Cain082a6ca2023-03-21 10:27:26 -0500572 if (hostRunning)
573 {
574 log<level::WARNING>(
Patrick Williams48002492024-02-13 21:43:32 -0600575 std::format(
Chris Cain082a6ca2023-03-21 10:27:26 -0500576 "updateOCCActive: No status object to update for OCC{} (active={})",
577 instance, status)
578 .c_str());
579 }
580 else
581 {
582 if (status == true)
583 {
584 log<level::WARNING>(
Patrick Williams48002492024-02-13 21:43:32 -0600585 std::format(
Chris Cain082a6ca2023-03-21 10:27:26 -0500586 "updateOCCActive: No status objects and Host is not running yet (OCC{} active={})",
587 instance, status)
588 .c_str());
589 }
590 }
Chris Cainbd551de2022-04-26 13:41:16 -0500591 if (status == true)
592 {
593 // OCC went active
594 queuedActiveState.insert(instance);
595 }
596 else
597 {
598 auto match = queuedActiveState.find(instance);
599 if (match != queuedActiveState.end())
600 {
601 // OCC was disabled
602 queuedActiveState.erase(match);
603 }
604 }
Chris Cain7e374fb2022-04-07 09:47:23 -0500605 return false;
606 }
Tom Joseph815f9f52020-07-27 12:12:13 +0530607}
Eddie Jamescbad2192021-10-07 09:39:39 -0500608
Sheldon Bailey31a2f132022-05-20 11:31:52 -0500609// Called upon pldm event To set powermode Safe Mode State for system.
610void Manager::updateOccSafeMode(bool safeMode)
611{
612#ifdef POWER10
613 pmode->updateDbusSafeMode(safeMode);
614#endif
Chris Cainc86d80f2023-05-04 15:49:18 -0500615 // Update the processor throttle status on dbus
616 for (auto& obj : statusObjects)
617 {
618 obj->updateThrottle(safeMode, THROTTLED_SAFE);
619 }
Sheldon Bailey31a2f132022-05-20 11:31:52 -0500620}
621
Eddie Jamescbad2192021-10-07 09:39:39 -0500622void Manager::sbeHRESETResult(instanceID instance, bool success)
623{
624 if (success)
625 {
Chris Cainbae4d072022-02-28 09:46:50 -0600626 log<level::INFO>(
Patrick Williams48002492024-02-13 21:43:32 -0600627 std::format("HRESET succeeded (OCC{})", instance).c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500628
629 setSBEState(instance, SBE_STATE_BOOTED);
630
631 return;
632 }
633
634 setSBEState(instance, SBE_STATE_FAILED);
635
636 if (sbeCanDump(instance))
637 {
Chris Cainbae4d072022-02-28 09:46:50 -0600638 log<level::INFO>(
Patrick Williams48002492024-02-13 21:43:32 -0600639 std::format("HRESET failed (OCC{}), triggering SBE dump", instance)
Chris Cainbae4d072022-02-28 09:46:50 -0600640 .c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500641
642 auto& bus = utils::getBus();
643 uint32_t src6 = instance << 16;
644 uint32_t logId =
645 FFDC::createPEL("org.open_power.Processor.Error.SbeChipOpTimeout",
646 src6, "SBE command timeout");
647
648 try
649 {
George Liuf3a4a692021-12-28 13:59:51 +0800650 constexpr auto interface = "xyz.openbmc_project.Dump.Create";
651 constexpr auto function = "CreateDump";
652
Patrick Williamsd7542c82024-08-16 15:20:28 -0400653 std::string service =
654 utils::getService(OP_DUMP_OBJ_PATH, interface);
Dhruvaraj Subhashchandran1173b2b2024-06-01 11:12:13 -0500655 auto method = bus.new_method_call(service.c_str(), OP_DUMP_OBJ_PATH,
656 interface, function);
Eddie Jamescbad2192021-10-07 09:39:39 -0500657
658 std::map<std::string, std::variant<std::string, uint64_t>>
659 createParams{
660 {"com.ibm.Dump.Create.CreateParameters.ErrorLogId",
661 uint64_t(logId)},
662 {"com.ibm.Dump.Create.CreateParameters.DumpType",
663 "com.ibm.Dump.Create.DumpType.SBE"},
664 {"com.ibm.Dump.Create.CreateParameters.FailingUnitId",
665 uint64_t(instance)},
666 };
667
668 method.append(createParams);
669
670 auto response = bus.call(method);
671 }
Patrick Williamsaf408082022-07-22 19:26:54 -0500672 catch (const sdbusplus::exception_t& e)
Eddie Jamescbad2192021-10-07 09:39:39 -0500673 {
674 constexpr auto ERROR_DUMP_DISABLED =
675 "xyz.openbmc_project.Dump.Create.Error.Disabled";
676 if (e.name() == ERROR_DUMP_DISABLED)
677 {
678 log<level::INFO>("Dump is disabled, skipping");
679 }
680 else
681 {
682 log<level::ERR>("Dump failed");
683 }
684 }
685 }
686}
687
688bool Manager::sbeCanDump(unsigned int instance)
689{
690 struct pdbg_target* proc = getPdbgTarget(instance);
691
692 if (!proc)
693 {
694 // allow the dump in the error case
695 return true;
696 }
697
698 try
699 {
700 if (!openpower::phal::sbe::isDumpAllowed(proc))
701 {
702 return false;
703 }
704
705 if (openpower::phal::pdbg::isSbeVitalAttnActive(proc))
706 {
707 return false;
708 }
709 }
710 catch (openpower::phal::exception::SbeError& e)
711 {
712 log<level::INFO>("Failed to query SBE state");
713 }
714
715 // allow the dump in the error case
716 return true;
717}
718
719void Manager::setSBEState(unsigned int instance, enum sbe_state state)
720{
721 struct pdbg_target* proc = getPdbgTarget(instance);
722
723 if (!proc)
724 {
725 return;
726 }
727
728 try
729 {
730 openpower::phal::sbe::setState(proc, state);
731 }
732 catch (const openpower::phal::exception::SbeError& e)
733 {
734 log<level::ERR>("Failed to set SBE state");
735 }
736}
737
738struct pdbg_target* Manager::getPdbgTarget(unsigned int instance)
739{
740 if (!pdbgInitialized)
741 {
742 try
743 {
744 openpower::phal::pdbg::init();
745 pdbgInitialized = true;
746 }
747 catch (const openpower::phal::exception::PdbgError& e)
748 {
749 log<level::ERR>("pdbg initialization failed");
750 return nullptr;
751 }
752 }
753
754 struct pdbg_target* proc = nullptr;
755 pdbg_for_each_class_target("proc", proc)
756 {
757 if (pdbg_target_index(proc) == instance)
758 {
759 return proc;
760 }
761 }
762
763 log<level::ERR>("Failed to get pdbg target");
764 return nullptr;
765}
Tom Joseph815f9f52020-07-27 12:12:13 +0530766#endif
767
Chris Caina8857c52021-01-27 11:53:05 -0600768void Manager::pollerTimerExpired()
769{
Chris Caina8857c52021-01-27 11:53:05 -0600770 if (!_pollTimer)
771 {
772 log<level::ERR>(
773 "Manager::pollerTimerExpired() ERROR: Timer not defined");
774 return;
775 }
776
777 for (auto& obj : statusObjects)
778 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600779 if (!obj->occActive())
780 {
781 // OCC is not running yet
782#ifdef READ_OCC_SENSORS
Chris Cain5d66a0a2022-02-09 08:52:10 -0600783 auto id = obj->getOccInstanceID();
Sheldon Baileyc8dd4592022-05-12 10:15:14 -0500784 setSensorValueToNaN(id);
Chris Caina7b74dc2021-11-10 17:03:43 -0600785#endif
786 continue;
787 }
788
Chris Caina8857c52021-01-27 11:53:05 -0600789 // Read sysfs to force kernel to poll OCC
790 obj->readOccState();
Chicago Duanbb895cb2021-06-18 19:37:16 +0800791
792#ifdef READ_OCC_SENSORS
793 // Read occ sensor values
Chris Cain5d66a0a2022-02-09 08:52:10 -0600794 getSensorValues(obj);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800795#endif
Chris Caina8857c52021-01-27 11:53:05 -0600796 }
797
Chris Caina7b74dc2021-11-10 17:03:43 -0600798 if (activeCount > 0)
799 {
800 // Restart OCC poll timer
801 _pollTimer->restartOnce(std::chrono::seconds(pollInterval));
802 }
803 else
804 {
805 // No OCCs running, so poll timer will not be restarted
806 log<level::INFO>(
Patrick Williams48002492024-02-13 21:43:32 -0600807 std::format(
Chris Caina7b74dc2021-11-10 17:03:43 -0600808 "Manager::pollerTimerExpired: poll timer will not be restarted")
809 .c_str());
810 }
Chris Caina8857c52021-01-27 11:53:05 -0600811}
812
Chicago Duanbb895cb2021-06-18 19:37:16 +0800813#ifdef READ_OCC_SENSORS
Chris Cainae157b62024-01-23 16:05:12 -0600814void Manager::readTempSensors(const fs::path& path, uint32_t occInstance)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800815{
Matt Spinler818cc8d2023-10-23 11:43:39 -0500816 // There may be more than one sensor with the same FRU type
817 // and label so make two passes: the first to read the temps
818 // from sysfs, and the second to put them on D-Bus after
819 // resolving any conflicts.
820 std::map<std::string, double> sensorData;
821
Chicago Duanbb895cb2021-06-18 19:37:16 +0800822 std::regex expr{"temp\\d+_label$"}; // Example: temp5_label
823 for (auto& file : fs::directory_iterator(path))
824 {
825 if (!std::regex_search(file.path().string(), expr))
826 {
827 continue;
828 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800829
Matt Spinlera26f1522021-08-25 15:50:20 -0500830 uint32_t labelValue{0};
831
832 try
833 {
834 labelValue = readFile<uint32_t>(file.path());
835 }
836 catch (const std::system_error& e)
837 {
838 log<level::DEBUG>(
Patrick Williams48002492024-02-13 21:43:32 -0600839 std::format("readTempSensors: Failed reading {}, errno = {}",
Matt Spinlera26f1522021-08-25 15:50:20 -0500840 file.path().string(), e.code().value())
841 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800842 continue;
843 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800844
845 const std::string& tempLabel = "label";
846 const std::string filePathString = file.path().string().substr(
847 0, file.path().string().length() - tempLabel.length());
Matt Spinlera26f1522021-08-25 15:50:20 -0500848
849 uint32_t fruTypeValue{0};
850 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800851 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500852 fruTypeValue = readFile<uint32_t>(filePathString + fruTypeSuffix);
853 }
854 catch (const std::system_error& e)
855 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800856 log<level::DEBUG>(
Patrick Williams48002492024-02-13 21:43:32 -0600857 std::format("readTempSensors: Failed reading {}, errno = {}",
Matt Spinlera26f1522021-08-25 15:50:20 -0500858 filePathString + fruTypeSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +0800859 .c_str());
860 continue;
861 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800862
Patrick Williamsd7542c82024-08-16 15:20:28 -0400863 std::string sensorPath =
864 OCC_SENSORS_ROOT + std::string("/temperature/");
Chicago Duanbb895cb2021-06-18 19:37:16 +0800865
Matt Spinlerace67d82021-10-18 13:41:57 -0500866 std::string dvfsTempPath;
867
Chicago Duanbb895cb2021-06-18 19:37:16 +0800868 if (fruTypeValue == VRMVdd)
869 {
Patrick Williamsd7542c82024-08-16 15:20:28 -0400870 sensorPath.append(
871 "vrm_vdd" + std::to_string(occInstance) + "_temp");
Chicago Duanbb895cb2021-06-18 19:37:16 +0800872 }
Matt Spinlerace67d82021-10-18 13:41:57 -0500873 else if (fruTypeValue == processorIoRing)
874 {
Patrick Williamsd7542c82024-08-16 15:20:28 -0400875 sensorPath.append(
876 "proc" + std::to_string(occInstance) + "_ioring_temp");
Matt Spinlerace67d82021-10-18 13:41:57 -0500877 dvfsTempPath = std::string{OCC_SENSORS_ROOT} + "/temperature/proc" +
Chris Cainae157b62024-01-23 16:05:12 -0600878 std::to_string(occInstance) + "_ioring_dvfs_temp";
Matt Spinlerace67d82021-10-18 13:41:57 -0500879 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800880 else
881 {
Matt Spinler14d14022021-08-25 15:38:29 -0500882 uint16_t type = (labelValue & 0xFF000000) >> 24;
883 uint16_t instanceID = labelValue & 0x0000FFFF;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800884
885 if (type == OCC_DIMM_TEMP_SENSOR_TYPE)
886 {
Matt Spinler8b8abee2021-08-25 15:18:21 -0500887 if (fruTypeValue == fruTypeNotAvailable)
888 {
889 // Not all DIMM related temps are available to read
890 // (no _input file in this case)
891 continue;
892 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800893 auto iter = dimmTempSensorName.find(fruTypeValue);
894 if (iter == dimmTempSensorName.end())
895 {
George Liub5ca1012021-09-10 12:53:11 +0800896 log<level::ERR>(
Patrick Williams48002492024-02-13 21:43:32 -0600897 std::format(
George Liub5ca1012021-09-10 12:53:11 +0800898 "readTempSensors: Fru type error! fruTypeValue = {}) ",
899 fruTypeValue)
900 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800901 continue;
902 }
903
Patrick Williamsd7542c82024-08-16 15:20:28 -0400904 sensorPath.append(
905 "dimm" + std::to_string(instanceID) + iter->second);
Matt Spinlerad8f4522023-10-25 11:14:46 -0500906
907 dvfsTempPath = std::string{OCC_SENSORS_ROOT} + "/temperature/" +
908 dimmDVFSSensorName.at(fruTypeValue);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800909 }
910 else if (type == OCC_CPU_TEMP_SENSOR_TYPE)
911 {
Matt Spinlerace67d82021-10-18 13:41:57 -0500912 if (fruTypeValue == processorCore)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800913 {
Matt Spinlerace67d82021-10-18 13:41:57 -0500914 // The OCC reports small core temps, of which there are
915 // two per big core. All current P10 systems are in big
916 // core mode, so use a big core name.
917 uint16_t coreNum = instanceID / 2;
918 uint16_t tempNum = instanceID % 2;
Chris Cainae157b62024-01-23 16:05:12 -0600919 sensorPath.append("proc" + std::to_string(occInstance) +
920 "_core" + std::to_string(coreNum) + "_" +
Matt Spinlerace67d82021-10-18 13:41:57 -0500921 std::to_string(tempNum) + "_temp");
922
Chris Cainae157b62024-01-23 16:05:12 -0600923 dvfsTempPath =
924 std::string{OCC_SENSORS_ROOT} + "/temperature/proc" +
925 std::to_string(occInstance) + "_core_dvfs_temp";
Matt Spinlerace67d82021-10-18 13:41:57 -0500926 }
927 else
928 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800929 continue;
930 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800931 }
932 else
933 {
934 continue;
935 }
936 }
937
Matt Spinlerace67d82021-10-18 13:41:57 -0500938 // The dvfs temp file only needs to be read once per chip per type.
939 if (!dvfsTempPath.empty() &&
940 !dbus::OccDBusSensors::getOccDBus().hasDvfsTemp(dvfsTempPath))
941 {
942 try
943 {
944 auto dvfsValue = readFile<double>(filePathString + maxSuffix);
945
946 dbus::OccDBusSensors::getOccDBus().setDvfsTemp(
947 dvfsTempPath, dvfsValue * std::pow(10, -3));
948 }
949 catch (const std::system_error& e)
950 {
951 log<level::DEBUG>(
Patrick Williams48002492024-02-13 21:43:32 -0600952 std::format(
Matt Spinlerace67d82021-10-18 13:41:57 -0500953 "readTempSensors: Failed reading {}, errno = {}",
954 filePathString + maxSuffix, e.code().value())
955 .c_str());
956 }
957 }
958
Matt Spinlera26f1522021-08-25 15:50:20 -0500959 uint32_t faultValue{0};
960 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800961 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500962 faultValue = readFile<uint32_t>(filePathString + faultSuffix);
963 }
964 catch (const std::system_error& e)
965 {
966 log<level::DEBUG>(
Patrick Williams48002492024-02-13 21:43:32 -0600967 std::format("readTempSensors: Failed reading {}, errno = {}",
Matt Spinlera26f1522021-08-25 15:50:20 -0500968 filePathString + faultSuffix, e.code().value())
969 .c_str());
970 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800971 }
972
Chris Cainae157b62024-01-23 16:05:12 -0600973 double tempValue{0};
974 // NOTE: if OCC sends back 0xFF, kernal sets this fault value to 1.
Matt Spinlera26f1522021-08-25 15:50:20 -0500975 if (faultValue != 0)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800976 {
Chris Cainae157b62024-01-23 16:05:12 -0600977 tempValue = std::numeric_limits<double>::quiet_NaN();
Chicago Duanbb895cb2021-06-18 19:37:16 +0800978 }
Chris Cainae157b62024-01-23 16:05:12 -0600979 else
Chicago Duanbb895cb2021-06-18 19:37:16 +0800980 {
Chris Cainae157b62024-01-23 16:05:12 -0600981 // Read the temperature
982 try
Sheldon Baileycd0940b2022-04-26 14:24:05 -0500983 {
Chris Cainae157b62024-01-23 16:05:12 -0600984 tempValue = readFile<double>(filePathString + inputSuffix);
Sheldon Baileycd0940b2022-04-26 14:24:05 -0500985 }
Chris Cainae157b62024-01-23 16:05:12 -0600986 catch (const std::system_error& e)
Sheldon Baileycd0940b2022-04-26 14:24:05 -0500987 {
Chris Cainae157b62024-01-23 16:05:12 -0600988 log<level::DEBUG>(
Patrick Williams48002492024-02-13 21:43:32 -0600989 std::format(
Chris Cainae157b62024-01-23 16:05:12 -0600990 "readTempSensors: Failed reading {}, errno = {}",
991 filePathString + inputSuffix, e.code().value())
992 .c_str());
993
994 // if errno == EAGAIN(Resource temporarily unavailable) then set
995 // temp to 0, to avoid using old temp, and affecting FAN
996 // Control.
997 if (e.code().value() == EAGAIN)
998 {
999 tempValue = 0;
1000 }
1001 // else the errno would be something like
1002 // EBADF(Bad file descriptor)
1003 // or ENOENT(No such file or directory)
1004 else
1005 {
1006 continue;
1007 }
Sheldon Baileycd0940b2022-04-26 14:24:05 -05001008 }
Matt Spinlera26f1522021-08-25 15:50:20 -05001009 }
1010
Matt Spinler818cc8d2023-10-23 11:43:39 -05001011 // If this object path already has a value, only overwite
1012 // it if the previous one was an NaN or a smaller value.
1013 auto existing = sensorData.find(sensorPath);
1014 if (existing != sensorData.end())
1015 {
Chris Cainae157b62024-01-23 16:05:12 -06001016 // Multiple sensors found for this FRU type
1017 if ((std::isnan(existing->second) && (tempValue == 0)) ||
1018 ((existing->second == 0) && std::isnan(tempValue)))
1019 {
1020 // One of the redundant sensors has failed (0xFF/nan), and the
1021 // other sensor has no reading (0), so set the FRU to NaN to
1022 // force fan increase
1023 tempValue = std::numeric_limits<double>::quiet_NaN();
1024 existing->second = tempValue;
1025 }
Matt Spinler818cc8d2023-10-23 11:43:39 -05001026 if (std::isnan(existing->second) || (tempValue > existing->second))
1027 {
1028 existing->second = tempValue;
1029 }
1030 }
1031 else
1032 {
Chris Cainae157b62024-01-23 16:05:12 -06001033 // First sensor for this FRU type
Matt Spinler818cc8d2023-10-23 11:43:39 -05001034 sensorData[sensorPath] = tempValue;
1035 }
1036 }
Matt Spinlera26f1522021-08-25 15:50:20 -05001037
Matt Spinler818cc8d2023-10-23 11:43:39 -05001038 // Now publish the values on D-Bus.
1039 for (const auto& [objectPath, value] : sensorData)
1040 {
1041 dbus::OccDBusSensors::getOccDBus().setValue(objectPath,
1042 value * std::pow(10, -3));
Matt Spinlera26f1522021-08-25 15:50:20 -05001043
Matt Spinler818cc8d2023-10-23 11:43:39 -05001044 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(
1045 objectPath, !std::isnan(value));
1046
1047 if (existingSensors.find(objectPath) == existingSensors.end())
Chris Cain6fa848a2022-01-24 14:54:38 -06001048 {
Chris Cain5d66a0a2022-02-09 08:52:10 -06001049 dbus::OccDBusSensors::getOccDBus().setChassisAssociation(
Matt Spinler818cc8d2023-10-23 11:43:39 -05001050 objectPath);
Chris Cain6fa848a2022-01-24 14:54:38 -06001051 }
1052
Chris Cainae157b62024-01-23 16:05:12 -06001053 existingSensors[objectPath] = occInstance;
Chicago Duanbb895cb2021-06-18 19:37:16 +08001054 }
Chicago Duanbb895cb2021-06-18 19:37:16 +08001055}
1056
1057std::optional<std::string>
1058 Manager::getPowerLabelFunctionID(const std::string& value)
1059{
1060 // If the value is "system", then the FunctionID is "system".
1061 if (value == "system")
1062 {
1063 return value;
1064 }
1065
1066 // If the value is not "system", then the label value have 3 numbers, of
1067 // which we only care about the middle one:
1068 // <sensor id>_<function id>_<apss channel>
1069 // eg: The value is "0_10_5" , then the FunctionID is "10".
1070 if (value.find("_") == std::string::npos)
1071 {
1072 return std::nullopt;
1073 }
1074
1075 auto powerLabelValue = value.substr((value.find("_") + 1));
1076
1077 if (powerLabelValue.find("_") == std::string::npos)
1078 {
1079 return std::nullopt;
1080 }
1081
1082 return powerLabelValue.substr(0, powerLabelValue.find("_"));
1083}
1084
1085void Manager::readPowerSensors(const fs::path& path, uint32_t id)
1086{
Chicago Duanbb895cb2021-06-18 19:37:16 +08001087 std::regex expr{"power\\d+_label$"}; // Example: power5_label
1088 for (auto& file : fs::directory_iterator(path))
1089 {
1090 if (!std::regex_search(file.path().string(), expr))
1091 {
1092 continue;
1093 }
Chicago Duanbb895cb2021-06-18 19:37:16 +08001094
Matt Spinlera26f1522021-08-25 15:50:20 -05001095 std::string labelValue;
1096 try
1097 {
1098 labelValue = readFile<std::string>(file.path());
1099 }
1100 catch (const std::system_error& e)
1101 {
1102 log<level::DEBUG>(
Patrick Williams48002492024-02-13 21:43:32 -06001103 std::format("readPowerSensors: Failed reading {}, errno = {}",
Matt Spinlera26f1522021-08-25 15:50:20 -05001104 file.path().string(), e.code().value())
1105 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +08001106 continue;
1107 }
Chicago Duanbb895cb2021-06-18 19:37:16 +08001108
1109 auto functionID = getPowerLabelFunctionID(labelValue);
1110 if (functionID == std::nullopt)
1111 {
1112 continue;
1113 }
1114
1115 const std::string& tempLabel = "label";
1116 const std::string filePathString = file.path().string().substr(
1117 0, file.path().string().length() - tempLabel.length());
1118
1119 std::string sensorPath = OCC_SENSORS_ROOT + std::string("/power/");
1120
1121 auto iter = powerSensorName.find(*functionID);
1122 if (iter == powerSensorName.end())
1123 {
1124 continue;
1125 }
1126 sensorPath.append(iter->second);
1127
Matt Spinlera26f1522021-08-25 15:50:20 -05001128 double tempValue{0};
1129
1130 try
Chicago Duanbb895cb2021-06-18 19:37:16 +08001131 {
Matt Spinlera26f1522021-08-25 15:50:20 -05001132 tempValue = readFile<double>(filePathString + inputSuffix);
Chicago Duanbb895cb2021-06-18 19:37:16 +08001133 }
Matt Spinlera26f1522021-08-25 15:50:20 -05001134 catch (const std::system_error& e)
Chicago Duanbb895cb2021-06-18 19:37:16 +08001135 {
Chicago Duanbb895cb2021-06-18 19:37:16 +08001136 log<level::DEBUG>(
Patrick Williams48002492024-02-13 21:43:32 -06001137 std::format("readPowerSensors: Failed reading {}, errno = {}",
Matt Spinlera26f1522021-08-25 15:50:20 -05001138 filePathString + inputSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +08001139 .c_str());
Matt Spinlera26f1522021-08-25 15:50:20 -05001140 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +08001141 }
Matt Spinlera26f1522021-08-25 15:50:20 -05001142
Chris Cain5d66a0a2022-02-09 08:52:10 -06001143 dbus::OccDBusSensors::getOccDBus().setUnit(
Chris Caind84a8332022-01-13 08:58:45 -06001144 sensorPath, "xyz.openbmc_project.Sensor.Value.Unit.Watts");
1145
Chris Cain5d66a0a2022-02-09 08:52:10 -06001146 dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -05001147 sensorPath, tempValue * std::pow(10, -3) * std::pow(10, -3));
1148
Patrick Williamsd7542c82024-08-16 15:20:28 -04001149 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(
1150 sensorPath, true);
Matt Spinlera26f1522021-08-25 15:50:20 -05001151
Matt Spinler5901abd2021-09-23 13:50:03 -05001152 if (existingSensors.find(sensorPath) == existingSensors.end())
1153 {
Chris Cain5d66a0a2022-02-09 08:52:10 -06001154 dbus::OccDBusSensors::getOccDBus().setChassisAssociation(
1155 sensorPath);
Matt Spinler5901abd2021-09-23 13:50:03 -05001156 }
1157
Matt Spinlera26f1522021-08-25 15:50:20 -05001158 existingSensors[sensorPath] = id;
Chicago Duanbb895cb2021-06-18 19:37:16 +08001159 }
1160 return;
1161}
1162
Sheldon Baileyc8dd4592022-05-12 10:15:14 -05001163void Manager::setSensorValueToNaN(uint32_t id) const
Chicago Duanbb895cb2021-06-18 19:37:16 +08001164{
1165 for (const auto& [sensorPath, occId] : existingSensors)
1166 {
1167 if (occId == id)
1168 {
Chris Cain5d66a0a2022-02-09 08:52:10 -06001169 dbus::OccDBusSensors::getOccDBus().setValue(
Chicago Duanbb895cb2021-06-18 19:37:16 +08001170 sensorPath, std::numeric_limits<double>::quiet_NaN());
Sheldon Baileyc8dd4592022-05-12 10:15:14 -05001171
Patrick Williamsd7542c82024-08-16 15:20:28 -04001172 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(
1173 sensorPath, true);
Chicago Duanbb895cb2021-06-18 19:37:16 +08001174 }
1175 }
1176 return;
1177}
1178
Sheldon Bailey373af752022-02-21 15:14:00 -06001179void Manager::setSensorValueToNonFunctional(uint32_t id) const
1180{
1181 for (const auto& [sensorPath, occId] : existingSensors)
1182 {
1183 if (occId == id)
1184 {
1185 dbus::OccDBusSensors::getOccDBus().setValue(
1186 sensorPath, std::numeric_limits<double>::quiet_NaN());
1187
Patrick Williamsd7542c82024-08-16 15:20:28 -04001188 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(
1189 sensorPath, false);
Sheldon Bailey373af752022-02-21 15:14:00 -06001190 }
1191 }
1192 return;
1193}
1194
Chris Cain5d66a0a2022-02-09 08:52:10 -06001195void Manager::getSensorValues(std::unique_ptr<Status>& occ)
Chicago Duanbb895cb2021-06-18 19:37:16 +08001196{
Chris Caine2d0a432022-03-28 11:08:49 -05001197 static bool tracedError[8] = {0};
1198 const fs::path sensorPath = occ->getHwmonPath();
Chris Cain5d66a0a2022-02-09 08:52:10 -06001199 const uint32_t id = occ->getOccInstanceID();
Chicago Duanbb895cb2021-06-18 19:37:16 +08001200
Chris Caine2d0a432022-03-28 11:08:49 -05001201 if (fs::exists(sensorPath))
Chicago Duanbb895cb2021-06-18 19:37:16 +08001202 {
Chris Caine2d0a432022-03-28 11:08:49 -05001203 // Read temperature sensors
1204 readTempSensors(sensorPath, id);
1205
1206 if (occ->isMasterOcc())
1207 {
1208 // Read power sensors
1209 readPowerSensors(sensorPath, id);
1210 }
1211 tracedError[id] = false;
1212 }
1213 else
1214 {
1215 if (!tracedError[id])
1216 {
1217 log<level::ERR>(
Patrick Williams48002492024-02-13 21:43:32 -06001218 std::format(
Chris Caine2d0a432022-03-28 11:08:49 -05001219 "Manager::getSensorValues: OCC{} sensor path missing: {}",
1220 id, sensorPath.c_str())
1221 .c_str());
1222 tracedError[id] = true;
1223 }
Chicago Duanbb895cb2021-06-18 19:37:16 +08001224 }
1225
1226 return;
1227}
1228#endif
Chris Cain17257672021-10-22 13:41:03 -05001229
1230// Read the altitude from DBus
1231void Manager::readAltitude()
1232{
1233 static bool traceAltitudeErr = true;
1234
1235 utils::PropertyValue altitudeProperty{};
1236 try
1237 {
1238 altitudeProperty = utils::getProperty(ALTITUDE_PATH, ALTITUDE_INTERFACE,
1239 ALTITUDE_PROP);
1240 auto sensorVal = std::get<double>(altitudeProperty);
1241 if (sensorVal < 0xFFFF)
1242 {
1243 if (sensorVal < 0)
1244 {
1245 altitude = 0;
1246 }
1247 else
1248 {
1249 // Round to nearest meter
1250 altitude = uint16_t(sensorVal + 0.5);
1251 }
Patrick Williams48002492024-02-13 21:43:32 -06001252 log<level::DEBUG>(std::format("readAltitude: sensor={} ({}m)",
Chris Cain17257672021-10-22 13:41:03 -05001253 sensorVal, altitude)
1254 .c_str());
1255 traceAltitudeErr = true;
1256 }
1257 else
1258 {
1259 if (traceAltitudeErr)
1260 {
1261 traceAltitudeErr = false;
1262 log<level::DEBUG>(
Patrick Williams48002492024-02-13 21:43:32 -06001263 std::format("Invalid altitude value: {}", sensorVal)
Chris Cain17257672021-10-22 13:41:03 -05001264 .c_str());
1265 }
1266 }
1267 }
Patrick Williamsaf408082022-07-22 19:26:54 -05001268 catch (const sdbusplus::exception_t& e)
Chris Cain17257672021-10-22 13:41:03 -05001269 {
1270 if (traceAltitudeErr)
1271 {
1272 traceAltitudeErr = false;
1273 log<level::INFO>(
Patrick Williams48002492024-02-13 21:43:32 -06001274 std::format("Unable to read Altitude: {}", e.what()).c_str());
Chris Cain17257672021-10-22 13:41:03 -05001275 }
1276 altitude = 0xFFFF; // not available
1277 }
1278}
1279
1280// Callback function when ambient temperature changes
Patrick Williamsaf408082022-07-22 19:26:54 -05001281void Manager::ambientCallback(sdbusplus::message_t& msg)
Chris Cain17257672021-10-22 13:41:03 -05001282{
1283 double currentTemp = 0;
1284 uint8_t truncatedTemp = 0xFF;
1285 std::string msgSensor;
1286 std::map<std::string, std::variant<double>> msgData;
1287 msg.read(msgSensor, msgData);
1288
1289 auto valPropMap = msgData.find(AMBIENT_PROP);
1290 if (valPropMap == msgData.end())
1291 {
1292 log<level::DEBUG>("ambientCallback: Unknown ambient property changed");
1293 return;
1294 }
1295 currentTemp = std::get<double>(valPropMap->second);
1296 if (std::isnan(currentTemp))
1297 {
1298 truncatedTemp = 0xFF;
1299 }
1300 else
1301 {
1302 if (currentTemp < 0)
1303 {
1304 truncatedTemp = 0;
1305 }
1306 else
1307 {
1308 // Round to nearest degree C
1309 truncatedTemp = uint8_t(currentTemp + 0.5);
1310 }
1311 }
1312
1313 // If ambient changes, notify OCCs
1314 if (truncatedTemp != ambient)
1315 {
1316 log<level::DEBUG>(
Patrick Williams48002492024-02-13 21:43:32 -06001317 std::format("ambientCallback: Ambient change from {} to {}C",
Chris Cain17257672021-10-22 13:41:03 -05001318 ambient, currentTemp)
1319 .c_str());
1320
1321 ambient = truncatedTemp;
1322 if (altitude == 0xFFFF)
1323 {
1324 // No altitude yet, try reading again
1325 readAltitude();
1326 }
1327
1328 log<level::DEBUG>(
Patrick Williams48002492024-02-13 21:43:32 -06001329 std::format("ambientCallback: Ambient: {}C, altitude: {}m", ambient,
Chris Cain17257672021-10-22 13:41:03 -05001330 altitude)
1331 .c_str());
1332#ifdef POWER10
1333 // Send ambient and altitude to all OCCs
1334 for (auto& obj : statusObjects)
1335 {
1336 if (obj->occActive())
1337 {
1338 obj->sendAmbient(ambient, altitude);
1339 }
1340 }
1341#endif // POWER10
1342 }
1343}
1344
1345// return the current ambient and altitude readings
1346void Manager::getAmbientData(bool& ambientValid, uint8_t& ambientTemp,
1347 uint16_t& altitudeValue) const
1348{
1349 ambientValid = true;
1350 ambientTemp = ambient;
1351 altitudeValue = altitude;
1352
1353 if (ambient == 0xFF)
1354 {
1355 ambientValid = false;
1356 }
1357}
1358
Chris Caina7b74dc2021-11-10 17:03:43 -06001359#ifdef POWER10
Chris Cain7f89e4d2022-05-09 13:27:45 -05001360// Called when waitForAllOccsTimer expires
1361// After the first OCC goes active, this timer will be started (60 seconds)
Chris Caina7b74dc2021-11-10 17:03:43 -06001362void Manager::occsNotAllRunning()
1363{
Chris Caina7b74dc2021-11-10 17:03:43 -06001364 if (activeCount != statusObjects.size())
1365 {
1366 // Not all OCCs went active
1367 log<level::WARNING>(
Patrick Williams48002492024-02-13 21:43:32 -06001368 std::format(
Chris Caina7b74dc2021-11-10 17:03:43 -06001369 "occsNotAllRunning: Active OCC count ({}) does not match expected count ({})",
1370 activeCount, statusObjects.size())
1371 .c_str());
Chris Cain7f89e4d2022-05-09 13:27:45 -05001372 // Procs may be garded, so may be expected
Chris Caina7b74dc2021-11-10 17:03:43 -06001373 }
1374
1375 validateOccMaster();
1376}
Chris Cain755af102024-02-27 16:09:51 -06001377
1378#ifdef PLDM
Chris Cainc33171b2024-05-24 16:14:50 -05001379// Called when throttlePldmTraceTimer expires.
Chris Caina19bd422024-05-24 16:39:01 -05001380// If this timer expires, that indicates there are no OCC active sensor PDRs
Chris Cainc33171b2024-05-24 16:14:50 -05001381// found which will trigger pldm traces to be throttled.
1382// The second time this timer expires, a PEL will get created.
1383void Manager::throttlePldmTraceExpired()
Chris Cain755af102024-02-27 16:09:51 -06001384{
Chris Cain7651c062024-05-02 14:14:06 -05001385 if (utils::isHostRunning())
1386 {
Chris Cainc33171b2024-05-24 16:14:50 -05001387 if (!onPldmTimeoutCreatePel)
1388 {
1389 // Throttle traces
1390 pldmHandle->setTraceThrottle(true);
1391 // Restart timer to log a PEL when timer expires
1392 onPldmTimeoutCreatePel = true;
1393 throttlePldmTraceTimer->restartOnce(40min);
1394 }
1395 else
1396 {
1397 log<level::ERR>(
1398 "throttlePldmTraceExpired(): OCC active sensors still not available!");
1399 // Create PEL
1400 createPldmSensorPEL();
1401 }
Chris Cain7651c062024-05-02 14:14:06 -05001402 }
1403 else
1404 {
1405 // Make sure traces are not throttled
1406 pldmHandle->setTraceThrottle(false);
1407 log<level::INFO>(
Chris Cainc33171b2024-05-24 16:14:50 -05001408 "throttlePldmTraceExpired(): host it not running ignoring sensor timer");
Chris Cain7651c062024-05-02 14:14:06 -05001409 }
Chris Cain4b82f3e2024-04-22 14:44:29 -05001410}
1411
1412void Manager::createPldmSensorPEL()
1413{
1414 Error::Descriptor d = Error::Descriptor(MISSING_OCC_SENSORS_PATH);
1415 std::map<std::string, std::string> additionalData;
1416
1417 additionalData.emplace("_PID", std::to_string(getpid()));
1418
1419 log<level::INFO>(
1420 std::format(
1421 "createPldmSensorPEL(): Unable to find PLDM sensors for the OCCs")
1422 .c_str());
1423
1424 auto& bus = utils::getBus();
1425
1426 try
1427 {
1428 FFDCFiles ffdc;
1429 // Add occ-control journal traces to PEL FFDC
1430 auto occJournalFile =
1431 FFDC::addJournalEntries(ffdc, "openpower-occ-control", 40);
1432
1433 static constexpr auto loggingObjectPath =
1434 "/xyz/openbmc_project/logging";
1435 static constexpr auto opLoggingInterface = "org.open_power.Logging.PEL";
Patrick Williamsd7542c82024-08-16 15:20:28 -04001436 std::string service =
1437 utils::getService(loggingObjectPath, opLoggingInterface);
1438 auto method =
1439 bus.new_method_call(service.c_str(), loggingObjectPath,
1440 opLoggingInterface, "CreatePELWithFFDCFiles");
Chris Cain4b82f3e2024-04-22 14:44:29 -05001441
Chris Cain1c3349e2024-04-24 14:14:11 -05001442 // Set level to Warning (Predictive).
Chris Cain4b82f3e2024-04-22 14:44:29 -05001443 auto level =
1444 sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage(
1445 sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level::
Chris Cain1c3349e2024-04-24 14:14:11 -05001446 Warning);
Chris Cain4b82f3e2024-04-22 14:44:29 -05001447
1448 method.append(d.path, level, additionalData, ffdc);
1449 bus.call(method);
1450 }
1451 catch (const sdbusplus::exception_t& e)
1452 {
1453 log<level::ERR>(
1454 std::format("Failed to create MISSING_OCC_SENSORS PEL: {}",
1455 e.what())
1456 .c_str());
1457 }
Chris Cain755af102024-02-27 16:09:51 -06001458}
1459#endif // PLDM
Chris Caina7b74dc2021-11-10 17:03:43 -06001460#endif // POWER10
1461
1462// Verify single master OCC and start presence monitor
1463void Manager::validateOccMaster()
1464{
1465 int masterInstance = -1;
1466 for (auto& obj : statusObjects)
1467 {
Chris Cainbd551de2022-04-26 13:41:16 -05001468 auto instance = obj->getOccInstanceID();
Chris Cainbae4d072022-02-28 09:46:50 -06001469#ifdef POWER10
1470 if (!obj->occActive())
1471 {
1472 if (utils::isHostRunning())
1473 {
Chris Cainbd551de2022-04-26 13:41:16 -05001474 // Check if sensor was queued while waiting for discovery
1475 auto match = queuedActiveState.find(instance);
1476 if (match != queuedActiveState.end())
Chris Cainbae4d072022-02-28 09:46:50 -06001477 {
Chris Cain7f89e4d2022-05-09 13:27:45 -05001478 queuedActiveState.erase(match);
Chris Cainbae4d072022-02-28 09:46:50 -06001479 log<level::INFO>(
Patrick Williams48002492024-02-13 21:43:32 -06001480 std::format(
Chris Cainbd551de2022-04-26 13:41:16 -05001481 "validateOccMaster: OCC{} is ACTIVE (queued)",
1482 instance)
Chris Cainbae4d072022-02-28 09:46:50 -06001483 .c_str());
Chris Cainbd551de2022-04-26 13:41:16 -05001484 obj->occActive(true);
1485 }
1486 else
1487 {
1488 // OCC does not appear to be active yet, check active sensor
Patrick Williamsfb0a5c32024-02-28 11:27:00 -06001489#ifdef PLDM
Chris Cainbd551de2022-04-26 13:41:16 -05001490 pldmHandle->checkActiveSensor(instance);
Patrick Williamsfb0a5c32024-02-28 11:27:00 -06001491#endif
Chris Cainbd551de2022-04-26 13:41:16 -05001492 if (obj->occActive())
1493 {
1494 log<level::INFO>(
Patrick Williams48002492024-02-13 21:43:32 -06001495 std::format(
Chris Cainbd551de2022-04-26 13:41:16 -05001496 "validateOccMaster: OCC{} is ACTIVE after reading sensor",
1497 instance)
1498 .c_str());
1499 }
Chris Cainbae4d072022-02-28 09:46:50 -06001500 }
1501 }
1502 else
1503 {
1504 log<level::WARNING>(
Patrick Williams48002492024-02-13 21:43:32 -06001505 std::format(
Chris Cainbae4d072022-02-28 09:46:50 -06001506 "validateOccMaster: HOST is not running (OCC{})",
Chris Cainbd551de2022-04-26 13:41:16 -05001507 instance)
Chris Cainbae4d072022-02-28 09:46:50 -06001508 .c_str());
1509 return;
1510 }
1511 }
1512#endif // POWER10
1513
Chris Caina7b74dc2021-11-10 17:03:43 -06001514 if (obj->isMasterOcc())
1515 {
Chris Cain5d66a0a2022-02-09 08:52:10 -06001516 obj->addPresenceWatchMaster();
1517
Chris Caina7b74dc2021-11-10 17:03:43 -06001518 if (masterInstance == -1)
1519 {
Chris Cainbd551de2022-04-26 13:41:16 -05001520 masterInstance = instance;
Chris Caina7b74dc2021-11-10 17:03:43 -06001521 }
1522 else
1523 {
1524 log<level::ERR>(
Patrick Williams48002492024-02-13 21:43:32 -06001525 std::format(
Chris Caina7b74dc2021-11-10 17:03:43 -06001526 "validateOccMaster: Multiple OCC masters! ({} and {})",
Chris Cainbd551de2022-04-26 13:41:16 -05001527 masterInstance, instance)
Chris Caina7b74dc2021-11-10 17:03:43 -06001528 .c_str());
1529 // request reset
Eddie James9789e712022-05-25 15:43:40 -05001530 obj->deviceError(Error::Descriptor(PRESENCE_ERROR_PATH));
Chris Caina7b74dc2021-11-10 17:03:43 -06001531 }
1532 }
1533 }
Chris Cainbae4d072022-02-28 09:46:50 -06001534
Chris Caina7b74dc2021-11-10 17:03:43 -06001535 if (masterInstance < 0)
1536 {
Chris Cainbae4d072022-02-28 09:46:50 -06001537 log<level::ERR>(
Patrick Williams48002492024-02-13 21:43:32 -06001538 std::format("validateOccMaster: Master OCC not found! (of {} OCCs)",
Chris Cainbae4d072022-02-28 09:46:50 -06001539 statusObjects.size())
1540 .c_str());
Chris Caina7b74dc2021-11-10 17:03:43 -06001541 // request reset
Eddie James9789e712022-05-25 15:43:40 -05001542 statusObjects.front()->deviceError(
1543 Error::Descriptor(PRESENCE_ERROR_PATH));
Chris Caina7b74dc2021-11-10 17:03:43 -06001544 }
1545 else
1546 {
1547 log<level::INFO>(
Patrick Williams48002492024-02-13 21:43:32 -06001548 std::format("validateOccMaster: OCC{} is master of {} OCCs",
Chris Cain36f9cde2021-11-22 11:18:21 -06001549 masterInstance, activeCount)
Chris Caina7b74dc2021-11-10 17:03:43 -06001550 .c_str());
Sheldon Bailey31a2f132022-05-20 11:31:52 -05001551#ifdef POWER10
1552 pmode->updateDbusSafeMode(false);
1553#endif
Chris Caina7b74dc2021-11-10 17:03:43 -06001554 }
1555}
1556
Chris Cain40501a22022-03-14 17:33:27 -05001557void Manager::updatePcapBounds() const
1558{
1559 if (pcap)
1560 {
1561 pcap->updatePcapBounds();
1562 }
1563}
1564
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +05301565} // namespace occ
1566} // namespace open_power