blob: e621a21a48120146e2ecb6c56e5d3b6b9de01ea0 [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>(
Chris Cain1be43372021-12-09 19:29:37 -0600250 *this, powermode::PMODE_PATH, powermode::PIPS_PATH);
Chris Cain6fa848a2022-01-24 14:54:38 -0600251 }
252#endif
253
Gunnar Mills94df8c92018-09-14 14:50:03 -0500254 statusObjects.emplace_back(std::make_unique<Status>(
George Liuf3b75142021-06-10 11:22:50 +0800255 event, path.c_str(), *this,
Chris Cain36f9cde2021-11-22 11:18:21 -0600256#ifdef POWER10
257 pmode,
258#endif
Gunnar Mills94df8c92018-09-14 14:50:03 -0500259 std::bind(std::mem_fn(&Manager::statusCallBack), this,
Sheldon Bailey373af752022-02-21 15:14:00 -0600260 std::placeholders::_1, std::placeholders::_2)
Tom Joseph00325232020-07-29 17:51:48 +0530261#ifdef PLDM
262 ,
263 std::bind(std::mem_fn(&pldm::Interface::resetOCC), pldmHandle.get(),
264 std::placeholders::_1)
265#endif
266 ));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530267
Chris Cain40501a22022-03-14 17:33:27 -0500268 // Create the power cap monitor object
269 if (!pcap)
270 {
271 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
272 *statusObjects.back());
273 }
274
Chris Cain36f9cde2021-11-22 11:18:21 -0600275 if (statusObjects.back()->isMasterOcc())
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530276 {
Chris Cain36f9cde2021-11-22 11:18:21 -0600277 log<level::INFO>(
278 fmt::format("Manager::createObjects(): OCC{} is the master",
279 statusObjects.back()->getOccInstanceID())
280 .c_str());
281 _pollTimer->setEnabled(false);
282
Chris Cain78e86012021-03-04 16:15:31 -0600283#ifdef POWER10
Chris Cain6fa848a2022-01-24 14:54:38 -0600284 // Set the master OCC on the PowerMode object
285 pmode->setMasterOcc(path);
Chris Cain40501a22022-03-14 17:33:27 -0500286 // Update power cap bounds
287 pcap->updatePcapBounds();
Chris Cain78e86012021-03-04 16:15:31 -0600288#endif
Chris Cain36f9cde2021-11-22 11:18:21 -0600289 }
290
291 passThroughObjects.emplace_back(std::make_unique<PassThrough>(path.c_str()
292#ifdef POWER10
293 ,
294 pmode
295#endif
296 ));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530297}
298
Sheldon Bailey373af752022-02-21 15:14:00 -0600299void Manager::statusCallBack(instanceID instance, bool status)
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530300{
Gunnar Mills94df8c92018-09-14 14:50:03 -0500301 using InternalFailure =
302 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530303
304 // At this time, it won't happen but keeping it
305 // here just in case something changes in the future
306 if ((activeCount == 0) && (!status))
307 {
Sheldon Bailey373af752022-02-21 15:14:00 -0600308 log<level::ERR>(
309 fmt::format("Invalid update on OCCActive with OCC{}", instance)
310 .c_str());
311
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530312 elog<InternalFailure>();
313 }
314
Chris Caina7b74dc2021-11-10 17:03:43 -0600315 if (status == true)
Eddie Jamesdae2d942017-12-20 10:50:03 -0600316 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600317 // OCC went active
318 ++activeCount;
319
320#ifdef POWER10
321 if (activeCount == 1)
Eddie Jamesdae2d942017-12-20 10:50:03 -0600322 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600323 // First OCC went active (allow some time for all OCCs to go active)
324 waitForAllOccsTimer->restartOnce(30s);
Matt Spinler53f68142021-08-25 15:47:31 -0500325 }
326#endif
Chris Caina7b74dc2021-11-10 17:03:43 -0600327
328 if (activeCount == statusObjects.size())
329 {
330#ifdef POWER10
331 // All OCCs are now running
332 if (waitForAllOccsTimer->isEnabled())
333 {
334 // stop occ wait timer
335 waitForAllOccsTimer->setEnabled(false);
336 }
337#endif
338
339 // Verify master OCC and start presence monitor
340 validateOccMaster();
341 }
342
343 // Start poll timer if not already started
344 if (!_pollTimer->isEnabled())
345 {
346 log<level::INFO>(
Chris Cain36f9cde2021-11-22 11:18:21 -0600347 fmt::format("Manager: OCCs will be polled every {} seconds",
348 pollInterval)
Chris Caina7b74dc2021-11-10 17:03:43 -0600349 .c_str());
350
351 // Send poll and start OCC poll timer
352 pollerTimerExpired();
353 }
354 }
355 else
356 {
357 // OCC went away
358 --activeCount;
359
360 if (activeCount == 0)
361 {
362 // No OCCs are running
363
364 // Stop OCC poll timer
365 if (_pollTimer->isEnabled())
366 {
367 log<level::INFO>(
368 "Manager::statusCallBack(): OCCs are not running, stopping poll timer");
369 _pollTimer->setEnabled(false);
370 }
371
372#ifdef POWER10
373 // stop wait timer
374 if (waitForAllOccsTimer->isEnabled())
375 {
376 waitForAllOccsTimer->setEnabled(false);
377 }
378#endif
Chris Caina7b74dc2021-11-10 17:03:43 -0600379 }
Sheldon Bailey373af752022-02-21 15:14:00 -0600380#ifdef READ_OCC_SENSORS
381 // Clear OCC sensors
382 setSensorValueToNonFunctional(instance);
383#endif
Chris Caina8857c52021-01-27 11:53:05 -0600384 }
Chris Cainbae4d072022-02-28 09:46:50 -0600385
386#ifdef POWER10
387 if (waitingForAllOccActiveSensors)
388 {
389 checkAllActiveSensors();
390 }
391#endif
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530392}
393
394#ifdef I2C_OCC
395void Manager::initStatusObjects()
396{
397 // Make sure we have a valid path string
398 static_assert(sizeof(DEV_PATH) != 0);
399
400 auto deviceNames = i2c_occ::getOccHwmonDevices(DEV_PATH);
401 for (auto& name : deviceNames)
402 {
403 i2c_occ::i2cToDbus(name);
Lei YUb5259a12017-09-01 16:22:40 +0800404 name = std::string(OCC_NAME) + '_' + name;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530405 auto path = fs::path(OCC_CONTROL_ROOT) / name;
406 statusObjects.emplace_back(
George Liuf3b75142021-06-10 11:22:50 +0800407 std::make_unique<Status>(event, path.c_str(), *this));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530408 }
Chris Cain40501a22022-03-14 17:33:27 -0500409 // The first device is master occ
410 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
411 *statusObjects.front());
Chris Cain78e86012021-03-04 16:15:31 -0600412#ifdef POWER10
Chris Cain5d66a0a2022-02-09 08:52:10 -0600413 pmode = std::make_unique<powermode::PowerMode>(*this, powermode::PMODE_PATH,
414 powermode::PIPS_PATH);
Chris Cain6fa848a2022-01-24 14:54:38 -0600415 // Set the master OCC on the PowerMode object
416 pmode->setMasterOcc(path);
Chris Cain78e86012021-03-04 16:15:31 -0600417#endif
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530418}
419#endif
420
Tom Joseph815f9f52020-07-27 12:12:13 +0530421#ifdef PLDM
Eddie Jamescbad2192021-10-07 09:39:39 -0500422void Manager::sbeTimeout(unsigned int instance)
423{
Eddie James2a751d72022-03-04 09:16:12 -0600424 auto obj = std::find_if(statusObjects.begin(), statusObjects.end(),
425 [instance](const auto& obj) {
426 return instance == obj->getOccInstanceID();
427 });
Eddie Jamescbad2192021-10-07 09:39:39 -0500428
Eddie Jamescb018da2022-03-05 11:49:37 -0600429 if (obj != statusObjects.end() && (*obj)->occActive())
Eddie James2a751d72022-03-04 09:16:12 -0600430 {
Chris Cainbae4d072022-02-28 09:46:50 -0600431 log<level::INFO>(
432 fmt::format("SBE timeout, requesting HRESET (OCC{})", instance)
433 .c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500434
Eddie James2a751d72022-03-04 09:16:12 -0600435 setSBEState(instance, SBE_STATE_NOT_USABLE);
436
437 pldmHandle->sendHRESET(instance);
438 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500439}
440
Tom Joseph815f9f52020-07-27 12:12:13 +0530441bool Manager::updateOCCActive(instanceID instance, bool status)
442{
Chris Cain7e374fb2022-04-07 09:47:23 -0500443 auto obj = std::find_if(statusObjects.begin(), statusObjects.end(),
444 [instance](const auto& obj) {
445 return instance == obj->getOccInstanceID();
446 });
447
448 if (obj != statusObjects.end())
449 {
450 return (*obj)->occActive(status);
451 }
452 else
453 {
454 log<level::WARNING>(
455 fmt::format(
456 "Manager::updateOCCActive: No status object to update for OCC{} (active={})",
457 instance, status)
458 .c_str());
459 return false;
460 }
Tom Joseph815f9f52020-07-27 12:12:13 +0530461}
Eddie Jamescbad2192021-10-07 09:39:39 -0500462
463void Manager::sbeHRESETResult(instanceID instance, bool success)
464{
465 if (success)
466 {
Chris Cainbae4d072022-02-28 09:46:50 -0600467 log<level::INFO>(
468 fmt::format("HRESET succeeded (OCC{})", instance).c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500469
470 setSBEState(instance, SBE_STATE_BOOTED);
471
472 return;
473 }
474
475 setSBEState(instance, SBE_STATE_FAILED);
476
477 if (sbeCanDump(instance))
478 {
Chris Cainbae4d072022-02-28 09:46:50 -0600479 log<level::INFO>(
480 fmt::format("HRESET failed (OCC{}), triggering SBE dump", instance)
481 .c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500482
483 auto& bus = utils::getBus();
484 uint32_t src6 = instance << 16;
485 uint32_t logId =
486 FFDC::createPEL("org.open_power.Processor.Error.SbeChipOpTimeout",
487 src6, "SBE command timeout");
488
489 try
490 {
George Liuf3a4a692021-12-28 13:59:51 +0800491 constexpr auto path = "/org/openpower/dump";
492 constexpr auto interface = "xyz.openbmc_project.Dump.Create";
493 constexpr auto function = "CreateDump";
494
Eddie Jamescbad2192021-10-07 09:39:39 -0500495 std::string service = utils::getService(path, interface);
496 auto method =
497 bus.new_method_call(service.c_str(), path, interface, function);
498
499 std::map<std::string, std::variant<std::string, uint64_t>>
500 createParams{
501 {"com.ibm.Dump.Create.CreateParameters.ErrorLogId",
502 uint64_t(logId)},
503 {"com.ibm.Dump.Create.CreateParameters.DumpType",
504 "com.ibm.Dump.Create.DumpType.SBE"},
505 {"com.ibm.Dump.Create.CreateParameters.FailingUnitId",
506 uint64_t(instance)},
507 };
508
509 method.append(createParams);
510
511 auto response = bus.call(method);
512 }
513 catch (const sdbusplus::exception::exception& e)
514 {
515 constexpr auto ERROR_DUMP_DISABLED =
516 "xyz.openbmc_project.Dump.Create.Error.Disabled";
517 if (e.name() == ERROR_DUMP_DISABLED)
518 {
519 log<level::INFO>("Dump is disabled, skipping");
520 }
521 else
522 {
523 log<level::ERR>("Dump failed");
524 }
525 }
526 }
527}
528
529bool Manager::sbeCanDump(unsigned int instance)
530{
531 struct pdbg_target* proc = getPdbgTarget(instance);
532
533 if (!proc)
534 {
535 // allow the dump in the error case
536 return true;
537 }
538
539 try
540 {
541 if (!openpower::phal::sbe::isDumpAllowed(proc))
542 {
543 return false;
544 }
545
546 if (openpower::phal::pdbg::isSbeVitalAttnActive(proc))
547 {
548 return false;
549 }
550 }
551 catch (openpower::phal::exception::SbeError& e)
552 {
553 log<level::INFO>("Failed to query SBE state");
554 }
555
556 // allow the dump in the error case
557 return true;
558}
559
560void Manager::setSBEState(unsigned int instance, enum sbe_state state)
561{
562 struct pdbg_target* proc = getPdbgTarget(instance);
563
564 if (!proc)
565 {
566 return;
567 }
568
569 try
570 {
571 openpower::phal::sbe::setState(proc, state);
572 }
573 catch (const openpower::phal::exception::SbeError& e)
574 {
575 log<level::ERR>("Failed to set SBE state");
576 }
577}
578
579struct pdbg_target* Manager::getPdbgTarget(unsigned int instance)
580{
581 if (!pdbgInitialized)
582 {
583 try
584 {
585 openpower::phal::pdbg::init();
586 pdbgInitialized = true;
587 }
588 catch (const openpower::phal::exception::PdbgError& e)
589 {
590 log<level::ERR>("pdbg initialization failed");
591 return nullptr;
592 }
593 }
594
595 struct pdbg_target* proc = nullptr;
596 pdbg_for_each_class_target("proc", proc)
597 {
598 if (pdbg_target_index(proc) == instance)
599 {
600 return proc;
601 }
602 }
603
604 log<level::ERR>("Failed to get pdbg target");
605 return nullptr;
606}
Tom Joseph815f9f52020-07-27 12:12:13 +0530607#endif
608
Chris Caina8857c52021-01-27 11:53:05 -0600609void Manager::pollerTimerExpired()
610{
Chris Caina8857c52021-01-27 11:53:05 -0600611 if (!_pollTimer)
612 {
613 log<level::ERR>(
614 "Manager::pollerTimerExpired() ERROR: Timer not defined");
615 return;
616 }
617
618 for (auto& obj : statusObjects)
619 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600620 if (!obj->occActive())
621 {
622 // OCC is not running yet
623#ifdef READ_OCC_SENSORS
Chris Cain5d66a0a2022-02-09 08:52:10 -0600624 auto id = obj->getOccInstanceID();
Sheldon Bailey373af752022-02-21 15:14:00 -0600625 setSensorValueToNonFunctional(id);
Chris Caina7b74dc2021-11-10 17:03:43 -0600626#endif
627 continue;
628 }
629
Chris Caina8857c52021-01-27 11:53:05 -0600630 // Read sysfs to force kernel to poll OCC
631 obj->readOccState();
Chicago Duanbb895cb2021-06-18 19:37:16 +0800632
633#ifdef READ_OCC_SENSORS
634 // Read occ sensor values
Chris Cain5d66a0a2022-02-09 08:52:10 -0600635 getSensorValues(obj);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800636#endif
Chris Caina8857c52021-01-27 11:53:05 -0600637 }
638
Chris Caina7b74dc2021-11-10 17:03:43 -0600639 if (activeCount > 0)
640 {
641 // Restart OCC poll timer
642 _pollTimer->restartOnce(std::chrono::seconds(pollInterval));
643 }
644 else
645 {
646 // No OCCs running, so poll timer will not be restarted
647 log<level::INFO>(
648 fmt::format(
649 "Manager::pollerTimerExpired: poll timer will not be restarted")
650 .c_str());
651 }
Chris Caina8857c52021-01-27 11:53:05 -0600652}
653
Chicago Duanbb895cb2021-06-18 19:37:16 +0800654#ifdef READ_OCC_SENSORS
655void Manager::readTempSensors(const fs::path& path, uint32_t id)
656{
Chicago Duanbb895cb2021-06-18 19:37:16 +0800657 std::regex expr{"temp\\d+_label$"}; // Example: temp5_label
658 for (auto& file : fs::directory_iterator(path))
659 {
660 if (!std::regex_search(file.path().string(), expr))
661 {
662 continue;
663 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800664
Matt Spinlera26f1522021-08-25 15:50:20 -0500665 uint32_t labelValue{0};
666
667 try
668 {
669 labelValue = readFile<uint32_t>(file.path());
670 }
671 catch (const std::system_error& e)
672 {
673 log<level::DEBUG>(
674 fmt::format("readTempSensors: Failed reading {}, errno = {}",
675 file.path().string(), e.code().value())
676 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800677 continue;
678 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800679
680 const std::string& tempLabel = "label";
681 const std::string filePathString = file.path().string().substr(
682 0, file.path().string().length() - tempLabel.length());
Matt Spinlera26f1522021-08-25 15:50:20 -0500683
684 uint32_t fruTypeValue{0};
685 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800686 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500687 fruTypeValue = readFile<uint32_t>(filePathString + fruTypeSuffix);
688 }
689 catch (const std::system_error& e)
690 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800691 log<level::DEBUG>(
Matt Spinlera26f1522021-08-25 15:50:20 -0500692 fmt::format("readTempSensors: Failed reading {}, errno = {}",
693 filePathString + fruTypeSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +0800694 .c_str());
695 continue;
696 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800697
698 std::string sensorPath =
699 OCC_SENSORS_ROOT + std::string("/temperature/");
700
Matt Spinlerace67d82021-10-18 13:41:57 -0500701 std::string dvfsTempPath;
702
Chicago Duanbb895cb2021-06-18 19:37:16 +0800703 if (fruTypeValue == VRMVdd)
704 {
705 sensorPath.append("vrm_vdd" + std::to_string(id) + "_temp");
706 }
Matt Spinlerace67d82021-10-18 13:41:57 -0500707 else if (fruTypeValue == processorIoRing)
708 {
709 sensorPath.append("proc" + std::to_string(id) + "_ioring_temp");
710 dvfsTempPath = std::string{OCC_SENSORS_ROOT} + "/temperature/proc" +
711 std::to_string(id) + "_ioring_dvfs_temp";
712 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800713 else
714 {
Matt Spinler14d14022021-08-25 15:38:29 -0500715 uint16_t type = (labelValue & 0xFF000000) >> 24;
716 uint16_t instanceID = labelValue & 0x0000FFFF;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800717
718 if (type == OCC_DIMM_TEMP_SENSOR_TYPE)
719 {
Matt Spinler8b8abee2021-08-25 15:18:21 -0500720 if (fruTypeValue == fruTypeNotAvailable)
721 {
722 // Not all DIMM related temps are available to read
723 // (no _input file in this case)
724 continue;
725 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800726 auto iter = dimmTempSensorName.find(fruTypeValue);
727 if (iter == dimmTempSensorName.end())
728 {
George Liub5ca1012021-09-10 12:53:11 +0800729 log<level::ERR>(
730 fmt::format(
731 "readTempSensors: Fru type error! fruTypeValue = {}) ",
732 fruTypeValue)
733 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800734 continue;
735 }
736
737 sensorPath.append("dimm" + std::to_string(instanceID) +
738 iter->second);
739 }
740 else if (type == OCC_CPU_TEMP_SENSOR_TYPE)
741 {
Matt Spinlerace67d82021-10-18 13:41:57 -0500742 if (fruTypeValue == processorCore)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800743 {
Matt Spinlerace67d82021-10-18 13:41:57 -0500744 // The OCC reports small core temps, of which there are
745 // two per big core. All current P10 systems are in big
746 // core mode, so use a big core name.
747 uint16_t coreNum = instanceID / 2;
748 uint16_t tempNum = instanceID % 2;
749 sensorPath.append("proc" + std::to_string(id) + "_core" +
750 std::to_string(coreNum) + "_" +
751 std::to_string(tempNum) + "_temp");
752
753 dvfsTempPath = std::string{OCC_SENSORS_ROOT} +
754 "/temperature/proc" + std::to_string(id) +
755 "_core_dvfs_temp";
756 }
757 else
758 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800759 continue;
760 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800761 }
762 else
763 {
764 continue;
765 }
766 }
767
Matt Spinlerace67d82021-10-18 13:41:57 -0500768 // The dvfs temp file only needs to be read once per chip per type.
769 if (!dvfsTempPath.empty() &&
770 !dbus::OccDBusSensors::getOccDBus().hasDvfsTemp(dvfsTempPath))
771 {
772 try
773 {
774 auto dvfsValue = readFile<double>(filePathString + maxSuffix);
775
776 dbus::OccDBusSensors::getOccDBus().setDvfsTemp(
777 dvfsTempPath, dvfsValue * std::pow(10, -3));
778 }
779 catch (const std::system_error& e)
780 {
781 log<level::DEBUG>(
782 fmt::format(
783 "readTempSensors: Failed reading {}, errno = {}",
784 filePathString + maxSuffix, e.code().value())
785 .c_str());
786 }
787 }
788
Matt Spinlera26f1522021-08-25 15:50:20 -0500789 uint32_t faultValue{0};
790 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800791 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500792 faultValue = readFile<uint32_t>(filePathString + faultSuffix);
793 }
794 catch (const std::system_error& e)
795 {
796 log<level::DEBUG>(
797 fmt::format("readTempSensors: Failed reading {}, errno = {}",
798 filePathString + faultSuffix, e.code().value())
799 .c_str());
800 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800801 }
802
Matt Spinlera26f1522021-08-25 15:50:20 -0500803 if (faultValue != 0)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800804 {
Chris Cain5d66a0a2022-02-09 08:52:10 -0600805 dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -0500806 sensorPath, std::numeric_limits<double>::quiet_NaN());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800807
Chris Cain5d66a0a2022-02-09 08:52:10 -0600808 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
809 false);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800810
Matt Spinlera26f1522021-08-25 15:50:20 -0500811 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800812 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500813
814 double tempValue{0};
815
816 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800817 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500818 tempValue = readFile<double>(filePathString + inputSuffix);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800819 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500820 catch (const std::system_error& e)
821 {
822 log<level::DEBUG>(
823 fmt::format("readTempSensors: Failed reading {}, errno = {}",
824 filePathString + inputSuffix, e.code().value())
825 .c_str());
826 continue;
827 }
828
Chris Cain5d66a0a2022-02-09 08:52:10 -0600829 dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -0500830 sensorPath, tempValue * std::pow(10, -3));
831
Chris Cain5d66a0a2022-02-09 08:52:10 -0600832 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
833 true);
Matt Spinlera26f1522021-08-25 15:50:20 -0500834
Chris Cain6fa848a2022-01-24 14:54:38 -0600835 // At this point, the sensor will be created for sure.
836 if (existingSensors.find(sensorPath) == existingSensors.end())
837 {
Chris Cain5d66a0a2022-02-09 08:52:10 -0600838 dbus::OccDBusSensors::getOccDBus().setChassisAssociation(
839 sensorPath);
Chris Cain6fa848a2022-01-24 14:54:38 -0600840 }
841
Matt Spinlera26f1522021-08-25 15:50:20 -0500842 existingSensors[sensorPath] = id;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800843 }
844 return;
845}
846
847std::optional<std::string>
848 Manager::getPowerLabelFunctionID(const std::string& value)
849{
850 // If the value is "system", then the FunctionID is "system".
851 if (value == "system")
852 {
853 return value;
854 }
855
856 // If the value is not "system", then the label value have 3 numbers, of
857 // which we only care about the middle one:
858 // <sensor id>_<function id>_<apss channel>
859 // eg: The value is "0_10_5" , then the FunctionID is "10".
860 if (value.find("_") == std::string::npos)
861 {
862 return std::nullopt;
863 }
864
865 auto powerLabelValue = value.substr((value.find("_") + 1));
866
867 if (powerLabelValue.find("_") == std::string::npos)
868 {
869 return std::nullopt;
870 }
871
872 return powerLabelValue.substr(0, powerLabelValue.find("_"));
873}
874
875void Manager::readPowerSensors(const fs::path& path, uint32_t id)
876{
Chicago Duanbb895cb2021-06-18 19:37:16 +0800877 std::regex expr{"power\\d+_label$"}; // Example: power5_label
878 for (auto& file : fs::directory_iterator(path))
879 {
880 if (!std::regex_search(file.path().string(), expr))
881 {
882 continue;
883 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800884
Matt Spinlera26f1522021-08-25 15:50:20 -0500885 std::string labelValue;
886 try
887 {
888 labelValue = readFile<std::string>(file.path());
889 }
890 catch (const std::system_error& e)
891 {
892 log<level::DEBUG>(
893 fmt::format("readPowerSensors: Failed reading {}, errno = {}",
894 file.path().string(), e.code().value())
895 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800896 continue;
897 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800898
899 auto functionID = getPowerLabelFunctionID(labelValue);
900 if (functionID == std::nullopt)
901 {
902 continue;
903 }
904
905 const std::string& tempLabel = "label";
906 const std::string filePathString = file.path().string().substr(
907 0, file.path().string().length() - tempLabel.length());
908
909 std::string sensorPath = OCC_SENSORS_ROOT + std::string("/power/");
910
911 auto iter = powerSensorName.find(*functionID);
912 if (iter == powerSensorName.end())
913 {
914 continue;
915 }
916 sensorPath.append(iter->second);
917
Matt Spinlera26f1522021-08-25 15:50:20 -0500918 double tempValue{0};
919
920 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800921 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500922 tempValue = readFile<double>(filePathString + inputSuffix);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800923 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500924 catch (const std::system_error& e)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800925 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800926 log<level::DEBUG>(
Chris Cain5d66a0a2022-02-09 08:52:10 -0600927 fmt::format("readPowerSensors: Failed reading {}, errno = {}",
Matt Spinlera26f1522021-08-25 15:50:20 -0500928 filePathString + inputSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +0800929 .c_str());
Matt Spinlera26f1522021-08-25 15:50:20 -0500930 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800931 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500932
Chris Cain5d66a0a2022-02-09 08:52:10 -0600933 dbus::OccDBusSensors::getOccDBus().setUnit(
Chris Caind84a8332022-01-13 08:58:45 -0600934 sensorPath, "xyz.openbmc_project.Sensor.Value.Unit.Watts");
935
Chris Cain5d66a0a2022-02-09 08:52:10 -0600936 dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -0500937 sensorPath, tempValue * std::pow(10, -3) * std::pow(10, -3));
938
Chris Cain5d66a0a2022-02-09 08:52:10 -0600939 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
940 true);
Matt Spinlera26f1522021-08-25 15:50:20 -0500941
Matt Spinler5901abd2021-09-23 13:50:03 -0500942 if (existingSensors.find(sensorPath) == existingSensors.end())
943 {
Chris Cain5d66a0a2022-02-09 08:52:10 -0600944 dbus::OccDBusSensors::getOccDBus().setChassisAssociation(
945 sensorPath);
Matt Spinler5901abd2021-09-23 13:50:03 -0500946 }
947
Matt Spinlera26f1522021-08-25 15:50:20 -0500948 existingSensors[sensorPath] = id;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800949 }
950 return;
951}
952
953void Manager::setSensorValueToNaN(uint32_t id)
954{
955 for (const auto& [sensorPath, occId] : existingSensors)
956 {
957 if (occId == id)
958 {
Chris Cain5d66a0a2022-02-09 08:52:10 -0600959 dbus::OccDBusSensors::getOccDBus().setValue(
Chicago Duanbb895cb2021-06-18 19:37:16 +0800960 sensorPath, std::numeric_limits<double>::quiet_NaN());
961 }
962 }
963 return;
964}
965
Sheldon Bailey373af752022-02-21 15:14:00 -0600966void Manager::setSensorValueToNonFunctional(uint32_t id) const
967{
968 for (const auto& [sensorPath, occId] : existingSensors)
969 {
970 if (occId == id)
971 {
972 dbus::OccDBusSensors::getOccDBus().setValue(
973 sensorPath, std::numeric_limits<double>::quiet_NaN());
974
975 dbus::OccDBusSensors::getOccDBus().setOperationalStatus(sensorPath,
976 false);
977 }
978 }
979 return;
980}
981
Chris Cain5d66a0a2022-02-09 08:52:10 -0600982void Manager::getSensorValues(std::unique_ptr<Status>& occ)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800983{
Chris Caine2d0a432022-03-28 11:08:49 -0500984 static bool tracedError[8] = {0};
985 const fs::path sensorPath = occ->getHwmonPath();
Chris Cain5d66a0a2022-02-09 08:52:10 -0600986 const uint32_t id = occ->getOccInstanceID();
Chicago Duanbb895cb2021-06-18 19:37:16 +0800987
Chris Caine2d0a432022-03-28 11:08:49 -0500988 if (fs::exists(sensorPath))
Chicago Duanbb895cb2021-06-18 19:37:16 +0800989 {
Chris Caine2d0a432022-03-28 11:08:49 -0500990 // Read temperature sensors
991 readTempSensors(sensorPath, id);
992
993 if (occ->isMasterOcc())
994 {
995 // Read power sensors
996 readPowerSensors(sensorPath, id);
997 }
998 tracedError[id] = false;
999 }
1000 else
1001 {
1002 if (!tracedError[id])
1003 {
1004 log<level::ERR>(
1005 fmt::format(
1006 "Manager::getSensorValues: OCC{} sensor path missing: {}",
1007 id, sensorPath.c_str())
1008 .c_str());
1009 tracedError[id] = true;
1010 }
Chicago Duanbb895cb2021-06-18 19:37:16 +08001011 }
1012
1013 return;
1014}
1015#endif
Chris Cain17257672021-10-22 13:41:03 -05001016
1017// Read the altitude from DBus
1018void Manager::readAltitude()
1019{
1020 static bool traceAltitudeErr = true;
1021
1022 utils::PropertyValue altitudeProperty{};
1023 try
1024 {
1025 altitudeProperty = utils::getProperty(ALTITUDE_PATH, ALTITUDE_INTERFACE,
1026 ALTITUDE_PROP);
1027 auto sensorVal = std::get<double>(altitudeProperty);
1028 if (sensorVal < 0xFFFF)
1029 {
1030 if (sensorVal < 0)
1031 {
1032 altitude = 0;
1033 }
1034 else
1035 {
1036 // Round to nearest meter
1037 altitude = uint16_t(sensorVal + 0.5);
1038 }
1039 log<level::DEBUG>(fmt::format("readAltitude: sensor={} ({}m)",
1040 sensorVal, altitude)
1041 .c_str());
1042 traceAltitudeErr = true;
1043 }
1044 else
1045 {
1046 if (traceAltitudeErr)
1047 {
1048 traceAltitudeErr = false;
1049 log<level::DEBUG>(
1050 fmt::format("Invalid altitude value: {}", sensorVal)
1051 .c_str());
1052 }
1053 }
1054 }
1055 catch (const sdbusplus::exception::exception& e)
1056 {
1057 if (traceAltitudeErr)
1058 {
1059 traceAltitudeErr = false;
1060 log<level::INFO>(
1061 fmt::format("Unable to read Altitude: {}", e.what()).c_str());
1062 }
1063 altitude = 0xFFFF; // not available
1064 }
1065}
1066
1067// Callback function when ambient temperature changes
1068void Manager::ambientCallback(sdbusplus::message::message& msg)
1069{
1070 double currentTemp = 0;
1071 uint8_t truncatedTemp = 0xFF;
1072 std::string msgSensor;
1073 std::map<std::string, std::variant<double>> msgData;
1074 msg.read(msgSensor, msgData);
1075
1076 auto valPropMap = msgData.find(AMBIENT_PROP);
1077 if (valPropMap == msgData.end())
1078 {
1079 log<level::DEBUG>("ambientCallback: Unknown ambient property changed");
1080 return;
1081 }
1082 currentTemp = std::get<double>(valPropMap->second);
1083 if (std::isnan(currentTemp))
1084 {
1085 truncatedTemp = 0xFF;
1086 }
1087 else
1088 {
1089 if (currentTemp < 0)
1090 {
1091 truncatedTemp = 0;
1092 }
1093 else
1094 {
1095 // Round to nearest degree C
1096 truncatedTemp = uint8_t(currentTemp + 0.5);
1097 }
1098 }
1099
1100 // If ambient changes, notify OCCs
1101 if (truncatedTemp != ambient)
1102 {
1103 log<level::DEBUG>(
1104 fmt::format("ambientCallback: Ambient change from {} to {}C",
1105 ambient, currentTemp)
1106 .c_str());
1107
1108 ambient = truncatedTemp;
1109 if (altitude == 0xFFFF)
1110 {
1111 // No altitude yet, try reading again
1112 readAltitude();
1113 }
1114
1115 log<level::DEBUG>(
1116 fmt::format("ambientCallback: Ambient: {}C, altitude: {}m", ambient,
1117 altitude)
1118 .c_str());
1119#ifdef POWER10
1120 // Send ambient and altitude to all OCCs
1121 for (auto& obj : statusObjects)
1122 {
1123 if (obj->occActive())
1124 {
1125 obj->sendAmbient(ambient, altitude);
1126 }
1127 }
1128#endif // POWER10
1129 }
1130}
1131
1132// return the current ambient and altitude readings
1133void Manager::getAmbientData(bool& ambientValid, uint8_t& ambientTemp,
1134 uint16_t& altitudeValue) const
1135{
1136 ambientValid = true;
1137 ambientTemp = ambient;
1138 altitudeValue = altitude;
1139
1140 if (ambient == 0xFF)
1141 {
1142 ambientValid = false;
1143 }
1144}
1145
Chris Caina7b74dc2021-11-10 17:03:43 -06001146#ifdef POWER10
1147void Manager::occsNotAllRunning()
1148{
Chris Cain6fa848a2022-01-24 14:54:38 -06001149 // Function will also gets called when occ-control app gets
1150 // restarted. (occ active sensors do not change, so the Status
1151 // object does not call Manager back for all OCCs)
Chris Caina7b74dc2021-11-10 17:03:43 -06001152
1153 if (activeCount != statusObjects.size())
1154 {
1155 // Not all OCCs went active
1156 log<level::WARNING>(
1157 fmt::format(
1158 "occsNotAllRunning: Active OCC count ({}) does not match expected count ({})",
1159 activeCount, statusObjects.size())
1160 .c_str());
1161 // Procs may be garded, so may not need reset.
1162 }
1163
1164 validateOccMaster();
1165}
1166#endif // POWER10
1167
1168// Verify single master OCC and start presence monitor
1169void Manager::validateOccMaster()
1170{
1171 int masterInstance = -1;
1172 for (auto& obj : statusObjects)
1173 {
Chris Cainbae4d072022-02-28 09:46:50 -06001174#ifdef POWER10
1175 if (!obj->occActive())
1176 {
1177 if (utils::isHostRunning())
1178 {
1179 // OCC does not appear to be active yet, check active sensor
1180 pldmHandle->checkActiveSensor(obj->getOccInstanceID());
1181 if (obj->occActive())
1182 {
1183 log<level::INFO>(
1184 fmt::format(
1185 "validateOccMaster: OCC{} is ACTIVE after reading sensor",
1186 obj->getOccInstanceID())
1187 .c_str());
1188 }
1189 }
1190 else
1191 {
1192 log<level::WARNING>(
1193 fmt::format(
1194 "validateOccMaster: HOST is not running (OCC{})",
1195 obj->getOccInstanceID())
1196 .c_str());
1197 return;
1198 }
1199 }
1200#endif // POWER10
1201
Chris Caina7b74dc2021-11-10 17:03:43 -06001202 if (obj->isMasterOcc())
1203 {
Chris Cain5d66a0a2022-02-09 08:52:10 -06001204 obj->addPresenceWatchMaster();
1205
Chris Caina7b74dc2021-11-10 17:03:43 -06001206 if (masterInstance == -1)
1207 {
1208 masterInstance = obj->getOccInstanceID();
1209 }
1210 else
1211 {
1212 log<level::ERR>(
1213 fmt::format(
1214 "validateOccMaster: Multiple OCC masters! ({} and {})",
1215 masterInstance, obj->getOccInstanceID())
1216 .c_str());
1217 // request reset
1218 obj->deviceError();
1219 }
1220 }
1221 }
Chris Cainbae4d072022-02-28 09:46:50 -06001222
Chris Caina7b74dc2021-11-10 17:03:43 -06001223 if (masterInstance < 0)
1224 {
Chris Cainbae4d072022-02-28 09:46:50 -06001225 log<level::ERR>(
1226 fmt::format("validateOccMaster: Master OCC not found! (of {} OCCs)",
1227 statusObjects.size())
1228 .c_str());
Chris Caina7b74dc2021-11-10 17:03:43 -06001229 // request reset
1230 statusObjects.front()->deviceError();
1231 }
1232 else
1233 {
1234 log<level::INFO>(
Chris Cain36f9cde2021-11-22 11:18:21 -06001235 fmt::format("validateOccMaster: OCC{} is master of {} OCCs",
1236 masterInstance, activeCount)
Chris Caina7b74dc2021-11-10 17:03:43 -06001237 .c_str());
1238 }
1239}
1240
Chris Cain40501a22022-03-14 17:33:27 -05001241void Manager::updatePcapBounds() const
1242{
1243 if (pcap)
1244 {
1245 pcap->updatePcapBounds();
1246 }
1247}
1248
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +05301249} // namespace occ
1250} // namespace open_power