blob: c5038de334f3f64e73b4791513fcf41326d37cde [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"
Gunnar Mills94df8c92018-09-14 14:50:03 -05007#include "utils.hpp"
8
George Liub5ca1012021-09-10 12:53:11 +08009#include <phosphor-logging/elog-errors.hpp>
10#include <phosphor-logging/log.hpp>
11#include <xyz/openbmc_project/Common/error.hpp>
12
Matt Spinlerd267cec2021-09-01 14:49:19 -050013#include <chrono>
Chicago Duanbb895cb2021-06-18 19:37:16 +080014#include <cmath>
George Liubcef3b42021-09-10 12:39:02 +080015#include <filesystem>
Chris Cain36f9cde2021-11-22 11:18:21 -060016#include <fstream>
Chicago Duanbb895cb2021-06-18 19:37:16 +080017#include <regex>
Gunnar Mills94df8c92018-09-14 14:50:03 -050018
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +053019namespace open_power
20{
21namespace occ
22{
23
Matt Spinler8b8abee2021-08-25 15:18:21 -050024constexpr uint32_t fruTypeNotAvailable = 0xFF;
Matt Spinlera26f1522021-08-25 15:50:20 -050025constexpr auto fruTypeSuffix = "fru_type";
26constexpr auto faultSuffix = "fault";
27constexpr auto inputSuffix = "input";
Matt Spinlerace67d82021-10-18 13:41:57 -050028constexpr auto maxSuffix = "max";
Matt Spinler8b8abee2021-08-25 15:18:21 -050029
Chris Cain1718fd82022-02-16 16:39:50 -060030const auto HOST_ON_FILE = "/run/openbmc/host@0-on";
31
Chris Caina8857c52021-01-27 11:53:05 -060032using namespace phosphor::logging;
Chris Caina7b74dc2021-11-10 17:03:43 -060033using namespace std::literals::chrono_literals;
Chris Caina8857c52021-01-27 11:53:05 -060034
Matt Spinlera26f1522021-08-25 15:50:20 -050035template <typename T>
36T readFile(const std::string& path)
37{
38 std::ifstream ifs;
39 ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit |
40 std::ifstream::eofbit);
41 T data;
42
43 try
44 {
45 ifs.open(path);
46 ifs >> data;
47 ifs.close();
48 }
49 catch (const std::exception& e)
50 {
51 auto err = errno;
52 throw std::system_error(err, std::generic_category());
53 }
54
55 return data;
56}
57
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +053058void Manager::findAndCreateObjects()
59{
Matt Spinlerd267cec2021-09-01 14:49:19 -050060#ifndef POWER10
Deepak Kodihalli370f06b2017-10-25 04:26:07 -050061 for (auto id = 0; id < MAX_CPUS; ++id)
62 {
Deepak Kodihalli30417a12017-12-04 00:54:01 -060063 // Create one occ per cpu
64 auto occ = std::string(OCC_NAME) + std::to_string(id);
65 createObjects(occ);
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +053066 }
Matt Spinlerd267cec2021-09-01 14:49:19 -050067#else
Chris Cain1718fd82022-02-16 16:39:50 -060068 if (!fs::exists(HOST_ON_FILE))
Matt Spinlerd267cec2021-09-01 14:49:19 -050069 {
Chris Cainbae4d072022-02-28 09:46:50 -060070 static bool statusObjCreated = false;
71 if (!statusObjCreated)
Chris Cain1718fd82022-02-16 16:39:50 -060072 {
Chris Cainbae4d072022-02-28 09:46:50 -060073 // Create the OCCs based on on the /dev/occX devices
74 auto occs = findOCCsInDev();
Chris Cain1718fd82022-02-16 16:39:50 -060075
Chris Cainbae4d072022-02-28 09:46:50 -060076 if (occs.empty() || (prevOCCSearch.size() != occs.size()))
Chris Cain1718fd82022-02-16 16:39:50 -060077 {
Chris Cainbae4d072022-02-28 09:46:50 -060078 // Something changed or no OCCs yet, try again in 10s.
79 // Note on the first pass prevOCCSearch will be empty,
80 // so there will be at least one delay to give things
81 // a chance to settle.
82 prevOCCSearch = occs;
83
84 log<level::INFO>(
85 fmt::format(
86 "Manager::findAndCreateObjects(): Waiting for OCCs (currently {})",
87 occs.size())
88 .c_str());
89
90 discoverTimer->restartOnce(10s);
91 }
92 else
93 {
94 // All OCCs appear to be available, create status objects
95
96 // createObjects requires OCC0 first.
97 std::sort(occs.begin(), occs.end());
98
99 log<level::INFO>(
100 fmt::format(
101 "Manager::findAndCreateObjects(): Creating {} OCC Status Objects",
102 occs.size())
103 .c_str());
104 for (auto id : occs)
105 {
106 createObjects(std::string(OCC_NAME) + std::to_string(id));
107 }
108 statusObjCreated = true;
109 }
110 }
111
112 if (statusObjCreated)
113 {
114 static bool tracedHostWait = false;
115 if (utils::isHostRunning())
116 {
117 if (tracedHostWait)
118 {
119 log<level::INFO>(
120 "Manager::findAndCreateObjects(): Host is running");
121 tracedHostWait = false;
122 }
123 waitingForAllOccActiveSensors = true;
124 checkAllActiveSensors();
125 }
126 else
127 {
128 if (!tracedHostWait)
129 {
130 log<level::INFO>(
131 "Manager::findAndCreateObjects(): Waiting for host to start");
132 tracedHostWait = true;
133 }
134 discoverTimer->restartOnce(30s);
Chris Cain1718fd82022-02-16 16:39:50 -0600135 }
136 }
Matt Spinlerd267cec2021-09-01 14:49:19 -0500137 }
138 else
139 {
Chris Cain1718fd82022-02-16 16:39:50 -0600140 log<level::INFO>(
141 fmt::format(
142 "Manager::findAndCreateObjects(): Waiting for {} to complete...",
143 HOST_ON_FILE)
144 .c_str());
145 discoverTimer->restartOnce(10s);
Matt Spinlerd267cec2021-09-01 14:49:19 -0500146 }
147#endif
148}
149
Chris Cainbae4d072022-02-28 09:46:50 -0600150#ifdef POWER10
151// Check if all occActive sensors are available
152void Manager::checkAllActiveSensors()
153{
154 static bool allActiveSensorAvailable = false;
155 static bool tracedSensorWait = false;
156
157 // Start with the assumption that all are available
158 allActiveSensorAvailable = true;
159 for (auto& obj : statusObjects)
160 {
161 // If active sensor is already true, then no need to query sensor
162 if (!obj->occActive())
163 {
164 allActiveSensorAvailable = false;
165 if (!tracedSensorWait)
166 {
167 log<level::INFO>(
168 fmt::format(
169 "Manager::checkAllActiveSensors(): Waiting on OCC{} Active sensor",
170 obj->getOccInstanceID())
171 .c_str());
172 tracedSensorWait = true;
173 }
174 pldmHandle->checkActiveSensor(obj->getOccInstanceID());
175 break;
176 }
177 }
178
179 if (allActiveSensorAvailable)
180 {
181 // All sensors were found, disable the discovery timer
182 discoverTimer.reset();
183 waitingForAllOccActiveSensors = false;
184
185 log<level::INFO>(
186 "Manager::checkAllActiveSensors(): OCC Active sensors are available");
187 tracedSensorWait = false;
188 }
189 else
190 {
191 // Not all sensors were available, so keep waiting
192 if (!tracedSensorWait)
193 {
194 log<level::INFO>(
195 "Manager::checkAllActiveSensors(): Waiting for OCC Active sensors to become available");
196 tracedSensorWait = true;
197 }
198 discoverTimer->restartOnce(30s);
199 }
200}
201#endif
202
Matt Spinlerd267cec2021-09-01 14:49:19 -0500203std::vector<int> Manager::findOCCsInDev()
204{
205 std::vector<int> occs;
206 std::regex expr{R"(occ(\d+)$)"};
207
208 for (auto& file : fs::directory_iterator("/dev"))
209 {
210 std::smatch match;
211 std::string path{file.path().string()};
212 if (std::regex_search(path, match, expr))
213 {
214 auto num = std::stoi(match[1].str());
215
216 // /dev numbering starts at 1, ours starts at 0.
217 occs.push_back(num - 1);
218 }
219 }
220
221 return occs;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530222}
223
224int Manager::cpuCreated(sdbusplus::message::message& msg)
225{
George Liubcef3b42021-09-10 12:39:02 +0800226 namespace fs = std::filesystem;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530227
228 sdbusplus::message::object_path o;
229 msg.read(o);
230 fs::path cpuPath(std::string(std::move(o)));
231
232 auto name = cpuPath.filename().string();
233 auto index = name.find(CPU_NAME);
234 name.replace(index, std::strlen(CPU_NAME), OCC_NAME);
235
236 createObjects(name);
237
238 return 0;
239}
240
241void Manager::createObjects(const std::string& occ)
242{
243 auto path = fs::path(OCC_CONTROL_ROOT) / occ;
244
Chris Cain6fa848a2022-01-24 14:54:38 -0600245#ifdef POWER10
246 if (!pmode)
247 {
Chris Cain1be43372021-12-09 19:29:37 -0600248 // Create the power mode object
Chris Cain5d66a0a2022-02-09 08:52:10 -0600249 pmode = std::make_unique<powermode::PowerMode>(
Sheldon Baileyea2b22e2022-04-04 12:24:46 -0500250 *this, powermode::PMODE_PATH, powermode::PIPS_PATH
251#ifdef POWER10
252 ,
253 event
254#endif
255 );
Chris Cain6fa848a2022-01-24 14:54:38 -0600256 }
257#endif
258
Gunnar Mills94df8c92018-09-14 14:50:03 -0500259 statusObjects.emplace_back(std::make_unique<Status>(
George Liuf3b75142021-06-10 11:22:50 +0800260 event, path.c_str(), *this,
Chris Cain36f9cde2021-11-22 11:18:21 -0600261#ifdef POWER10
262 pmode,
263#endif
Gunnar Mills94df8c92018-09-14 14:50:03 -0500264 std::bind(std::mem_fn(&Manager::statusCallBack), this,
Sheldon Bailey373af752022-02-21 15:14:00 -0600265 std::placeholders::_1, std::placeholders::_2)
Tom Joseph00325232020-07-29 17:51:48 +0530266#ifdef PLDM
267 ,
268 std::bind(std::mem_fn(&pldm::Interface::resetOCC), pldmHandle.get(),
269 std::placeholders::_1)
270#endif
271 ));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530272
Chris Cain40501a22022-03-14 17:33:27 -0500273 // Create the power cap monitor object
274 if (!pcap)
275 {
276 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
277 *statusObjects.back());
278 }
279
Chris Cain36f9cde2021-11-22 11:18:21 -0600280 if (statusObjects.back()->isMasterOcc())
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530281 {
Chris Cain36f9cde2021-11-22 11:18:21 -0600282 log<level::INFO>(
283 fmt::format("Manager::createObjects(): OCC{} is the master",
284 statusObjects.back()->getOccInstanceID())
285 .c_str());
286 _pollTimer->setEnabled(false);
287
Chris Cain78e86012021-03-04 16:15:31 -0600288#ifdef POWER10
Chris Cain6fa848a2022-01-24 14:54:38 -0600289 // Set the master OCC on the PowerMode object
290 pmode->setMasterOcc(path);
Chris Cain78e86012021-03-04 16:15:31 -0600291#endif
Chris Cain36f9cde2021-11-22 11:18:21 -0600292 }
293
294 passThroughObjects.emplace_back(std::make_unique<PassThrough>(path.c_str()
295#ifdef POWER10
296 ,
297 pmode
298#endif
299 ));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530300}
301
Sheldon Bailey373af752022-02-21 15:14:00 -0600302void Manager::statusCallBack(instanceID instance, bool status)
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530303{
Gunnar Mills94df8c92018-09-14 14:50:03 -0500304 using InternalFailure =
305 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530306
307 // At this time, it won't happen but keeping it
308 // here just in case something changes in the future
309 if ((activeCount == 0) && (!status))
310 {
Sheldon Bailey373af752022-02-21 15:14:00 -0600311 log<level::ERR>(
312 fmt::format("Invalid update on OCCActive with OCC{}", instance)
313 .c_str());
314
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530315 elog<InternalFailure>();
316 }
317
Chris Caina7b74dc2021-11-10 17:03:43 -0600318 if (status == true)
Eddie Jamesdae2d942017-12-20 10:50:03 -0600319 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600320 // OCC went active
321 ++activeCount;
322
323#ifdef POWER10
324 if (activeCount == 1)
Eddie Jamesdae2d942017-12-20 10:50:03 -0600325 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600326 // First OCC went active (allow some time for all OCCs to go active)
327 waitForAllOccsTimer->restartOnce(30s);
Matt Spinler53f68142021-08-25 15:47:31 -0500328 }
329#endif
Chris Caina7b74dc2021-11-10 17:03:43 -0600330
331 if (activeCount == statusObjects.size())
332 {
333#ifdef POWER10
334 // All OCCs are now running
335 if (waitForAllOccsTimer->isEnabled())
336 {
337 // stop occ wait timer
338 waitForAllOccsTimer->setEnabled(false);
339 }
340#endif
341
342 // Verify master OCC and start presence monitor
343 validateOccMaster();
344 }
345
346 // Start poll timer if not already started
347 if (!_pollTimer->isEnabled())
348 {
349 log<level::INFO>(
Chris Cain36f9cde2021-11-22 11:18:21 -0600350 fmt::format("Manager: OCCs will be polled every {} seconds",
351 pollInterval)
Chris Caina7b74dc2021-11-10 17:03:43 -0600352 .c_str());
353
354 // Send poll and start OCC poll timer
355 pollerTimerExpired();
356 }
357 }
358 else
359 {
360 // OCC went away
361 --activeCount;
362
363 if (activeCount == 0)
364 {
365 // No OCCs are running
366
367 // Stop OCC poll timer
368 if (_pollTimer->isEnabled())
369 {
370 log<level::INFO>(
371 "Manager::statusCallBack(): OCCs are not running, stopping poll timer");
372 _pollTimer->setEnabled(false);
373 }
374
375#ifdef POWER10
376 // stop wait timer
377 if (waitForAllOccsTimer->isEnabled())
378 {
379 waitForAllOccsTimer->setEnabled(false);
380 }
381#endif
Chris Caina7b74dc2021-11-10 17:03:43 -0600382 }
Sheldon Bailey373af752022-02-21 15:14:00 -0600383#ifdef READ_OCC_SENSORS
384 // Clear OCC sensors
385 setSensorValueToNonFunctional(instance);
386#endif
Chris Caina8857c52021-01-27 11:53:05 -0600387 }
Chris Cainbae4d072022-02-28 09:46:50 -0600388
389#ifdef POWER10
390 if (waitingForAllOccActiveSensors)
391 {
392 checkAllActiveSensors();
393 }
394#endif
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530395}
396
397#ifdef I2C_OCC
398void Manager::initStatusObjects()
399{
400 // Make sure we have a valid path string
401 static_assert(sizeof(DEV_PATH) != 0);
402
403 auto deviceNames = i2c_occ::getOccHwmonDevices(DEV_PATH);
404 for (auto& name : deviceNames)
405 {
406 i2c_occ::i2cToDbus(name);
Lei YUb5259a12017-09-01 16:22:40 +0800407 name = std::string(OCC_NAME) + '_' + name;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530408 auto path = fs::path(OCC_CONTROL_ROOT) / name;
409 statusObjects.emplace_back(
George Liuf3b75142021-06-10 11:22:50 +0800410 std::make_unique<Status>(event, path.c_str(), *this));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530411 }
Chris Cain40501a22022-03-14 17:33:27 -0500412 // The first device is master occ
413 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
414 *statusObjects.front());
Chris Cain78e86012021-03-04 16:15:31 -0600415#ifdef POWER10
Chris Cain5d66a0a2022-02-09 08:52:10 -0600416 pmode = std::make_unique<powermode::PowerMode>(*this, powermode::PMODE_PATH,
417 powermode::PIPS_PATH);
Chris Cain6fa848a2022-01-24 14:54:38 -0600418 // Set the master OCC on the PowerMode object
419 pmode->setMasterOcc(path);
Chris Cain78e86012021-03-04 16:15:31 -0600420#endif
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530421}
422#endif
423
Tom Joseph815f9f52020-07-27 12:12:13 +0530424#ifdef PLDM
Eddie Jamescbad2192021-10-07 09:39:39 -0500425void Manager::sbeTimeout(unsigned int instance)
426{
Eddie James2a751d72022-03-04 09:16:12 -0600427 auto obj = std::find_if(statusObjects.begin(), statusObjects.end(),
428 [instance](const auto& obj) {
429 return instance == obj->getOccInstanceID();
430 });
Eddie Jamescbad2192021-10-07 09:39:39 -0500431
Eddie Jamescb018da2022-03-05 11:49:37 -0600432 if (obj != statusObjects.end() && (*obj)->occActive())
Eddie James2a751d72022-03-04 09:16:12 -0600433 {
Chris Cainbae4d072022-02-28 09:46:50 -0600434 log<level::INFO>(
435 fmt::format("SBE timeout, requesting HRESET (OCC{})", instance)
436 .c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500437
Eddie James2a751d72022-03-04 09:16:12 -0600438 setSBEState(instance, SBE_STATE_NOT_USABLE);
439
440 pldmHandle->sendHRESET(instance);
441 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500442}
443
Tom Joseph815f9f52020-07-27 12:12:13 +0530444bool Manager::updateOCCActive(instanceID instance, bool status)
445{
Chris Cain7e374fb2022-04-07 09:47:23 -0500446 auto obj = std::find_if(statusObjects.begin(), statusObjects.end(),
447 [instance](const auto& obj) {
448 return instance == obj->getOccInstanceID();
449 });
450
451 if (obj != statusObjects.end())
452 {
453 return (*obj)->occActive(status);
454 }
455 else
456 {
457 log<level::WARNING>(
458 fmt::format(
459 "Manager::updateOCCActive: No status object to update for OCC{} (active={})",
460 instance, status)
461 .c_str());
462 return false;
463 }
Tom Joseph815f9f52020-07-27 12:12:13 +0530464}
Eddie Jamescbad2192021-10-07 09:39:39 -0500465
466void Manager::sbeHRESETResult(instanceID instance, bool success)
467{
468 if (success)
469 {
Chris Cainbae4d072022-02-28 09:46:50 -0600470 log<level::INFO>(
471 fmt::format("HRESET succeeded (OCC{})", instance).c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500472
473 setSBEState(instance, SBE_STATE_BOOTED);
474
475 return;
476 }
477
478 setSBEState(instance, SBE_STATE_FAILED);
479
480 if (sbeCanDump(instance))
481 {
Chris Cainbae4d072022-02-28 09:46:50 -0600482 log<level::INFO>(
483 fmt::format("HRESET failed (OCC{}), triggering SBE dump", instance)
484 .c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500485
486 auto& bus = utils::getBus();
487 uint32_t src6 = instance << 16;
488 uint32_t logId =
489 FFDC::createPEL("org.open_power.Processor.Error.SbeChipOpTimeout",
490 src6, "SBE command timeout");
491
492 try
493 {
George Liuf3a4a692021-12-28 13:59:51 +0800494 constexpr auto path = "/org/openpower/dump";
495 constexpr auto interface = "xyz.openbmc_project.Dump.Create";
496 constexpr auto function = "CreateDump";
497
Eddie Jamescbad2192021-10-07 09:39:39 -0500498 std::string service = utils::getService(path, interface);
499 auto method =
500 bus.new_method_call(service.c_str(), path, interface, function);
501
502 std::map<std::string, std::variant<std::string, uint64_t>>
503 createParams{
504 {"com.ibm.Dump.Create.CreateParameters.ErrorLogId",
505 uint64_t(logId)},
506 {"com.ibm.Dump.Create.CreateParameters.DumpType",
507 "com.ibm.Dump.Create.DumpType.SBE"},
508 {"com.ibm.Dump.Create.CreateParameters.FailingUnitId",
509 uint64_t(instance)},
510 };
511
512 method.append(createParams);
513
514 auto response = bus.call(method);
515 }
516 catch (const sdbusplus::exception::exception& e)
517 {
518 constexpr auto ERROR_DUMP_DISABLED =
519 "xyz.openbmc_project.Dump.Create.Error.Disabled";
520 if (e.name() == ERROR_DUMP_DISABLED)
521 {
522 log<level::INFO>("Dump is disabled, skipping");
523 }
524 else
525 {
526 log<level::ERR>("Dump failed");
527 }
528 }
529 }
530}
531
532bool Manager::sbeCanDump(unsigned int instance)
533{
534 struct pdbg_target* proc = getPdbgTarget(instance);
535
536 if (!proc)
537 {
538 // allow the dump in the error case
539 return true;
540 }
541
542 try
543 {
544 if (!openpower::phal::sbe::isDumpAllowed(proc))
545 {
546 return false;
547 }
548
549 if (openpower::phal::pdbg::isSbeVitalAttnActive(proc))
550 {
551 return false;
552 }
553 }
554 catch (openpower::phal::exception::SbeError& e)
555 {
556 log<level::INFO>("Failed to query SBE state");
557 }
558
559 // allow the dump in the error case
560 return true;
561}
562
563void Manager::setSBEState(unsigned int instance, enum sbe_state state)
564{
565 struct pdbg_target* proc = getPdbgTarget(instance);
566
567 if (!proc)
568 {
569 return;
570 }
571
572 try
573 {
574 openpower::phal::sbe::setState(proc, state);
575 }
576 catch (const openpower::phal::exception::SbeError& e)
577 {
578 log<level::ERR>("Failed to set SBE state");
579 }
580}
581
582struct pdbg_target* Manager::getPdbgTarget(unsigned int instance)
583{
584 if (!pdbgInitialized)
585 {
586 try
587 {
588 openpower::phal::pdbg::init();
589 pdbgInitialized = true;
590 }
591 catch (const openpower::phal::exception::PdbgError& e)
592 {
593 log<level::ERR>("pdbg initialization failed");
594 return nullptr;
595 }
596 }
597
598 struct pdbg_target* proc = nullptr;
599 pdbg_for_each_class_target("proc", proc)
600 {
601 if (pdbg_target_index(proc) == instance)
602 {
603 return proc;
604 }
605 }
606
607 log<level::ERR>("Failed to get pdbg target");
608 return nullptr;
609}
Tom Joseph815f9f52020-07-27 12:12:13 +0530610#endif
611
Chris Caina8857c52021-01-27 11:53:05 -0600612void Manager::pollerTimerExpired()
613{
Chris Caina8857c52021-01-27 11:53:05 -0600614 if (!_pollTimer)
615 {
616 log<level::ERR>(
617 "Manager::pollerTimerExpired() ERROR: Timer not defined");
618 return;
619 }
620
621 for (auto& obj : statusObjects)
622 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600623 if (!obj->occActive())
624 {
625 // OCC is not running yet
626#ifdef READ_OCC_SENSORS
Chris Cain5d66a0a2022-02-09 08:52:10 -0600627 auto id = obj->getOccInstanceID();
Sheldon Bailey373af752022-02-21 15:14:00 -0600628 setSensorValueToNonFunctional(id);
Chris Caina7b74dc2021-11-10 17:03:43 -0600629#endif
630 continue;
631 }
632
Chris Caina8857c52021-01-27 11:53:05 -0600633 // Read sysfs to force kernel to poll OCC
634 obj->readOccState();
Chicago Duanbb895cb2021-06-18 19:37:16 +0800635
636#ifdef READ_OCC_SENSORS
637 // Read occ sensor values
Chris Cain5d66a0a2022-02-09 08:52:10 -0600638 getSensorValues(obj);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800639#endif
Chris Caina8857c52021-01-27 11:53:05 -0600640 }
641
Chris Caina7b74dc2021-11-10 17:03:43 -0600642 if (activeCount > 0)
643 {
644 // Restart OCC poll timer
645 _pollTimer->restartOnce(std::chrono::seconds(pollInterval));
646 }
647 else
648 {
649 // No OCCs running, so poll timer will not be restarted
650 log<level::INFO>(
651 fmt::format(
652 "Manager::pollerTimerExpired: poll timer will not be restarted")
653 .c_str());
654 }
Chris Caina8857c52021-01-27 11:53:05 -0600655}
656
Chicago Duanbb895cb2021-06-18 19:37:16 +0800657#ifdef READ_OCC_SENSORS
658void Manager::readTempSensors(const fs::path& path, uint32_t id)
659{
Chicago Duanbb895cb2021-06-18 19:37:16 +0800660 std::regex expr{"temp\\d+_label$"}; // Example: temp5_label
661 for (auto& file : fs::directory_iterator(path))
662 {
663 if (!std::regex_search(file.path().string(), expr))
664 {
665 continue;
666 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800667
Matt Spinlera26f1522021-08-25 15:50:20 -0500668 uint32_t labelValue{0};
669
670 try
671 {
672 labelValue = readFile<uint32_t>(file.path());
673 }
674 catch (const std::system_error& e)
675 {
676 log<level::DEBUG>(
677 fmt::format("readTempSensors: Failed reading {}, errno = {}",
678 file.path().string(), e.code().value())
679 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800680 continue;
681 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800682
683 const std::string& tempLabel = "label";
684 const std::string filePathString = file.path().string().substr(
685 0, file.path().string().length() - tempLabel.length());
Matt Spinlera26f1522021-08-25 15:50:20 -0500686
687 uint32_t fruTypeValue{0};
688 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800689 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500690 fruTypeValue = readFile<uint32_t>(filePathString + fruTypeSuffix);
691 }
692 catch (const std::system_error& e)
693 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800694 log<level::DEBUG>(
Matt Spinlera26f1522021-08-25 15:50:20 -0500695 fmt::format("readTempSensors: Failed reading {}, errno = {}",
696 filePathString + fruTypeSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +0800697 .c_str());
698 continue;
699 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800700
701 std::string sensorPath =
702 OCC_SENSORS_ROOT + std::string("/temperature/");
703
Matt Spinlerace67d82021-10-18 13:41:57 -0500704 std::string dvfsTempPath;
705
Chicago Duanbb895cb2021-06-18 19:37:16 +0800706 if (fruTypeValue == VRMVdd)
707 {
708 sensorPath.append("vrm_vdd" + std::to_string(id) + "_temp");
709 }
Matt Spinlerace67d82021-10-18 13:41:57 -0500710 else if (fruTypeValue == processorIoRing)
711 {
712 sensorPath.append("proc" + std::to_string(id) + "_ioring_temp");
713 dvfsTempPath = std::string{OCC_SENSORS_ROOT} + "/temperature/proc" +
714 std::to_string(id) + "_ioring_dvfs_temp";
715 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800716 else
717 {
Matt Spinler14d14022021-08-25 15:38:29 -0500718 uint16_t type = (labelValue & 0xFF000000) >> 24;
719 uint16_t instanceID = labelValue & 0x0000FFFF;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800720
721 if (type == OCC_DIMM_TEMP_SENSOR_TYPE)
722 {
Matt Spinler8b8abee2021-08-25 15:18:21 -0500723 if (fruTypeValue == fruTypeNotAvailable)
724 {
725 // Not all DIMM related temps are available to read
726 // (no _input file in this case)
727 continue;
728 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800729 auto iter = dimmTempSensorName.find(fruTypeValue);
730 if (iter == dimmTempSensorName.end())
731 {
George Liub5ca1012021-09-10 12:53:11 +0800732 log<level::ERR>(
733 fmt::format(
734 "readTempSensors: Fru type error! fruTypeValue = {}) ",
735 fruTypeValue)
736 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800737 continue;
738 }
739
740 sensorPath.append("dimm" + std::to_string(instanceID) +
741 iter->second);
742 }
743 else if (type == OCC_CPU_TEMP_SENSOR_TYPE)
744 {
Matt Spinlerace67d82021-10-18 13:41:57 -0500745 if (fruTypeValue == processorCore)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800746 {
Matt Spinlerace67d82021-10-18 13:41:57 -0500747 // The OCC reports small core temps, of which there are
748 // two per big core. All current P10 systems are in big
749 // core mode, so use a big core name.
750 uint16_t coreNum = instanceID / 2;
751 uint16_t tempNum = instanceID % 2;
752 sensorPath.append("proc" + std::to_string(id) + "_core" +
753 std::to_string(coreNum) + "_" +
754 std::to_string(tempNum) + "_temp");
755
756 dvfsTempPath = std::string{OCC_SENSORS_ROOT} +
757 "/temperature/proc" + std::to_string(id) +
758 "_core_dvfs_temp";
759 }
760 else
761 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800762 continue;
763 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800764 }
765 else
766 {
767 continue;
768 }
769 }
770
Matt Spinlerace67d82021-10-18 13:41:57 -0500771 // The dvfs temp file only needs to be read once per chip per type.
772 if (!dvfsTempPath.empty() &&
773 !dbus::OccDBusSensors::getOccDBus().hasDvfsTemp(dvfsTempPath))
774 {
775 try
776 {
777 auto dvfsValue = readFile<double>(filePathString + maxSuffix);
778
779 dbus::OccDBusSensors::getOccDBus().setDvfsTemp(
780 dvfsTempPath, dvfsValue * std::pow(10, -3));
781 }
782 catch (const std::system_error& e)
783 {
784 log<level::DEBUG>(
785 fmt::format(
786 "readTempSensors: Failed reading {}, errno = {}",
787 filePathString + maxSuffix, e.code().value())
788 .c_str());
789 }
790 }
791
Matt Spinlera26f1522021-08-25 15:50:20 -0500792 uint32_t faultValue{0};
793 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800794 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500795 faultValue = readFile<uint32_t>(filePathString + faultSuffix);
796 }
797 catch (const std::system_error& e)
798 {
799 log<level::DEBUG>(
800 fmt::format("readTempSensors: Failed reading {}, errno = {}",
801 filePathString + faultSuffix, e.code().value())
802 .c_str());
803 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800804 }
805
Matt Spinlera26f1522021-08-25 15:50:20 -0500806 if (faultValue != 0)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800807 {
Chris Cain5d66a0a2022-02-09 08:52:10 -0600808 dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -0500809 sensorPath, std::numeric_limits<double>::quiet_NaN());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800810
Chris Cain5d66a0a2022-02-09 08:52:10 -0600811 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
812 false);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800813
Matt Spinlera26f1522021-08-25 15:50:20 -0500814 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800815 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500816
817 double tempValue{0};
818
819 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800820 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500821 tempValue = readFile<double>(filePathString + inputSuffix);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800822 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500823 catch (const std::system_error& e)
824 {
825 log<level::DEBUG>(
826 fmt::format("readTempSensors: Failed reading {}, errno = {}",
827 filePathString + inputSuffix, e.code().value())
828 .c_str());
829 continue;
830 }
831
Chris Cain5d66a0a2022-02-09 08:52:10 -0600832 dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -0500833 sensorPath, tempValue * std::pow(10, -3));
834
Chris Cain5d66a0a2022-02-09 08:52:10 -0600835 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
836 true);
Matt Spinlera26f1522021-08-25 15:50:20 -0500837
Chris Cain6fa848a2022-01-24 14:54:38 -0600838 // At this point, the sensor will be created for sure.
839 if (existingSensors.find(sensorPath) == existingSensors.end())
840 {
Chris Cain5d66a0a2022-02-09 08:52:10 -0600841 dbus::OccDBusSensors::getOccDBus().setChassisAssociation(
842 sensorPath);
Chris Cain6fa848a2022-01-24 14:54:38 -0600843 }
844
Matt Spinlera26f1522021-08-25 15:50:20 -0500845 existingSensors[sensorPath] = id;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800846 }
847 return;
848}
849
850std::optional<std::string>
851 Manager::getPowerLabelFunctionID(const std::string& value)
852{
853 // If the value is "system", then the FunctionID is "system".
854 if (value == "system")
855 {
856 return value;
857 }
858
859 // If the value is not "system", then the label value have 3 numbers, of
860 // which we only care about the middle one:
861 // <sensor id>_<function id>_<apss channel>
862 // eg: The value is "0_10_5" , then the FunctionID is "10".
863 if (value.find("_") == std::string::npos)
864 {
865 return std::nullopt;
866 }
867
868 auto powerLabelValue = value.substr((value.find("_") + 1));
869
870 if (powerLabelValue.find("_") == std::string::npos)
871 {
872 return std::nullopt;
873 }
874
875 return powerLabelValue.substr(0, powerLabelValue.find("_"));
876}
877
878void Manager::readPowerSensors(const fs::path& path, uint32_t id)
879{
Chicago Duanbb895cb2021-06-18 19:37:16 +0800880 std::regex expr{"power\\d+_label$"}; // Example: power5_label
881 for (auto& file : fs::directory_iterator(path))
882 {
883 if (!std::regex_search(file.path().string(), expr))
884 {
885 continue;
886 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800887
Matt Spinlera26f1522021-08-25 15:50:20 -0500888 std::string labelValue;
889 try
890 {
891 labelValue = readFile<std::string>(file.path());
892 }
893 catch (const std::system_error& e)
894 {
895 log<level::DEBUG>(
896 fmt::format("readPowerSensors: Failed reading {}, errno = {}",
897 file.path().string(), e.code().value())
898 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800899 continue;
900 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800901
902 auto functionID = getPowerLabelFunctionID(labelValue);
903 if (functionID == std::nullopt)
904 {
905 continue;
906 }
907
908 const std::string& tempLabel = "label";
909 const std::string filePathString = file.path().string().substr(
910 0, file.path().string().length() - tempLabel.length());
911
912 std::string sensorPath = OCC_SENSORS_ROOT + std::string("/power/");
913
914 auto iter = powerSensorName.find(*functionID);
915 if (iter == powerSensorName.end())
916 {
917 continue;
918 }
919 sensorPath.append(iter->second);
920
Matt Spinlera26f1522021-08-25 15:50:20 -0500921 double tempValue{0};
922
923 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800924 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500925 tempValue = readFile<double>(filePathString + inputSuffix);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800926 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500927 catch (const std::system_error& e)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800928 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800929 log<level::DEBUG>(
Chris Cain5d66a0a2022-02-09 08:52:10 -0600930 fmt::format("readPowerSensors: Failed reading {}, errno = {}",
Matt Spinlera26f1522021-08-25 15:50:20 -0500931 filePathString + inputSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +0800932 .c_str());
Matt Spinlera26f1522021-08-25 15:50:20 -0500933 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800934 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500935
Chris Cain5d66a0a2022-02-09 08:52:10 -0600936 dbus::OccDBusSensors::getOccDBus().setUnit(
Chris Caind84a8332022-01-13 08:58:45 -0600937 sensorPath, "xyz.openbmc_project.Sensor.Value.Unit.Watts");
938
Chris Cain5d66a0a2022-02-09 08:52:10 -0600939 dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -0500940 sensorPath, tempValue * std::pow(10, -3) * std::pow(10, -3));
941
Chris Cain5d66a0a2022-02-09 08:52:10 -0600942 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
943 true);
Matt Spinlera26f1522021-08-25 15:50:20 -0500944
Matt Spinler5901abd2021-09-23 13:50:03 -0500945 if (existingSensors.find(sensorPath) == existingSensors.end())
946 {
Chris Cain5d66a0a2022-02-09 08:52:10 -0600947 dbus::OccDBusSensors::getOccDBus().setChassisAssociation(
948 sensorPath);
Matt Spinler5901abd2021-09-23 13:50:03 -0500949 }
950
Matt Spinlera26f1522021-08-25 15:50:20 -0500951 existingSensors[sensorPath] = id;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800952 }
953 return;
954}
955
956void Manager::setSensorValueToNaN(uint32_t id)
957{
958 for (const auto& [sensorPath, occId] : existingSensors)
959 {
960 if (occId == id)
961 {
Chris Cain5d66a0a2022-02-09 08:52:10 -0600962 dbus::OccDBusSensors::getOccDBus().setValue(
Chicago Duanbb895cb2021-06-18 19:37:16 +0800963 sensorPath, std::numeric_limits<double>::quiet_NaN());
964 }
965 }
966 return;
967}
968
Sheldon Bailey373af752022-02-21 15:14:00 -0600969void Manager::setSensorValueToNonFunctional(uint32_t id) const
970{
971 for (const auto& [sensorPath, occId] : existingSensors)
972 {
973 if (occId == id)
974 {
975 dbus::OccDBusSensors::getOccDBus().setValue(
976 sensorPath, std::numeric_limits<double>::quiet_NaN());
977
978 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
979 false);
980 }
981 }
982 return;
983}
984
Chris Cain5d66a0a2022-02-09 08:52:10 -0600985void Manager::getSensorValues(std::unique_ptr<Status>& occ)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800986{
Chris Caine2d0a432022-03-28 11:08:49 -0500987 static bool tracedError[8] = {0};
988 const fs::path sensorPath = occ->getHwmonPath();
Chris Cain5d66a0a2022-02-09 08:52:10 -0600989 const uint32_t id = occ->getOccInstanceID();
Chicago Duanbb895cb2021-06-18 19:37:16 +0800990
Chris Caine2d0a432022-03-28 11:08:49 -0500991 if (fs::exists(sensorPath))
Chicago Duanbb895cb2021-06-18 19:37:16 +0800992 {
Chris Caine2d0a432022-03-28 11:08:49 -0500993 // Read temperature sensors
994 readTempSensors(sensorPath, id);
995
996 if (occ->isMasterOcc())
997 {
998 // Read power sensors
999 readPowerSensors(sensorPath, id);
1000 }
1001 tracedError[id] = false;
1002 }
1003 else
1004 {
1005 if (!tracedError[id])
1006 {
1007 log<level::ERR>(
1008 fmt::format(
1009 "Manager::getSensorValues: OCC{} sensor path missing: {}",
1010 id, sensorPath.c_str())
1011 .c_str());
1012 tracedError[id] = true;
1013 }
Chicago Duanbb895cb2021-06-18 19:37:16 +08001014 }
1015
1016 return;
1017}
1018#endif
Chris Cain17257672021-10-22 13:41:03 -05001019
1020// Read the altitude from DBus
1021void Manager::readAltitude()
1022{
1023 static bool traceAltitudeErr = true;
1024
1025 utils::PropertyValue altitudeProperty{};
1026 try
1027 {
1028 altitudeProperty = utils::getProperty(ALTITUDE_PATH, ALTITUDE_INTERFACE,
1029 ALTITUDE_PROP);
1030 auto sensorVal = std::get<double>(altitudeProperty);
1031 if (sensorVal < 0xFFFF)
1032 {
1033 if (sensorVal < 0)
1034 {
1035 altitude = 0;
1036 }
1037 else
1038 {
1039 // Round to nearest meter
1040 altitude = uint16_t(sensorVal + 0.5);
1041 }
1042 log<level::DEBUG>(fmt::format("readAltitude: sensor={} ({}m)",
1043 sensorVal, altitude)
1044 .c_str());
1045 traceAltitudeErr = true;
1046 }
1047 else
1048 {
1049 if (traceAltitudeErr)
1050 {
1051 traceAltitudeErr = false;
1052 log<level::DEBUG>(
1053 fmt::format("Invalid altitude value: {}", sensorVal)
1054 .c_str());
1055 }
1056 }
1057 }
1058 catch (const sdbusplus::exception::exception& e)
1059 {
1060 if (traceAltitudeErr)
1061 {
1062 traceAltitudeErr = false;
1063 log<level::INFO>(
1064 fmt::format("Unable to read Altitude: {}", e.what()).c_str());
1065 }
1066 altitude = 0xFFFF; // not available
1067 }
1068}
1069
1070// Callback function when ambient temperature changes
1071void Manager::ambientCallback(sdbusplus::message::message& msg)
1072{
1073 double currentTemp = 0;
1074 uint8_t truncatedTemp = 0xFF;
1075 std::string msgSensor;
1076 std::map<std::string, std::variant<double>> msgData;
1077 msg.read(msgSensor, msgData);
1078
1079 auto valPropMap = msgData.find(AMBIENT_PROP);
1080 if (valPropMap == msgData.end())
1081 {
1082 log<level::DEBUG>("ambientCallback: Unknown ambient property changed");
1083 return;
1084 }
1085 currentTemp = std::get<double>(valPropMap->second);
1086 if (std::isnan(currentTemp))
1087 {
1088 truncatedTemp = 0xFF;
1089 }
1090 else
1091 {
1092 if (currentTemp < 0)
1093 {
1094 truncatedTemp = 0;
1095 }
1096 else
1097 {
1098 // Round to nearest degree C
1099 truncatedTemp = uint8_t(currentTemp + 0.5);
1100 }
1101 }
1102
1103 // If ambient changes, notify OCCs
1104 if (truncatedTemp != ambient)
1105 {
1106 log<level::DEBUG>(
1107 fmt::format("ambientCallback: Ambient change from {} to {}C",
1108 ambient, currentTemp)
1109 .c_str());
1110
1111 ambient = truncatedTemp;
1112 if (altitude == 0xFFFF)
1113 {
1114 // No altitude yet, try reading again
1115 readAltitude();
1116 }
1117
1118 log<level::DEBUG>(
1119 fmt::format("ambientCallback: Ambient: {}C, altitude: {}m", ambient,
1120 altitude)
1121 .c_str());
1122#ifdef POWER10
1123 // Send ambient and altitude to all OCCs
1124 for (auto& obj : statusObjects)
1125 {
1126 if (obj->occActive())
1127 {
1128 obj->sendAmbient(ambient, altitude);
1129 }
1130 }
1131#endif // POWER10
1132 }
1133}
1134
1135// return the current ambient and altitude readings
1136void Manager::getAmbientData(bool& ambientValid, uint8_t& ambientTemp,
1137 uint16_t& altitudeValue) const
1138{
1139 ambientValid = true;
1140 ambientTemp = ambient;
1141 altitudeValue = altitude;
1142
1143 if (ambient == 0xFF)
1144 {
1145 ambientValid = false;
1146 }
1147}
1148
Chris Caina7b74dc2021-11-10 17:03:43 -06001149#ifdef POWER10
1150void Manager::occsNotAllRunning()
1151{
Chris Cain6fa848a2022-01-24 14:54:38 -06001152 // Function will also gets called when occ-control app gets
1153 // restarted. (occ active sensors do not change, so the Status
1154 // object does not call Manager back for all OCCs)
Chris Caina7b74dc2021-11-10 17:03:43 -06001155
1156 if (activeCount != statusObjects.size())
1157 {
1158 // Not all OCCs went active
1159 log<level::WARNING>(
1160 fmt::format(
1161 "occsNotAllRunning: Active OCC count ({}) does not match expected count ({})",
1162 activeCount, statusObjects.size())
1163 .c_str());
1164 // Procs may be garded, so may not need reset.
1165 }
1166
1167 validateOccMaster();
1168}
1169#endif // POWER10
1170
1171// Verify single master OCC and start presence monitor
1172void Manager::validateOccMaster()
1173{
1174 int masterInstance = -1;
1175 for (auto& obj : statusObjects)
1176 {
Chris Cainbae4d072022-02-28 09:46:50 -06001177#ifdef POWER10
1178 if (!obj->occActive())
1179 {
1180 if (utils::isHostRunning())
1181 {
1182 // OCC does not appear to be active yet, check active sensor
1183 pldmHandle->checkActiveSensor(obj->getOccInstanceID());
1184 if (obj->occActive())
1185 {
1186 log<level::INFO>(
1187 fmt::format(
1188 "validateOccMaster: OCC{} is ACTIVE after reading sensor",
1189 obj->getOccInstanceID())
1190 .c_str());
1191 }
1192 }
1193 else
1194 {
1195 log<level::WARNING>(
1196 fmt::format(
1197 "validateOccMaster: HOST is not running (OCC{})",
1198 obj->getOccInstanceID())
1199 .c_str());
1200 return;
1201 }
1202 }
1203#endif // POWER10
1204
Chris Caina7b74dc2021-11-10 17:03:43 -06001205 if (obj->isMasterOcc())
1206 {
Chris Cain5d66a0a2022-02-09 08:52:10 -06001207 obj->addPresenceWatchMaster();
1208
Chris Caina7b74dc2021-11-10 17:03:43 -06001209 if (masterInstance == -1)
1210 {
1211 masterInstance = obj->getOccInstanceID();
1212 }
1213 else
1214 {
1215 log<level::ERR>(
1216 fmt::format(
1217 "validateOccMaster: Multiple OCC masters! ({} and {})",
1218 masterInstance, obj->getOccInstanceID())
1219 .c_str());
1220 // request reset
1221 obj->deviceError();
1222 }
1223 }
1224 }
Chris Cainbae4d072022-02-28 09:46:50 -06001225
Chris Caina7b74dc2021-11-10 17:03:43 -06001226 if (masterInstance < 0)
1227 {
Chris Cainbae4d072022-02-28 09:46:50 -06001228 log<level::ERR>(
1229 fmt::format("validateOccMaster: Master OCC not found! (of {} OCCs)",
1230 statusObjects.size())
1231 .c_str());
Chris Caina7b74dc2021-11-10 17:03:43 -06001232 // request reset
1233 statusObjects.front()->deviceError();
1234 }
1235 else
1236 {
1237 log<level::INFO>(
Chris Cain36f9cde2021-11-22 11:18:21 -06001238 fmt::format("validateOccMaster: OCC{} is master of {} OCCs",
1239 masterInstance, activeCount)
Chris Caina7b74dc2021-11-10 17:03:43 -06001240 .c_str());
1241 }
1242}
1243
Chris Cain40501a22022-03-14 17:33:27 -05001244void Manager::updatePcapBounds() const
1245{
1246 if (pcap)
1247 {
1248 pcap->updatePcapBounds();
1249 }
1250}
1251
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +05301252} // namespace occ
1253} // namespace open_power