blob: eadbca15bf4e4323f0d68bd291d5957fe938eaa8 [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>
Chicago Duanbb895cb2021-06-18 19:37:16 +080016#include <regex>
Gunnar Mills94df8c92018-09-14 14:50:03 -050017
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +053018namespace open_power
19{
20namespace occ
21{
22
Matt Spinler8b8abee2021-08-25 15:18:21 -050023constexpr uint32_t fruTypeNotAvailable = 0xFF;
Matt Spinlera26f1522021-08-25 15:50:20 -050024constexpr auto fruTypeSuffix = "fru_type";
25constexpr auto faultSuffix = "fault";
26constexpr auto inputSuffix = "input";
Matt Spinlerace67d82021-10-18 13:41:57 -050027constexpr auto maxSuffix = "max";
Matt Spinler8b8abee2021-08-25 15:18:21 -050028
Chris Caina8857c52021-01-27 11:53:05 -060029using namespace phosphor::logging;
30
Matt Spinlera26f1522021-08-25 15:50:20 -050031template <typename T>
32T readFile(const std::string& path)
33{
34 std::ifstream ifs;
35 ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit |
36 std::ifstream::eofbit);
37 T data;
38
39 try
40 {
41 ifs.open(path);
42 ifs >> data;
43 ifs.close();
44 }
45 catch (const std::exception& e)
46 {
47 auto err = errno;
48 throw std::system_error(err, std::generic_category());
49 }
50
51 return data;
52}
53
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +053054void Manager::findAndCreateObjects()
55{
Matt Spinlerd267cec2021-09-01 14:49:19 -050056#ifndef POWER10
Deepak Kodihalli370f06b2017-10-25 04:26:07 -050057 for (auto id = 0; id < MAX_CPUS; ++id)
58 {
Deepak Kodihalli30417a12017-12-04 00:54:01 -060059 // Create one occ per cpu
60 auto occ = std::string(OCC_NAME) + std::to_string(id);
61 createObjects(occ);
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +053062 }
Matt Spinlerd267cec2021-09-01 14:49:19 -050063#else
64 // Create the OCCs based on on the /dev/occX devices
65 auto occs = findOCCsInDev();
66
67 if (occs.empty() || (prevOCCSearch.size() != occs.size()))
68 {
69 // Something changed or no OCCs yet, try again in 10s.
70 // Note on the first pass prevOCCSearch will be empty,
71 // so there will be at least one delay to give things
72 // a chance to settle.
73 prevOCCSearch = occs;
74
75 using namespace std::literals::chrono_literals;
76 discoverTimer->restartOnce(10s);
77 }
78 else
79 {
80 discoverTimer.reset();
81
82 // createObjects requires OCC0 first.
83 std::sort(occs.begin(), occs.end());
84
85 for (auto id : occs)
86 {
87 createObjects(std::string(OCC_NAME) + std::to_string(id));
88 }
89 }
90#endif
91}
92
93std::vector<int> Manager::findOCCsInDev()
94{
95 std::vector<int> occs;
96 std::regex expr{R"(occ(\d+)$)"};
97
98 for (auto& file : fs::directory_iterator("/dev"))
99 {
100 std::smatch match;
101 std::string path{file.path().string()};
102 if (std::regex_search(path, match, expr))
103 {
104 auto num = std::stoi(match[1].str());
105
106 // /dev numbering starts at 1, ours starts at 0.
107 occs.push_back(num - 1);
108 }
109 }
110
111 return occs;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530112}
113
114int Manager::cpuCreated(sdbusplus::message::message& msg)
115{
George Liubcef3b42021-09-10 12:39:02 +0800116 namespace fs = std::filesystem;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530117
118 sdbusplus::message::object_path o;
119 msg.read(o);
120 fs::path cpuPath(std::string(std::move(o)));
121
122 auto name = cpuPath.filename().string();
123 auto index = name.find(CPU_NAME);
124 name.replace(index, std::strlen(CPU_NAME), OCC_NAME);
125
126 createObjects(name);
127
128 return 0;
129}
130
131void Manager::createObjects(const std::string& occ)
132{
133 auto path = fs::path(OCC_CONTROL_ROOT) / occ;
134
135 passThroughObjects.emplace_back(
George Liuf3b75142021-06-10 11:22:50 +0800136 std::make_unique<PassThrough>(path.c_str()));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530137
Gunnar Mills94df8c92018-09-14 14:50:03 -0500138 statusObjects.emplace_back(std::make_unique<Status>(
George Liuf3b75142021-06-10 11:22:50 +0800139 event, path.c_str(), *this,
Gunnar Mills94df8c92018-09-14 14:50:03 -0500140 std::bind(std::mem_fn(&Manager::statusCallBack), this,
Tom Joseph00325232020-07-29 17:51:48 +0530141 std::placeholders::_1)
142#ifdef PLDM
143 ,
144 std::bind(std::mem_fn(&pldm::Interface::resetOCC), pldmHandle.get(),
145 std::placeholders::_1)
146#endif
147 ));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530148
149 // Create the power cap monitor object for master occ (0)
150 if (!pcap)
151 {
152 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
George Liuf3b75142021-06-10 11:22:50 +0800153 *statusObjects.front());
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530154 }
Chris Cain78e86012021-03-04 16:15:31 -0600155
156#ifdef POWER10
157 // Create the power mode monitor object for master occ (0)
158 if (!pmode)
159 {
160 pmode = std::make_unique<open_power::occ::powermode::PowerMode>(
161 *statusObjects.front());
162 }
Chris Cain1d51da22021-09-21 14:13:41 -0500163 // Create the idle power saver monitor object for master occ (0)
164 if (!pips)
165 {
166 pips = std::make_unique<open_power::occ::powermode::PowerIPS>(
167 *statusObjects.front());
168 }
Chris Cain78e86012021-03-04 16:15:31 -0600169#endif
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530170}
171
172void Manager::statusCallBack(bool status)
173{
Gunnar Mills94df8c92018-09-14 14:50:03 -0500174 using InternalFailure =
175 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530176
177 // At this time, it won't happen but keeping it
178 // here just in case something changes in the future
179 if ((activeCount == 0) && (!status))
180 {
181 log<level::ERR>("Invalid update on OCCActive");
182 elog<InternalFailure>();
183 }
184
185 activeCount += status ? 1 : -1;
Eddie Jamesdae2d942017-12-20 10:50:03 -0600186
187 // Only start presence detection if all the OCCs are bound
188 if (activeCount == statusObjects.size())
189 {
Gunnar Mills94df8c92018-09-14 14:50:03 -0500190 for (auto& obj : statusObjects)
Eddie Jamesdae2d942017-12-20 10:50:03 -0600191 {
192 obj->addPresenceWatchMaster();
193 }
194 }
Chris Caina8857c52021-01-27 11:53:05 -0600195
196 if ((!_pollTimer->isEnabled()) && (activeCount > 0))
197 {
George Liub5ca1012021-09-10 12:53:11 +0800198 log<level::INFO>(
199 fmt::format(
200 "Manager::statusCallBack(): {} OCCs will be polled every {} seconds",
201 activeCount, pollInterval)
202 .c_str());
Chris Caina8857c52021-01-27 11:53:05 -0600203
204 // Send poll and start OCC poll timer
205 pollerTimerExpired();
206 }
207 else if ((_pollTimer->isEnabled()) && (activeCount == 0))
208 {
209 // Stop OCC poll timer
George Liub5ca1012021-09-10 12:53:11 +0800210 log<level::INFO>(
211 "Manager::statusCallBack(): OCCs are not running, stopping poll timer");
Chris Caina8857c52021-01-27 11:53:05 -0600212 _pollTimer->setEnabled(false);
Matt Spinler53f68142021-08-25 15:47:31 -0500213
214#ifdef READ_OCC_SENSORS
215 for (auto& obj : statusObjects)
216 {
217 setSensorValueToNaN(obj->getOccInstanceID());
218 }
219#endif
Chris Caina8857c52021-01-27 11:53:05 -0600220 }
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530221}
222
223#ifdef I2C_OCC
224void Manager::initStatusObjects()
225{
226 // Make sure we have a valid path string
227 static_assert(sizeof(DEV_PATH) != 0);
228
229 auto deviceNames = i2c_occ::getOccHwmonDevices(DEV_PATH);
Lei YU41470e52017-11-30 16:03:50 +0800230 auto occMasterName = deviceNames.front();
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530231 for (auto& name : deviceNames)
232 {
233 i2c_occ::i2cToDbus(name);
Lei YUb5259a12017-09-01 16:22:40 +0800234 name = std::string(OCC_NAME) + '_' + name;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530235 auto path = fs::path(OCC_CONTROL_ROOT) / name;
236 statusObjects.emplace_back(
George Liuf3b75142021-06-10 11:22:50 +0800237 std::make_unique<Status>(event, path.c_str(), *this));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530238 }
Lei YU41470e52017-11-30 16:03:50 +0800239 // The first device is master occ
240 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
George Liuf3b75142021-06-10 11:22:50 +0800241 *statusObjects.front(), occMasterName);
Chris Cain78e86012021-03-04 16:15:31 -0600242#ifdef POWER10
243 pmode = std::make_unique<open_power::occ::powermode::PowerMode>(
244 *statusObjects.front());
Chris Cain1d51da22021-09-21 14:13:41 -0500245 pips = std::make_unique<open_power::occ::powermode::PowerIPS>(
246 *statusObjects.front());
Chris Cain78e86012021-03-04 16:15:31 -0600247#endif
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530248}
249#endif
250
Tom Joseph815f9f52020-07-27 12:12:13 +0530251#ifdef PLDM
Eddie Jamescbad2192021-10-07 09:39:39 -0500252void Manager::sbeTimeout(unsigned int instance)
253{
254 log<level::INFO>("SBE timeout, requesting HRESET",
255 entry("SBE=%d", instance));
256
257 setSBEState(instance, SBE_STATE_NOT_USABLE);
258
259 pldmHandle->sendHRESET(instance);
260}
261
Tom Joseph815f9f52020-07-27 12:12:13 +0530262bool Manager::updateOCCActive(instanceID instance, bool status)
263{
264 return (statusObjects[instance])->occActive(status);
265}
Eddie Jamescbad2192021-10-07 09:39:39 -0500266
267void Manager::sbeHRESETResult(instanceID instance, bool success)
268{
269 if (success)
270 {
271 log<level::INFO>("HRESET succeeded", entry("SBE=%d", instance));
272
273 setSBEState(instance, SBE_STATE_BOOTED);
274
275 return;
276 }
277
278 setSBEState(instance, SBE_STATE_FAILED);
279
280 if (sbeCanDump(instance))
281 {
282 constexpr auto path = "/org/openpower/dump";
283 constexpr auto interface = "xyz.openbmc_project.Dump.Create";
284 constexpr auto function = "CreateDump";
285
286 log<level::INFO>("HRESET failed, triggering SBE dump",
287 entry("SBE=%d", instance));
288
289 auto& bus = utils::getBus();
290 uint32_t src6 = instance << 16;
291 uint32_t logId =
292 FFDC::createPEL("org.open_power.Processor.Error.SbeChipOpTimeout",
293 src6, "SBE command timeout");
294
295 try
296 {
297 std::string service = utils::getService(path, interface);
298 auto method =
299 bus.new_method_call(service.c_str(), path, interface, function);
300
301 std::map<std::string, std::variant<std::string, uint64_t>>
302 createParams{
303 {"com.ibm.Dump.Create.CreateParameters.ErrorLogId",
304 uint64_t(logId)},
305 {"com.ibm.Dump.Create.CreateParameters.DumpType",
306 "com.ibm.Dump.Create.DumpType.SBE"},
307 {"com.ibm.Dump.Create.CreateParameters.FailingUnitId",
308 uint64_t(instance)},
309 };
310
311 method.append(createParams);
312
313 auto response = bus.call(method);
314 }
315 catch (const sdbusplus::exception::exception& e)
316 {
317 constexpr auto ERROR_DUMP_DISABLED =
318 "xyz.openbmc_project.Dump.Create.Error.Disabled";
319 if (e.name() == ERROR_DUMP_DISABLED)
320 {
321 log<level::INFO>("Dump is disabled, skipping");
322 }
323 else
324 {
325 log<level::ERR>("Dump failed");
326 }
327 }
328 }
329}
330
331bool Manager::sbeCanDump(unsigned int instance)
332{
333 struct pdbg_target* proc = getPdbgTarget(instance);
334
335 if (!proc)
336 {
337 // allow the dump in the error case
338 return true;
339 }
340
341 try
342 {
343 if (!openpower::phal::sbe::isDumpAllowed(proc))
344 {
345 return false;
346 }
347
348 if (openpower::phal::pdbg::isSbeVitalAttnActive(proc))
349 {
350 return false;
351 }
352 }
353 catch (openpower::phal::exception::SbeError& e)
354 {
355 log<level::INFO>("Failed to query SBE state");
356 }
357
358 // allow the dump in the error case
359 return true;
360}
361
362void Manager::setSBEState(unsigned int instance, enum sbe_state state)
363{
364 struct pdbg_target* proc = getPdbgTarget(instance);
365
366 if (!proc)
367 {
368 return;
369 }
370
371 try
372 {
373 openpower::phal::sbe::setState(proc, state);
374 }
375 catch (const openpower::phal::exception::SbeError& e)
376 {
377 log<level::ERR>("Failed to set SBE state");
378 }
379}
380
381struct pdbg_target* Manager::getPdbgTarget(unsigned int instance)
382{
383 if (!pdbgInitialized)
384 {
385 try
386 {
387 openpower::phal::pdbg::init();
388 pdbgInitialized = true;
389 }
390 catch (const openpower::phal::exception::PdbgError& e)
391 {
392 log<level::ERR>("pdbg initialization failed");
393 return nullptr;
394 }
395 }
396
397 struct pdbg_target* proc = nullptr;
398 pdbg_for_each_class_target("proc", proc)
399 {
400 if (pdbg_target_index(proc) == instance)
401 {
402 return proc;
403 }
404 }
405
406 log<level::ERR>("Failed to get pdbg target");
407 return nullptr;
408}
Tom Joseph815f9f52020-07-27 12:12:13 +0530409#endif
410
Chris Caina8857c52021-01-27 11:53:05 -0600411void Manager::pollerTimerExpired()
412{
413 if (activeCount == 0)
414 {
415 // No OCCs running, so poll timer will not be restarted
George Liub5ca1012021-09-10 12:53:11 +0800416 log<level::INFO>(
417 "Manager::pollerTimerExpire(): No OCCs running, poll timer not restarted");
Chris Caina8857c52021-01-27 11:53:05 -0600418 }
419
420 if (!_pollTimer)
421 {
422 log<level::ERR>(
423 "Manager::pollerTimerExpired() ERROR: Timer not defined");
424 return;
425 }
426
427 for (auto& obj : statusObjects)
428 {
429 // Read sysfs to force kernel to poll OCC
430 obj->readOccState();
Chicago Duanbb895cb2021-06-18 19:37:16 +0800431
432#ifdef READ_OCC_SENSORS
433 // Read occ sensor values
434 auto id = obj->getOccInstanceID();
435 if (!obj->occActive())
436 {
437 // Occ not activated
438 setSensorValueToNaN(id);
439 continue;
440 }
441 getSensorValues(id, obj->isMasterOcc());
442#endif
Chris Caina8857c52021-01-27 11:53:05 -0600443 }
444
445 // Restart OCC poll timer
446 _pollTimer->restartOnce(std::chrono::seconds(pollInterval));
447}
448
Chicago Duanbb895cb2021-06-18 19:37:16 +0800449#ifdef READ_OCC_SENSORS
450void Manager::readTempSensors(const fs::path& path, uint32_t id)
451{
Chicago Duanbb895cb2021-06-18 19:37:16 +0800452 std::regex expr{"temp\\d+_label$"}; // Example: temp5_label
453 for (auto& file : fs::directory_iterator(path))
454 {
455 if (!std::regex_search(file.path().string(), expr))
456 {
457 continue;
458 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800459
Matt Spinlera26f1522021-08-25 15:50:20 -0500460 uint32_t labelValue{0};
461
462 try
463 {
464 labelValue = readFile<uint32_t>(file.path());
465 }
466 catch (const std::system_error& e)
467 {
468 log<level::DEBUG>(
469 fmt::format("readTempSensors: Failed reading {}, errno = {}",
470 file.path().string(), e.code().value())
471 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800472 continue;
473 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800474
475 const std::string& tempLabel = "label";
476 const std::string filePathString = file.path().string().substr(
477 0, file.path().string().length() - tempLabel.length());
Matt Spinlera26f1522021-08-25 15:50:20 -0500478
479 uint32_t fruTypeValue{0};
480 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800481 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500482 fruTypeValue = readFile<uint32_t>(filePathString + fruTypeSuffix);
483 }
484 catch (const std::system_error& e)
485 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800486 log<level::DEBUG>(
Matt Spinlera26f1522021-08-25 15:50:20 -0500487 fmt::format("readTempSensors: Failed reading {}, errno = {}",
488 filePathString + fruTypeSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +0800489 .c_str());
490 continue;
491 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800492
493 std::string sensorPath =
494 OCC_SENSORS_ROOT + std::string("/temperature/");
495
Matt Spinlerace67d82021-10-18 13:41:57 -0500496 std::string dvfsTempPath;
497
Chicago Duanbb895cb2021-06-18 19:37:16 +0800498 if (fruTypeValue == VRMVdd)
499 {
500 sensorPath.append("vrm_vdd" + std::to_string(id) + "_temp");
501 }
Matt Spinlerace67d82021-10-18 13:41:57 -0500502 else if (fruTypeValue == processorIoRing)
503 {
504 sensorPath.append("proc" + std::to_string(id) + "_ioring_temp");
505 dvfsTempPath = std::string{OCC_SENSORS_ROOT} + "/temperature/proc" +
506 std::to_string(id) + "_ioring_dvfs_temp";
507 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800508 else
509 {
Matt Spinler14d14022021-08-25 15:38:29 -0500510 uint16_t type = (labelValue & 0xFF000000) >> 24;
511 uint16_t instanceID = labelValue & 0x0000FFFF;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800512
513 if (type == OCC_DIMM_TEMP_SENSOR_TYPE)
514 {
Matt Spinler8b8abee2021-08-25 15:18:21 -0500515 if (fruTypeValue == fruTypeNotAvailable)
516 {
517 // Not all DIMM related temps are available to read
518 // (no _input file in this case)
519 continue;
520 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800521 auto iter = dimmTempSensorName.find(fruTypeValue);
522 if (iter == dimmTempSensorName.end())
523 {
George Liub5ca1012021-09-10 12:53:11 +0800524 log<level::ERR>(
525 fmt::format(
526 "readTempSensors: Fru type error! fruTypeValue = {}) ",
527 fruTypeValue)
528 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800529 continue;
530 }
531
532 sensorPath.append("dimm" + std::to_string(instanceID) +
533 iter->second);
534 }
535 else if (type == OCC_CPU_TEMP_SENSOR_TYPE)
536 {
Matt Spinlerace67d82021-10-18 13:41:57 -0500537 if (fruTypeValue == processorCore)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800538 {
Matt Spinlerace67d82021-10-18 13:41:57 -0500539 // The OCC reports small core temps, of which there are
540 // two per big core. All current P10 systems are in big
541 // core mode, so use a big core name.
542 uint16_t coreNum = instanceID / 2;
543 uint16_t tempNum = instanceID % 2;
544 sensorPath.append("proc" + std::to_string(id) + "_core" +
545 std::to_string(coreNum) + "_" +
546 std::to_string(tempNum) + "_temp");
547
548 dvfsTempPath = std::string{OCC_SENSORS_ROOT} +
549 "/temperature/proc" + std::to_string(id) +
550 "_core_dvfs_temp";
551 }
552 else
553 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800554 continue;
555 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800556 }
557 else
558 {
559 continue;
560 }
561 }
562
Matt Spinlerace67d82021-10-18 13:41:57 -0500563 // The dvfs temp file only needs to be read once per chip per type.
564 if (!dvfsTempPath.empty() &&
565 !dbus::OccDBusSensors::getOccDBus().hasDvfsTemp(dvfsTempPath))
566 {
567 try
568 {
569 auto dvfsValue = readFile<double>(filePathString + maxSuffix);
570
571 dbus::OccDBusSensors::getOccDBus().setDvfsTemp(
572 dvfsTempPath, dvfsValue * std::pow(10, -3));
573 }
574 catch (const std::system_error& e)
575 {
576 log<level::DEBUG>(
577 fmt::format(
578 "readTempSensors: Failed reading {}, errno = {}",
579 filePathString + maxSuffix, e.code().value())
580 .c_str());
581 }
582 }
583
Matt Spinlera26f1522021-08-25 15:50:20 -0500584 uint32_t faultValue{0};
585 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800586 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500587 faultValue = readFile<uint32_t>(filePathString + faultSuffix);
588 }
589 catch (const std::system_error& e)
590 {
591 log<level::DEBUG>(
592 fmt::format("readTempSensors: Failed reading {}, errno = {}",
593 filePathString + faultSuffix, e.code().value())
594 .c_str());
595 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800596 }
597
Matt Spinler5901abd2021-09-23 13:50:03 -0500598 // At this point, the sensor will be created for sure.
599 if (existingSensors.find(sensorPath) == existingSensors.end())
600 {
601 open_power::occ::dbus::OccDBusSensors::getOccDBus()
602 .setChassisAssociation(sensorPath);
603 }
604
Matt Spinlera26f1522021-08-25 15:50:20 -0500605 if (faultValue != 0)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800606 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800607 open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -0500608 sensorPath, std::numeric_limits<double>::quiet_NaN());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800609
610 open_power::occ::dbus::OccDBusSensors::getOccDBus()
Matt Spinlera26f1522021-08-25 15:50:20 -0500611 .setOperationalStatus(sensorPath, false);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800612
Matt Spinlera26f1522021-08-25 15:50:20 -0500613 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800614 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500615
616 double tempValue{0};
617
618 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800619 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500620 tempValue = readFile<double>(filePathString + inputSuffix);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800621 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500622 catch (const std::system_error& e)
623 {
624 log<level::DEBUG>(
625 fmt::format("readTempSensors: Failed reading {}, errno = {}",
626 filePathString + inputSuffix, e.code().value())
627 .c_str());
628 continue;
629 }
630
631 open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue(
632 sensorPath, tempValue * std::pow(10, -3));
633
634 open_power::occ::dbus::OccDBusSensors::getOccDBus()
635 .setOperationalStatus(sensorPath, true);
636
637 existingSensors[sensorPath] = id;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800638 }
639 return;
640}
641
642std::optional<std::string>
643 Manager::getPowerLabelFunctionID(const std::string& value)
644{
645 // If the value is "system", then the FunctionID is "system".
646 if (value == "system")
647 {
648 return value;
649 }
650
651 // If the value is not "system", then the label value have 3 numbers, of
652 // which we only care about the middle one:
653 // <sensor id>_<function id>_<apss channel>
654 // eg: The value is "0_10_5" , then the FunctionID is "10".
655 if (value.find("_") == std::string::npos)
656 {
657 return std::nullopt;
658 }
659
660 auto powerLabelValue = value.substr((value.find("_") + 1));
661
662 if (powerLabelValue.find("_") == std::string::npos)
663 {
664 return std::nullopt;
665 }
666
667 return powerLabelValue.substr(0, powerLabelValue.find("_"));
668}
669
670void Manager::readPowerSensors(const fs::path& path, uint32_t id)
671{
Chicago Duanbb895cb2021-06-18 19:37:16 +0800672 std::regex expr{"power\\d+_label$"}; // Example: power5_label
673 for (auto& file : fs::directory_iterator(path))
674 {
675 if (!std::regex_search(file.path().string(), expr))
676 {
677 continue;
678 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800679
Matt Spinlera26f1522021-08-25 15:50:20 -0500680 std::string labelValue;
681 try
682 {
683 labelValue = readFile<std::string>(file.path());
684 }
685 catch (const std::system_error& e)
686 {
687 log<level::DEBUG>(
688 fmt::format("readPowerSensors: Failed reading {}, errno = {}",
689 file.path().string(), e.code().value())
690 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800691 continue;
692 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800693
694 auto functionID = getPowerLabelFunctionID(labelValue);
695 if (functionID == std::nullopt)
696 {
697 continue;
698 }
699
700 const std::string& tempLabel = "label";
701 const std::string filePathString = file.path().string().substr(
702 0, file.path().string().length() - tempLabel.length());
703
704 std::string sensorPath = OCC_SENSORS_ROOT + std::string("/power/");
705
706 auto iter = powerSensorName.find(*functionID);
707 if (iter == powerSensorName.end())
708 {
709 continue;
710 }
711 sensorPath.append(iter->second);
712
Matt Spinlera26f1522021-08-25 15:50:20 -0500713 double tempValue{0};
714
715 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800716 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500717 tempValue = readFile<double>(filePathString + inputSuffix);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800718 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500719 catch (const std::system_error& e)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800720 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800721 log<level::DEBUG>(
Matt Spinlera26f1522021-08-25 15:50:20 -0500722 fmt::format("readTempSensors: Failed reading {}, errno = {}",
723 filePathString + inputSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +0800724 .c_str());
Matt Spinlera26f1522021-08-25 15:50:20 -0500725 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800726 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500727
728 open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue(
729 sensorPath, tempValue * std::pow(10, -3) * std::pow(10, -3));
730
731 open_power::occ::dbus::OccDBusSensors::getOccDBus()
732 .setOperationalStatus(sensorPath, true);
733
Matt Spinler5901abd2021-09-23 13:50:03 -0500734 if (existingSensors.find(sensorPath) == existingSensors.end())
735 {
736 open_power::occ::dbus::OccDBusSensors::getOccDBus()
737 .setChassisAssociation(sensorPath);
738 }
739
Matt Spinlera26f1522021-08-25 15:50:20 -0500740 existingSensors[sensorPath] = id;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800741 }
742 return;
743}
744
745void Manager::setSensorValueToNaN(uint32_t id)
746{
747 for (const auto& [sensorPath, occId] : existingSensors)
748 {
749 if (occId == id)
750 {
751 open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue(
752 sensorPath, std::numeric_limits<double>::quiet_NaN());
753 }
754 }
755 return;
756}
757
758void Manager::getSensorValues(uint32_t id, bool masterOcc)
759{
760 const auto occ = std::string("occ-hwmon.") + std::to_string(id + 1);
761
762 fs::path fileName{OCC_HWMON_PATH + occ + "/hwmon/"};
763
764 // Need to get the hwmonXX directory name, there better only be 1 dir
765 assert(std::distance(fs::directory_iterator(fileName),
766 fs::directory_iterator{}) == 1);
767 // Now set our path to this full path, including this hwmonXX directory
768 fileName = fs::path(*fs::directory_iterator(fileName));
769
770 // Read temperature sensors
771 readTempSensors(fileName, id);
772
773 if (masterOcc)
774 {
775 // Read power sensors
776 readPowerSensors(fileName, id);
777 }
778
779 return;
780}
781#endif
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530782} // namespace occ
783} // namespace open_power