blob: 3160131eb21ee8cd8c1df25073195aa5e1d171b1 [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 Caina8857c52021-01-27 11:53:05 -060030using namespace phosphor::logging;
Chris Caina7b74dc2021-11-10 17:03:43 -060031using namespace std::literals::chrono_literals;
Chris Caina8857c52021-01-27 11:53:05 -060032
Matt Spinlera26f1522021-08-25 15:50:20 -050033template <typename T>
34T readFile(const std::string& path)
35{
36 std::ifstream ifs;
37 ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit |
38 std::ifstream::eofbit);
39 T data;
40
41 try
42 {
43 ifs.open(path);
44 ifs >> data;
45 ifs.close();
46 }
47 catch (const std::exception& e)
48 {
49 auto err = errno;
50 throw std::system_error(err, std::generic_category());
51 }
52
53 return data;
54}
55
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +053056void Manager::findAndCreateObjects()
57{
Matt Spinlerd267cec2021-09-01 14:49:19 -050058#ifndef POWER10
Deepak Kodihalli370f06b2017-10-25 04:26:07 -050059 for (auto id = 0; id < MAX_CPUS; ++id)
60 {
Deepak Kodihalli30417a12017-12-04 00:54:01 -060061 // Create one occ per cpu
62 auto occ = std::string(OCC_NAME) + std::to_string(id);
63 createObjects(occ);
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +053064 }
Matt Spinlerd267cec2021-09-01 14:49:19 -050065#else
66 // Create the OCCs based on on the /dev/occX devices
67 auto occs = findOCCsInDev();
68
69 if (occs.empty() || (prevOCCSearch.size() != occs.size()))
70 {
71 // Something changed or no OCCs yet, try again in 10s.
72 // Note on the first pass prevOCCSearch will be empty,
73 // so there will be at least one delay to give things
74 // a chance to settle.
75 prevOCCSearch = occs;
76
Matt Spinlerd267cec2021-09-01 14:49:19 -050077 discoverTimer->restartOnce(10s);
78 }
79 else
80 {
81 discoverTimer.reset();
82
83 // createObjects requires OCC0 first.
84 std::sort(occs.begin(), occs.end());
85
86 for (auto id : occs)
87 {
88 createObjects(std::string(OCC_NAME) + std::to_string(id));
89 }
90 }
91#endif
92}
93
94std::vector<int> Manager::findOCCsInDev()
95{
96 std::vector<int> occs;
97 std::regex expr{R"(occ(\d+)$)"};
98
99 for (auto& file : fs::directory_iterator("/dev"))
100 {
101 std::smatch match;
102 std::string path{file.path().string()};
103 if (std::regex_search(path, match, expr))
104 {
105 auto num = std::stoi(match[1].str());
106
107 // /dev numbering starts at 1, ours starts at 0.
108 occs.push_back(num - 1);
109 }
110 }
111
112 return occs;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530113}
114
115int Manager::cpuCreated(sdbusplus::message::message& msg)
116{
George Liubcef3b42021-09-10 12:39:02 +0800117 namespace fs = std::filesystem;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530118
119 sdbusplus::message::object_path o;
120 msg.read(o);
121 fs::path cpuPath(std::string(std::move(o)));
122
123 auto name = cpuPath.filename().string();
124 auto index = name.find(CPU_NAME);
125 name.replace(index, std::strlen(CPU_NAME), OCC_NAME);
126
127 createObjects(name);
128
129 return 0;
130}
131
132void Manager::createObjects(const std::string& occ)
133{
134 auto path = fs::path(OCC_CONTROL_ROOT) / occ;
135
Chris Cain6fa848a2022-01-24 14:54:38 -0600136#ifdef POWER10
137 if (!pmode)
138 {
Chris Cain1be43372021-12-09 19:29:37 -0600139 // Create the power mode object
140 pmode = std::make_unique<open_power::occ::powermode::PowerMode>(
141 *this, powermode::PMODE_PATH, powermode::PIPS_PATH);
Chris Cain6fa848a2022-01-24 14:54:38 -0600142 }
143#endif
144
Gunnar Mills94df8c92018-09-14 14:50:03 -0500145 statusObjects.emplace_back(std::make_unique<Status>(
George Liuf3b75142021-06-10 11:22:50 +0800146 event, path.c_str(), *this,
Chris Cain36f9cde2021-11-22 11:18:21 -0600147#ifdef POWER10
148 pmode,
149#endif
Gunnar Mills94df8c92018-09-14 14:50:03 -0500150 std::bind(std::mem_fn(&Manager::statusCallBack), this,
Tom Joseph00325232020-07-29 17:51:48 +0530151 std::placeholders::_1)
152#ifdef PLDM
153 ,
154 std::bind(std::mem_fn(&pldm::Interface::resetOCC), pldmHandle.get(),
155 std::placeholders::_1)
156#endif
157 ));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530158
Chris Cain36f9cde2021-11-22 11:18:21 -0600159 if (statusObjects.back()->isMasterOcc())
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530160 {
Chris Cain36f9cde2021-11-22 11:18:21 -0600161 log<level::INFO>(
162 fmt::format("Manager::createObjects(): OCC{} is the master",
163 statusObjects.back()->getOccInstanceID())
164 .c_str());
165 _pollTimer->setEnabled(false);
166
167 // Create the power cap monitor object for master OCC
168 if (!pcap)
169 {
170 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
Chris Cain1be43372021-12-09 19:29:37 -0600171 *statusObjects.back());
Chris Cain36f9cde2021-11-22 11:18:21 -0600172 }
Chris Cain78e86012021-03-04 16:15:31 -0600173
174#ifdef POWER10
Chris Cain6fa848a2022-01-24 14:54:38 -0600175 // Set the master OCC on the PowerMode object
176 pmode->setMasterOcc(path);
Chris Cain78e86012021-03-04 16:15:31 -0600177#endif
Chris Cain36f9cde2021-11-22 11:18:21 -0600178 }
179
180 passThroughObjects.emplace_back(std::make_unique<PassThrough>(path.c_str()
181#ifdef POWER10
182 ,
183 pmode
184#endif
185 ));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530186}
187
188void Manager::statusCallBack(bool status)
189{
Gunnar Mills94df8c92018-09-14 14:50:03 -0500190 using InternalFailure =
191 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530192
193 // At this time, it won't happen but keeping it
194 // here just in case something changes in the future
195 if ((activeCount == 0) && (!status))
196 {
197 log<level::ERR>("Invalid update on OCCActive");
198 elog<InternalFailure>();
199 }
200
Chris Caina7b74dc2021-11-10 17:03:43 -0600201 if (status == true)
Eddie Jamesdae2d942017-12-20 10:50:03 -0600202 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600203 // OCC went active
204 ++activeCount;
205
206#ifdef POWER10
207 if (activeCount == 1)
Eddie Jamesdae2d942017-12-20 10:50:03 -0600208 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600209 // First OCC went active (allow some time for all OCCs to go active)
210 waitForAllOccsTimer->restartOnce(30s);
Matt Spinler53f68142021-08-25 15:47:31 -0500211 }
212#endif
Chris Caina7b74dc2021-11-10 17:03:43 -0600213
214 if (activeCount == statusObjects.size())
215 {
216#ifdef POWER10
217 // All OCCs are now running
218 if (waitForAllOccsTimer->isEnabled())
219 {
220 // stop occ wait timer
221 waitForAllOccsTimer->setEnabled(false);
222 }
223#endif
224
225 // Verify master OCC and start presence monitor
226 validateOccMaster();
227 }
228
229 // Start poll timer if not already started
230 if (!_pollTimer->isEnabled())
231 {
232 log<level::INFO>(
Chris Cain36f9cde2021-11-22 11:18:21 -0600233 fmt::format("Manager: OCCs will be polled every {} seconds",
234 pollInterval)
Chris Caina7b74dc2021-11-10 17:03:43 -0600235 .c_str());
236
237 // Send poll and start OCC poll timer
238 pollerTimerExpired();
239 }
240 }
241 else
242 {
243 // OCC went away
244 --activeCount;
245
246 if (activeCount == 0)
247 {
248 // No OCCs are running
249
250 // Stop OCC poll timer
251 if (_pollTimer->isEnabled())
252 {
253 log<level::INFO>(
254 "Manager::statusCallBack(): OCCs are not running, stopping poll timer");
255 _pollTimer->setEnabled(false);
256 }
257
258#ifdef POWER10
259 // stop wait timer
260 if (waitForAllOccsTimer->isEnabled())
261 {
262 waitForAllOccsTimer->setEnabled(false);
263 }
264#endif
265
266#ifdef READ_OCC_SENSORS
267 // Clear OCC sensors
268 for (auto& obj : statusObjects)
269 {
270 setSensorValueToNaN(obj->getOccInstanceID());
271 }
272#endif
273 }
Chris Caina8857c52021-01-27 11:53:05 -0600274 }
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530275}
276
277#ifdef I2C_OCC
278void Manager::initStatusObjects()
279{
280 // Make sure we have a valid path string
281 static_assert(sizeof(DEV_PATH) != 0);
282
283 auto deviceNames = i2c_occ::getOccHwmonDevices(DEV_PATH);
Lei YU41470e52017-11-30 16:03:50 +0800284 auto occMasterName = deviceNames.front();
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530285 for (auto& name : deviceNames)
286 {
287 i2c_occ::i2cToDbus(name);
Lei YUb5259a12017-09-01 16:22:40 +0800288 name = std::string(OCC_NAME) + '_' + name;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530289 auto path = fs::path(OCC_CONTROL_ROOT) / name;
290 statusObjects.emplace_back(
George Liuf3b75142021-06-10 11:22:50 +0800291 std::make_unique<Status>(event, path.c_str(), *this));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530292 }
Lei YU41470e52017-11-30 16:03:50 +0800293 // The first device is master occ
294 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
George Liuf3b75142021-06-10 11:22:50 +0800295 *statusObjects.front(), occMasterName);
Chris Cain78e86012021-03-04 16:15:31 -0600296#ifdef POWER10
Chris Cain1be43372021-12-09 19:29:37 -0600297 pmode = std::make_unique<open_power::occ::powermode::PowerMode>(
298 *this, open_power::occ::powermode::PMODE_PATH,
299 open_power::occ::powermode::PIPS_PATH);
Chris Cain6fa848a2022-01-24 14:54:38 -0600300 // Set the master OCC on the PowerMode object
301 pmode->setMasterOcc(path);
Chris Cain78e86012021-03-04 16:15:31 -0600302#endif
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530303}
304#endif
305
Tom Joseph815f9f52020-07-27 12:12:13 +0530306#ifdef PLDM
Eddie Jamescbad2192021-10-07 09:39:39 -0500307void Manager::sbeTimeout(unsigned int instance)
308{
309 log<level::INFO>("SBE timeout, requesting HRESET",
310 entry("SBE=%d", instance));
311
312 setSBEState(instance, SBE_STATE_NOT_USABLE);
313
314 pldmHandle->sendHRESET(instance);
315}
316
Tom Joseph815f9f52020-07-27 12:12:13 +0530317bool Manager::updateOCCActive(instanceID instance, bool status)
318{
319 return (statusObjects[instance])->occActive(status);
320}
Eddie Jamescbad2192021-10-07 09:39:39 -0500321
322void Manager::sbeHRESETResult(instanceID instance, bool success)
323{
324 if (success)
325 {
326 log<level::INFO>("HRESET succeeded", entry("SBE=%d", instance));
327
328 setSBEState(instance, SBE_STATE_BOOTED);
329
330 return;
331 }
332
333 setSBEState(instance, SBE_STATE_FAILED);
334
335 if (sbeCanDump(instance))
336 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500337 log<level::INFO>("HRESET failed, triggering SBE dump",
338 entry("SBE=%d", instance));
339
340 auto& bus = utils::getBus();
341 uint32_t src6 = instance << 16;
342 uint32_t logId =
343 FFDC::createPEL("org.open_power.Processor.Error.SbeChipOpTimeout",
344 src6, "SBE command timeout");
345
346 try
347 {
George Liuf3a4a692021-12-28 13:59:51 +0800348 constexpr auto path = "/org/openpower/dump";
349 constexpr auto interface = "xyz.openbmc_project.Dump.Create";
350 constexpr auto function = "CreateDump";
351
Eddie Jamescbad2192021-10-07 09:39:39 -0500352 std::string service = utils::getService(path, interface);
353 auto method =
354 bus.new_method_call(service.c_str(), path, interface, function);
355
356 std::map<std::string, std::variant<std::string, uint64_t>>
357 createParams{
358 {"com.ibm.Dump.Create.CreateParameters.ErrorLogId",
359 uint64_t(logId)},
360 {"com.ibm.Dump.Create.CreateParameters.DumpType",
361 "com.ibm.Dump.Create.DumpType.SBE"},
362 {"com.ibm.Dump.Create.CreateParameters.FailingUnitId",
363 uint64_t(instance)},
364 };
365
366 method.append(createParams);
367
368 auto response = bus.call(method);
369 }
370 catch (const sdbusplus::exception::exception& e)
371 {
372 constexpr auto ERROR_DUMP_DISABLED =
373 "xyz.openbmc_project.Dump.Create.Error.Disabled";
374 if (e.name() == ERROR_DUMP_DISABLED)
375 {
376 log<level::INFO>("Dump is disabled, skipping");
377 }
378 else
379 {
380 log<level::ERR>("Dump failed");
381 }
382 }
383 }
384}
385
386bool Manager::sbeCanDump(unsigned int instance)
387{
388 struct pdbg_target* proc = getPdbgTarget(instance);
389
390 if (!proc)
391 {
392 // allow the dump in the error case
393 return true;
394 }
395
396 try
397 {
398 if (!openpower::phal::sbe::isDumpAllowed(proc))
399 {
400 return false;
401 }
402
403 if (openpower::phal::pdbg::isSbeVitalAttnActive(proc))
404 {
405 return false;
406 }
407 }
408 catch (openpower::phal::exception::SbeError& e)
409 {
410 log<level::INFO>("Failed to query SBE state");
411 }
412
413 // allow the dump in the error case
414 return true;
415}
416
417void Manager::setSBEState(unsigned int instance, enum sbe_state state)
418{
419 struct pdbg_target* proc = getPdbgTarget(instance);
420
421 if (!proc)
422 {
423 return;
424 }
425
426 try
427 {
428 openpower::phal::sbe::setState(proc, state);
429 }
430 catch (const openpower::phal::exception::SbeError& e)
431 {
432 log<level::ERR>("Failed to set SBE state");
433 }
434}
435
436struct pdbg_target* Manager::getPdbgTarget(unsigned int instance)
437{
438 if (!pdbgInitialized)
439 {
440 try
441 {
442 openpower::phal::pdbg::init();
443 pdbgInitialized = true;
444 }
445 catch (const openpower::phal::exception::PdbgError& e)
446 {
447 log<level::ERR>("pdbg initialization failed");
448 return nullptr;
449 }
450 }
451
452 struct pdbg_target* proc = nullptr;
453 pdbg_for_each_class_target("proc", proc)
454 {
455 if (pdbg_target_index(proc) == instance)
456 {
457 return proc;
458 }
459 }
460
461 log<level::ERR>("Failed to get pdbg target");
462 return nullptr;
463}
Tom Joseph815f9f52020-07-27 12:12:13 +0530464#endif
465
Chris Caina8857c52021-01-27 11:53:05 -0600466void Manager::pollerTimerExpired()
467{
Chris Caina8857c52021-01-27 11:53:05 -0600468 if (!_pollTimer)
469 {
470 log<level::ERR>(
471 "Manager::pollerTimerExpired() ERROR: Timer not defined");
472 return;
473 }
474
475 for (auto& obj : statusObjects)
476 {
Chris Caina7b74dc2021-11-10 17:03:43 -0600477#ifdef READ_OCC_SENSORS
478 auto id = obj->getOccInstanceID();
479#endif
480 if (!obj->occActive())
481 {
482 // OCC is not running yet
483#ifdef READ_OCC_SENSORS
484 setSensorValueToNaN(id);
485#endif
486 continue;
487 }
488
Chris Caina8857c52021-01-27 11:53:05 -0600489 // Read sysfs to force kernel to poll OCC
490 obj->readOccState();
Chicago Duanbb895cb2021-06-18 19:37:16 +0800491
492#ifdef READ_OCC_SENSORS
493 // Read occ sensor values
Chicago Duanbb895cb2021-06-18 19:37:16 +0800494 getSensorValues(id, obj->isMasterOcc());
495#endif
Chris Caina8857c52021-01-27 11:53:05 -0600496 }
497
Chris Caina7b74dc2021-11-10 17:03:43 -0600498 if (activeCount > 0)
499 {
500 // Restart OCC poll timer
501 _pollTimer->restartOnce(std::chrono::seconds(pollInterval));
502 }
503 else
504 {
505 // No OCCs running, so poll timer will not be restarted
506 log<level::INFO>(
507 fmt::format(
508 "Manager::pollerTimerExpired: poll timer will not be restarted")
509 .c_str());
510 }
Chris Caina8857c52021-01-27 11:53:05 -0600511}
512
Chicago Duanbb895cb2021-06-18 19:37:16 +0800513#ifdef READ_OCC_SENSORS
514void Manager::readTempSensors(const fs::path& path, uint32_t id)
515{
Chicago Duanbb895cb2021-06-18 19:37:16 +0800516 std::regex expr{"temp\\d+_label$"}; // Example: temp5_label
517 for (auto& file : fs::directory_iterator(path))
518 {
519 if (!std::regex_search(file.path().string(), expr))
520 {
521 continue;
522 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800523
Matt Spinlera26f1522021-08-25 15:50:20 -0500524 uint32_t labelValue{0};
525
526 try
527 {
528 labelValue = readFile<uint32_t>(file.path());
529 }
530 catch (const std::system_error& e)
531 {
532 log<level::DEBUG>(
533 fmt::format("readTempSensors: Failed reading {}, errno = {}",
534 file.path().string(), e.code().value())
535 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800536 continue;
537 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800538
539 const std::string& tempLabel = "label";
540 const std::string filePathString = file.path().string().substr(
541 0, file.path().string().length() - tempLabel.length());
Matt Spinlera26f1522021-08-25 15:50:20 -0500542
543 uint32_t fruTypeValue{0};
544 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800545 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500546 fruTypeValue = readFile<uint32_t>(filePathString + fruTypeSuffix);
547 }
548 catch (const std::system_error& e)
549 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800550 log<level::DEBUG>(
Matt Spinlera26f1522021-08-25 15:50:20 -0500551 fmt::format("readTempSensors: Failed reading {}, errno = {}",
552 filePathString + fruTypeSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +0800553 .c_str());
554 continue;
555 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800556
557 std::string sensorPath =
558 OCC_SENSORS_ROOT + std::string("/temperature/");
559
Matt Spinlerace67d82021-10-18 13:41:57 -0500560 std::string dvfsTempPath;
561
Chicago Duanbb895cb2021-06-18 19:37:16 +0800562 if (fruTypeValue == VRMVdd)
563 {
564 sensorPath.append("vrm_vdd" + std::to_string(id) + "_temp");
565 }
Matt Spinlerace67d82021-10-18 13:41:57 -0500566 else if (fruTypeValue == processorIoRing)
567 {
568 sensorPath.append("proc" + std::to_string(id) + "_ioring_temp");
569 dvfsTempPath = std::string{OCC_SENSORS_ROOT} + "/temperature/proc" +
570 std::to_string(id) + "_ioring_dvfs_temp";
571 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800572 else
573 {
Matt Spinler14d14022021-08-25 15:38:29 -0500574 uint16_t type = (labelValue & 0xFF000000) >> 24;
575 uint16_t instanceID = labelValue & 0x0000FFFF;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800576
577 if (type == OCC_DIMM_TEMP_SENSOR_TYPE)
578 {
Matt Spinler8b8abee2021-08-25 15:18:21 -0500579 if (fruTypeValue == fruTypeNotAvailable)
580 {
581 // Not all DIMM related temps are available to read
582 // (no _input file in this case)
583 continue;
584 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800585 auto iter = dimmTempSensorName.find(fruTypeValue);
586 if (iter == dimmTempSensorName.end())
587 {
George Liub5ca1012021-09-10 12:53:11 +0800588 log<level::ERR>(
589 fmt::format(
590 "readTempSensors: Fru type error! fruTypeValue = {}) ",
591 fruTypeValue)
592 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800593 continue;
594 }
595
596 sensorPath.append("dimm" + std::to_string(instanceID) +
597 iter->second);
598 }
599 else if (type == OCC_CPU_TEMP_SENSOR_TYPE)
600 {
Matt Spinlerace67d82021-10-18 13:41:57 -0500601 if (fruTypeValue == processorCore)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800602 {
Matt Spinlerace67d82021-10-18 13:41:57 -0500603 // The OCC reports small core temps, of which there are
604 // two per big core. All current P10 systems are in big
605 // core mode, so use a big core name.
606 uint16_t coreNum = instanceID / 2;
607 uint16_t tempNum = instanceID % 2;
608 sensorPath.append("proc" + std::to_string(id) + "_core" +
609 std::to_string(coreNum) + "_" +
610 std::to_string(tempNum) + "_temp");
611
612 dvfsTempPath = std::string{OCC_SENSORS_ROOT} +
613 "/temperature/proc" + std::to_string(id) +
614 "_core_dvfs_temp";
615 }
616 else
617 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800618 continue;
619 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800620 }
621 else
622 {
623 continue;
624 }
625 }
626
Matt Spinlerace67d82021-10-18 13:41:57 -0500627 // The dvfs temp file only needs to be read once per chip per type.
628 if (!dvfsTempPath.empty() &&
629 !dbus::OccDBusSensors::getOccDBus().hasDvfsTemp(dvfsTempPath))
630 {
631 try
632 {
633 auto dvfsValue = readFile<double>(filePathString + maxSuffix);
634
635 dbus::OccDBusSensors::getOccDBus().setDvfsTemp(
636 dvfsTempPath, dvfsValue * std::pow(10, -3));
637 }
638 catch (const std::system_error& e)
639 {
640 log<level::DEBUG>(
641 fmt::format(
642 "readTempSensors: Failed reading {}, errno = {}",
643 filePathString + maxSuffix, e.code().value())
644 .c_str());
645 }
646 }
647
Matt Spinlera26f1522021-08-25 15:50:20 -0500648 uint32_t faultValue{0};
649 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800650 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500651 faultValue = readFile<uint32_t>(filePathString + faultSuffix);
652 }
653 catch (const std::system_error& e)
654 {
655 log<level::DEBUG>(
656 fmt::format("readTempSensors: Failed reading {}, errno = {}",
657 filePathString + faultSuffix, e.code().value())
658 .c_str());
659 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800660 }
661
Matt Spinlera26f1522021-08-25 15:50:20 -0500662 if (faultValue != 0)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800663 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800664 open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -0500665 sensorPath, std::numeric_limits<double>::quiet_NaN());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800666
667 open_power::occ::dbus::OccDBusSensors::getOccDBus()
Matt Spinlera26f1522021-08-25 15:50:20 -0500668 .setOperationalStatus(sensorPath, false);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800669
Matt Spinlera26f1522021-08-25 15:50:20 -0500670 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800671 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500672
673 double tempValue{0};
674
675 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800676 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500677 tempValue = readFile<double>(filePathString + inputSuffix);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800678 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500679 catch (const std::system_error& e)
680 {
681 log<level::DEBUG>(
682 fmt::format("readTempSensors: Failed reading {}, errno = {}",
683 filePathString + inputSuffix, e.code().value())
684 .c_str());
685 continue;
686 }
687
688 open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue(
689 sensorPath, tempValue * std::pow(10, -3));
690
691 open_power::occ::dbus::OccDBusSensors::getOccDBus()
692 .setOperationalStatus(sensorPath, true);
693
Chris Cain6fa848a2022-01-24 14:54:38 -0600694 // At this point, the sensor will be created for sure.
695 if (existingSensors.find(sensorPath) == existingSensors.end())
696 {
697 open_power::occ::dbus::OccDBusSensors::getOccDBus()
698 .setChassisAssociation(sensorPath);
699 }
700
Matt Spinlera26f1522021-08-25 15:50:20 -0500701 existingSensors[sensorPath] = id;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800702 }
703 return;
704}
705
706std::optional<std::string>
707 Manager::getPowerLabelFunctionID(const std::string& value)
708{
709 // If the value is "system", then the FunctionID is "system".
710 if (value == "system")
711 {
712 return value;
713 }
714
715 // If the value is not "system", then the label value have 3 numbers, of
716 // which we only care about the middle one:
717 // <sensor id>_<function id>_<apss channel>
718 // eg: The value is "0_10_5" , then the FunctionID is "10".
719 if (value.find("_") == std::string::npos)
720 {
721 return std::nullopt;
722 }
723
724 auto powerLabelValue = value.substr((value.find("_") + 1));
725
726 if (powerLabelValue.find("_") == std::string::npos)
727 {
728 return std::nullopt;
729 }
730
731 return powerLabelValue.substr(0, powerLabelValue.find("_"));
732}
733
734void Manager::readPowerSensors(const fs::path& path, uint32_t id)
735{
Chicago Duanbb895cb2021-06-18 19:37:16 +0800736 std::regex expr{"power\\d+_label$"}; // Example: power5_label
737 for (auto& file : fs::directory_iterator(path))
738 {
739 if (!std::regex_search(file.path().string(), expr))
740 {
741 continue;
742 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800743
Matt Spinlera26f1522021-08-25 15:50:20 -0500744 std::string labelValue;
745 try
746 {
747 labelValue = readFile<std::string>(file.path());
748 }
749 catch (const std::system_error& e)
750 {
751 log<level::DEBUG>(
752 fmt::format("readPowerSensors: Failed reading {}, errno = {}",
753 file.path().string(), e.code().value())
754 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800755 continue;
756 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800757
758 auto functionID = getPowerLabelFunctionID(labelValue);
759 if (functionID == std::nullopt)
760 {
761 continue;
762 }
763
764 const std::string& tempLabel = "label";
765 const std::string filePathString = file.path().string().substr(
766 0, file.path().string().length() - tempLabel.length());
767
768 std::string sensorPath = OCC_SENSORS_ROOT + std::string("/power/");
769
770 auto iter = powerSensorName.find(*functionID);
771 if (iter == powerSensorName.end())
772 {
773 continue;
774 }
775 sensorPath.append(iter->second);
776
Matt Spinlera26f1522021-08-25 15:50:20 -0500777 double tempValue{0};
778
779 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800780 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500781 tempValue = readFile<double>(filePathString + inputSuffix);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800782 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500783 catch (const std::system_error& e)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800784 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800785 log<level::DEBUG>(
Matt Spinlera26f1522021-08-25 15:50:20 -0500786 fmt::format("readTempSensors: Failed reading {}, errno = {}",
787 filePathString + inputSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +0800788 .c_str());
Matt Spinlera26f1522021-08-25 15:50:20 -0500789 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800790 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500791
Chris Caind84a8332022-01-13 08:58:45 -0600792 open_power::occ::dbus::OccDBusSensors::getOccDBus().setUnit(
793 sensorPath, "xyz.openbmc_project.Sensor.Value.Unit.Watts");
794
Matt Spinlera26f1522021-08-25 15:50:20 -0500795 open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue(
796 sensorPath, tempValue * std::pow(10, -3) * std::pow(10, -3));
797
798 open_power::occ::dbus::OccDBusSensors::getOccDBus()
799 .setOperationalStatus(sensorPath, true);
800
Matt Spinler5901abd2021-09-23 13:50:03 -0500801 if (existingSensors.find(sensorPath) == existingSensors.end())
802 {
803 open_power::occ::dbus::OccDBusSensors::getOccDBus()
804 .setChassisAssociation(sensorPath);
805 }
806
Matt Spinlera26f1522021-08-25 15:50:20 -0500807 existingSensors[sensorPath] = id;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800808 }
809 return;
810}
811
812void Manager::setSensorValueToNaN(uint32_t id)
813{
814 for (const auto& [sensorPath, occId] : existingSensors)
815 {
816 if (occId == id)
817 {
818 open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue(
819 sensorPath, std::numeric_limits<double>::quiet_NaN());
820 }
821 }
822 return;
823}
824
825void Manager::getSensorValues(uint32_t id, bool masterOcc)
826{
827 const auto occ = std::string("occ-hwmon.") + std::to_string(id + 1);
828
829 fs::path fileName{OCC_HWMON_PATH + occ + "/hwmon/"};
830
831 // Need to get the hwmonXX directory name, there better only be 1 dir
832 assert(std::distance(fs::directory_iterator(fileName),
833 fs::directory_iterator{}) == 1);
834 // Now set our path to this full path, including this hwmonXX directory
835 fileName = fs::path(*fs::directory_iterator(fileName));
836
837 // Read temperature sensors
838 readTempSensors(fileName, id);
839
840 if (masterOcc)
841 {
842 // Read power sensors
843 readPowerSensors(fileName, id);
844 }
845
846 return;
847}
848#endif
Chris Cain17257672021-10-22 13:41:03 -0500849
850// Read the altitude from DBus
851void Manager::readAltitude()
852{
853 static bool traceAltitudeErr = true;
854
855 utils::PropertyValue altitudeProperty{};
856 try
857 {
858 altitudeProperty = utils::getProperty(ALTITUDE_PATH, ALTITUDE_INTERFACE,
859 ALTITUDE_PROP);
860 auto sensorVal = std::get<double>(altitudeProperty);
861 if (sensorVal < 0xFFFF)
862 {
863 if (sensorVal < 0)
864 {
865 altitude = 0;
866 }
867 else
868 {
869 // Round to nearest meter
870 altitude = uint16_t(sensorVal + 0.5);
871 }
872 log<level::DEBUG>(fmt::format("readAltitude: sensor={} ({}m)",
873 sensorVal, altitude)
874 .c_str());
875 traceAltitudeErr = true;
876 }
877 else
878 {
879 if (traceAltitudeErr)
880 {
881 traceAltitudeErr = false;
882 log<level::DEBUG>(
883 fmt::format("Invalid altitude value: {}", sensorVal)
884 .c_str());
885 }
886 }
887 }
888 catch (const sdbusplus::exception::exception& e)
889 {
890 if (traceAltitudeErr)
891 {
892 traceAltitudeErr = false;
893 log<level::INFO>(
894 fmt::format("Unable to read Altitude: {}", e.what()).c_str());
895 }
896 altitude = 0xFFFF; // not available
897 }
898}
899
900// Callback function when ambient temperature changes
901void Manager::ambientCallback(sdbusplus::message::message& msg)
902{
903 double currentTemp = 0;
904 uint8_t truncatedTemp = 0xFF;
905 std::string msgSensor;
906 std::map<std::string, std::variant<double>> msgData;
907 msg.read(msgSensor, msgData);
908
909 auto valPropMap = msgData.find(AMBIENT_PROP);
910 if (valPropMap == msgData.end())
911 {
912 log<level::DEBUG>("ambientCallback: Unknown ambient property changed");
913 return;
914 }
915 currentTemp = std::get<double>(valPropMap->second);
916 if (std::isnan(currentTemp))
917 {
918 truncatedTemp = 0xFF;
919 }
920 else
921 {
922 if (currentTemp < 0)
923 {
924 truncatedTemp = 0;
925 }
926 else
927 {
928 // Round to nearest degree C
929 truncatedTemp = uint8_t(currentTemp + 0.5);
930 }
931 }
932
933 // If ambient changes, notify OCCs
934 if (truncatedTemp != ambient)
935 {
936 log<level::DEBUG>(
937 fmt::format("ambientCallback: Ambient change from {} to {}C",
938 ambient, currentTemp)
939 .c_str());
940
941 ambient = truncatedTemp;
942 if (altitude == 0xFFFF)
943 {
944 // No altitude yet, try reading again
945 readAltitude();
946 }
947
948 log<level::DEBUG>(
949 fmt::format("ambientCallback: Ambient: {}C, altitude: {}m", ambient,
950 altitude)
951 .c_str());
952#ifdef POWER10
953 // Send ambient and altitude to all OCCs
954 for (auto& obj : statusObjects)
955 {
956 if (obj->occActive())
957 {
958 obj->sendAmbient(ambient, altitude);
959 }
960 }
961#endif // POWER10
962 }
963}
964
965// return the current ambient and altitude readings
966void Manager::getAmbientData(bool& ambientValid, uint8_t& ambientTemp,
967 uint16_t& altitudeValue) const
968{
969 ambientValid = true;
970 ambientTemp = ambient;
971 altitudeValue = altitude;
972
973 if (ambient == 0xFF)
974 {
975 ambientValid = false;
976 }
977}
978
Chris Caina7b74dc2021-11-10 17:03:43 -0600979#ifdef POWER10
980void Manager::occsNotAllRunning()
981{
Chris Cain6fa848a2022-01-24 14:54:38 -0600982 // Function will also gets called when occ-control app gets
983 // restarted. (occ active sensors do not change, so the Status
984 // object does not call Manager back for all OCCs)
Chris Caina7b74dc2021-11-10 17:03:43 -0600985
986 if (activeCount != statusObjects.size())
987 {
988 // Not all OCCs went active
989 log<level::WARNING>(
990 fmt::format(
991 "occsNotAllRunning: Active OCC count ({}) does not match expected count ({})",
992 activeCount, statusObjects.size())
993 .c_str());
994 // Procs may be garded, so may not need reset.
995 }
996
997 validateOccMaster();
998}
999#endif // POWER10
1000
1001// Verify single master OCC and start presence monitor
1002void Manager::validateOccMaster()
1003{
1004 int masterInstance = -1;
1005 for (auto& obj : statusObjects)
1006 {
1007 obj->addPresenceWatchMaster();
1008 if (obj->isMasterOcc())
1009 {
1010 if (masterInstance == -1)
1011 {
1012 masterInstance = obj->getOccInstanceID();
1013 }
1014 else
1015 {
1016 log<level::ERR>(
1017 fmt::format(
1018 "validateOccMaster: Multiple OCC masters! ({} and {})",
1019 masterInstance, obj->getOccInstanceID())
1020 .c_str());
1021 // request reset
1022 obj->deviceError();
1023 }
1024 }
1025 }
1026 if (masterInstance < 0)
1027 {
1028 log<level::ERR>("validateOccMaster: Master OCC not found!");
1029 // request reset
1030 statusObjects.front()->deviceError();
1031 }
1032 else
1033 {
1034 log<level::INFO>(
Chris Cain36f9cde2021-11-22 11:18:21 -06001035 fmt::format("validateOccMaster: OCC{} is master of {} OCCs",
1036 masterInstance, activeCount)
Chris Caina7b74dc2021-11-10 17:03:43 -06001037 .c_str());
1038 }
1039}
1040
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +05301041} // namespace occ
1042} // namespace open_power