blob: ed69274ac37e7519bbd0182b4235d2080e797d1c [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 Spinler8b8abee2021-08-25 15:18:21 -050027
Chris Caina8857c52021-01-27 11:53:05 -060028using namespace phosphor::logging;
29
Matt Spinlera26f1522021-08-25 15:50:20 -050030template <typename T>
31T readFile(const std::string& path)
32{
33 std::ifstream ifs;
34 ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit |
35 std::ifstream::eofbit);
36 T data;
37
38 try
39 {
40 ifs.open(path);
41 ifs >> data;
42 ifs.close();
43 }
44 catch (const std::exception& e)
45 {
46 auto err = errno;
47 throw std::system_error(err, std::generic_category());
48 }
49
50 return data;
51}
52
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +053053void Manager::findAndCreateObjects()
54{
Matt Spinlerd267cec2021-09-01 14:49:19 -050055#ifndef POWER10
Deepak Kodihalli370f06b2017-10-25 04:26:07 -050056 for (auto id = 0; id < MAX_CPUS; ++id)
57 {
Deepak Kodihalli30417a12017-12-04 00:54:01 -060058 // Create one occ per cpu
59 auto occ = std::string(OCC_NAME) + std::to_string(id);
60 createObjects(occ);
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +053061 }
Matt Spinlerd267cec2021-09-01 14:49:19 -050062#else
63 // Create the OCCs based on on the /dev/occX devices
64 auto occs = findOCCsInDev();
65
66 if (occs.empty() || (prevOCCSearch.size() != occs.size()))
67 {
68 // Something changed or no OCCs yet, try again in 10s.
69 // Note on the first pass prevOCCSearch will be empty,
70 // so there will be at least one delay to give things
71 // a chance to settle.
72 prevOCCSearch = occs;
73
74 using namespace std::literals::chrono_literals;
75 discoverTimer->restartOnce(10s);
76 }
77 else
78 {
79 discoverTimer.reset();
80
81 // createObjects requires OCC0 first.
82 std::sort(occs.begin(), occs.end());
83
84 for (auto id : occs)
85 {
86 createObjects(std::string(OCC_NAME) + std::to_string(id));
87 }
88 }
89#endif
90}
91
92std::vector<int> Manager::findOCCsInDev()
93{
94 std::vector<int> occs;
95 std::regex expr{R"(occ(\d+)$)"};
96
97 for (auto& file : fs::directory_iterator("/dev"))
98 {
99 std::smatch match;
100 std::string path{file.path().string()};
101 if (std::regex_search(path, match, expr))
102 {
103 auto num = std::stoi(match[1].str());
104
105 // /dev numbering starts at 1, ours starts at 0.
106 occs.push_back(num - 1);
107 }
108 }
109
110 return occs;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530111}
112
113int Manager::cpuCreated(sdbusplus::message::message& msg)
114{
George Liubcef3b42021-09-10 12:39:02 +0800115 namespace fs = std::filesystem;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530116
117 sdbusplus::message::object_path o;
118 msg.read(o);
119 fs::path cpuPath(std::string(std::move(o)));
120
121 auto name = cpuPath.filename().string();
122 auto index = name.find(CPU_NAME);
123 name.replace(index, std::strlen(CPU_NAME), OCC_NAME);
124
125 createObjects(name);
126
127 return 0;
128}
129
130void Manager::createObjects(const std::string& occ)
131{
132 auto path = fs::path(OCC_CONTROL_ROOT) / occ;
133
134 passThroughObjects.emplace_back(
George Liuf3b75142021-06-10 11:22:50 +0800135 std::make_unique<PassThrough>(path.c_str()));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530136
Gunnar Mills94df8c92018-09-14 14:50:03 -0500137 statusObjects.emplace_back(std::make_unique<Status>(
George Liuf3b75142021-06-10 11:22:50 +0800138 event, path.c_str(), *this,
Gunnar Mills94df8c92018-09-14 14:50:03 -0500139 std::bind(std::mem_fn(&Manager::statusCallBack), this,
Tom Joseph00325232020-07-29 17:51:48 +0530140 std::placeholders::_1)
141#ifdef PLDM
142 ,
143 std::bind(std::mem_fn(&pldm::Interface::resetOCC), pldmHandle.get(),
144 std::placeholders::_1)
145#endif
146 ));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530147
148 // Create the power cap monitor object for master occ (0)
149 if (!pcap)
150 {
151 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
George Liuf3b75142021-06-10 11:22:50 +0800152 *statusObjects.front());
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530153 }
Chris Cain78e86012021-03-04 16:15:31 -0600154
155#ifdef POWER10
156 // Create the power mode monitor object for master occ (0)
157 if (!pmode)
158 {
159 pmode = std::make_unique<open_power::occ::powermode::PowerMode>(
160 *statusObjects.front());
161 }
Chris Cain1d51da22021-09-21 14:13:41 -0500162 // Create the idle power saver monitor object for master occ (0)
163 if (!pips)
164 {
165 pips = std::make_unique<open_power::occ::powermode::PowerIPS>(
166 *statusObjects.front());
167 }
Chris Cain78e86012021-03-04 16:15:31 -0600168#endif
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530169}
170
171void Manager::statusCallBack(bool status)
172{
Gunnar Mills94df8c92018-09-14 14:50:03 -0500173 using InternalFailure =
174 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530175
176 // At this time, it won't happen but keeping it
177 // here just in case something changes in the future
178 if ((activeCount == 0) && (!status))
179 {
180 log<level::ERR>("Invalid update on OCCActive");
181 elog<InternalFailure>();
182 }
183
184 activeCount += status ? 1 : -1;
Eddie Jamesdae2d942017-12-20 10:50:03 -0600185
186 // Only start presence detection if all the OCCs are bound
187 if (activeCount == statusObjects.size())
188 {
Gunnar Mills94df8c92018-09-14 14:50:03 -0500189 for (auto& obj : statusObjects)
Eddie Jamesdae2d942017-12-20 10:50:03 -0600190 {
191 obj->addPresenceWatchMaster();
192 }
193 }
Chris Caina8857c52021-01-27 11:53:05 -0600194
195 if ((!_pollTimer->isEnabled()) && (activeCount > 0))
196 {
George Liub5ca1012021-09-10 12:53:11 +0800197 log<level::INFO>(
198 fmt::format(
199 "Manager::statusCallBack(): {} OCCs will be polled every {} seconds",
200 activeCount, pollInterval)
201 .c_str());
Chris Caina8857c52021-01-27 11:53:05 -0600202
203 // Send poll and start OCC poll timer
204 pollerTimerExpired();
205 }
206 else if ((_pollTimer->isEnabled()) && (activeCount == 0))
207 {
208 // Stop OCC poll timer
George Liub5ca1012021-09-10 12:53:11 +0800209 log<level::INFO>(
210 "Manager::statusCallBack(): OCCs are not running, stopping poll timer");
Chris Caina8857c52021-01-27 11:53:05 -0600211 _pollTimer->setEnabled(false);
Matt Spinler53f68142021-08-25 15:47:31 -0500212
213#ifdef READ_OCC_SENSORS
214 for (auto& obj : statusObjects)
215 {
216 setSensorValueToNaN(obj->getOccInstanceID());
217 }
218#endif
Chris Caina8857c52021-01-27 11:53:05 -0600219 }
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530220}
221
222#ifdef I2C_OCC
223void Manager::initStatusObjects()
224{
225 // Make sure we have a valid path string
226 static_assert(sizeof(DEV_PATH) != 0);
227
228 auto deviceNames = i2c_occ::getOccHwmonDevices(DEV_PATH);
Lei YU41470e52017-11-30 16:03:50 +0800229 auto occMasterName = deviceNames.front();
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530230 for (auto& name : deviceNames)
231 {
232 i2c_occ::i2cToDbus(name);
Lei YUb5259a12017-09-01 16:22:40 +0800233 name = std::string(OCC_NAME) + '_' + name;
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530234 auto path = fs::path(OCC_CONTROL_ROOT) / name;
235 statusObjects.emplace_back(
George Liuf3b75142021-06-10 11:22:50 +0800236 std::make_unique<Status>(event, path.c_str(), *this));
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530237 }
Lei YU41470e52017-11-30 16:03:50 +0800238 // The first device is master occ
239 pcap = std::make_unique<open_power::occ::powercap::PowerCap>(
George Liuf3b75142021-06-10 11:22:50 +0800240 *statusObjects.front(), occMasterName);
Chris Cain78e86012021-03-04 16:15:31 -0600241#ifdef POWER10
242 pmode = std::make_unique<open_power::occ::powermode::PowerMode>(
243 *statusObjects.front());
Chris Cain1d51da22021-09-21 14:13:41 -0500244 pips = std::make_unique<open_power::occ::powermode::PowerIPS>(
245 *statusObjects.front());
Chris Cain78e86012021-03-04 16:15:31 -0600246#endif
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530247}
248#endif
249
Tom Joseph815f9f52020-07-27 12:12:13 +0530250#ifdef PLDM
Eddie Jamescbad2192021-10-07 09:39:39 -0500251void Manager::sbeTimeout(unsigned int instance)
252{
253 log<level::INFO>("SBE timeout, requesting HRESET",
254 entry("SBE=%d", instance));
255
256 setSBEState(instance, SBE_STATE_NOT_USABLE);
257
258 pldmHandle->sendHRESET(instance);
259}
260
Tom Joseph815f9f52020-07-27 12:12:13 +0530261bool Manager::updateOCCActive(instanceID instance, bool status)
262{
263 return (statusObjects[instance])->occActive(status);
264}
Eddie Jamescbad2192021-10-07 09:39:39 -0500265
266void Manager::sbeHRESETResult(instanceID instance, bool success)
267{
268 if (success)
269 {
270 log<level::INFO>("HRESET succeeded", entry("SBE=%d", instance));
271
272 setSBEState(instance, SBE_STATE_BOOTED);
273
274 return;
275 }
276
277 setSBEState(instance, SBE_STATE_FAILED);
278
279 if (sbeCanDump(instance))
280 {
281 constexpr auto path = "/org/openpower/dump";
282 constexpr auto interface = "xyz.openbmc_project.Dump.Create";
283 constexpr auto function = "CreateDump";
284
285 log<level::INFO>("HRESET failed, triggering SBE dump",
286 entry("SBE=%d", instance));
287
288 auto& bus = utils::getBus();
289 uint32_t src6 = instance << 16;
290 uint32_t logId =
291 FFDC::createPEL("org.open_power.Processor.Error.SbeChipOpTimeout",
292 src6, "SBE command timeout");
293
294 try
295 {
296 std::string service = utils::getService(path, interface);
297 auto method =
298 bus.new_method_call(service.c_str(), path, interface, function);
299
300 std::map<std::string, std::variant<std::string, uint64_t>>
301 createParams{
302 {"com.ibm.Dump.Create.CreateParameters.ErrorLogId",
303 uint64_t(logId)},
304 {"com.ibm.Dump.Create.CreateParameters.DumpType",
305 "com.ibm.Dump.Create.DumpType.SBE"},
306 {"com.ibm.Dump.Create.CreateParameters.FailingUnitId",
307 uint64_t(instance)},
308 };
309
310 method.append(createParams);
311
312 auto response = bus.call(method);
313 }
314 catch (const sdbusplus::exception::exception& e)
315 {
316 constexpr auto ERROR_DUMP_DISABLED =
317 "xyz.openbmc_project.Dump.Create.Error.Disabled";
318 if (e.name() == ERROR_DUMP_DISABLED)
319 {
320 log<level::INFO>("Dump is disabled, skipping");
321 }
322 else
323 {
324 log<level::ERR>("Dump failed");
325 }
326 }
327 }
328}
329
330bool Manager::sbeCanDump(unsigned int instance)
331{
332 struct pdbg_target* proc = getPdbgTarget(instance);
333
334 if (!proc)
335 {
336 // allow the dump in the error case
337 return true;
338 }
339
340 try
341 {
342 if (!openpower::phal::sbe::isDumpAllowed(proc))
343 {
344 return false;
345 }
346
347 if (openpower::phal::pdbg::isSbeVitalAttnActive(proc))
348 {
349 return false;
350 }
351 }
352 catch (openpower::phal::exception::SbeError& e)
353 {
354 log<level::INFO>("Failed to query SBE state");
355 }
356
357 // allow the dump in the error case
358 return true;
359}
360
361void Manager::setSBEState(unsigned int instance, enum sbe_state state)
362{
363 struct pdbg_target* proc = getPdbgTarget(instance);
364
365 if (!proc)
366 {
367 return;
368 }
369
370 try
371 {
372 openpower::phal::sbe::setState(proc, state);
373 }
374 catch (const openpower::phal::exception::SbeError& e)
375 {
376 log<level::ERR>("Failed to set SBE state");
377 }
378}
379
380struct pdbg_target* Manager::getPdbgTarget(unsigned int instance)
381{
382 if (!pdbgInitialized)
383 {
384 try
385 {
386 openpower::phal::pdbg::init();
387 pdbgInitialized = true;
388 }
389 catch (const openpower::phal::exception::PdbgError& e)
390 {
391 log<level::ERR>("pdbg initialization failed");
392 return nullptr;
393 }
394 }
395
396 struct pdbg_target* proc = nullptr;
397 pdbg_for_each_class_target("proc", proc)
398 {
399 if (pdbg_target_index(proc) == instance)
400 {
401 return proc;
402 }
403 }
404
405 log<level::ERR>("Failed to get pdbg target");
406 return nullptr;
407}
Tom Joseph815f9f52020-07-27 12:12:13 +0530408#endif
409
Chris Caina8857c52021-01-27 11:53:05 -0600410void Manager::pollerTimerExpired()
411{
412 if (activeCount == 0)
413 {
414 // No OCCs running, so poll timer will not be restarted
George Liub5ca1012021-09-10 12:53:11 +0800415 log<level::INFO>(
416 "Manager::pollerTimerExpire(): No OCCs running, poll timer not restarted");
Chris Caina8857c52021-01-27 11:53:05 -0600417 }
418
419 if (!_pollTimer)
420 {
421 log<level::ERR>(
422 "Manager::pollerTimerExpired() ERROR: Timer not defined");
423 return;
424 }
425
426 for (auto& obj : statusObjects)
427 {
428 // Read sysfs to force kernel to poll OCC
429 obj->readOccState();
Chicago Duanbb895cb2021-06-18 19:37:16 +0800430
431#ifdef READ_OCC_SENSORS
432 // Read occ sensor values
433 auto id = obj->getOccInstanceID();
434 if (!obj->occActive())
435 {
436 // Occ not activated
437 setSensorValueToNaN(id);
438 continue;
439 }
440 getSensorValues(id, obj->isMasterOcc());
441#endif
Chris Caina8857c52021-01-27 11:53:05 -0600442 }
443
444 // Restart OCC poll timer
445 _pollTimer->restartOnce(std::chrono::seconds(pollInterval));
446}
447
Chicago Duanbb895cb2021-06-18 19:37:16 +0800448#ifdef READ_OCC_SENSORS
449void Manager::readTempSensors(const fs::path& path, uint32_t id)
450{
Chicago Duanbb895cb2021-06-18 19:37:16 +0800451 std::regex expr{"temp\\d+_label$"}; // Example: temp5_label
452 for (auto& file : fs::directory_iterator(path))
453 {
454 if (!std::regex_search(file.path().string(), expr))
455 {
456 continue;
457 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800458
Matt Spinlera26f1522021-08-25 15:50:20 -0500459 uint32_t labelValue{0};
460
461 try
462 {
463 labelValue = readFile<uint32_t>(file.path());
464 }
465 catch (const std::system_error& e)
466 {
467 log<level::DEBUG>(
468 fmt::format("readTempSensors: Failed reading {}, errno = {}",
469 file.path().string(), e.code().value())
470 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800471 continue;
472 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800473
474 const std::string& tempLabel = "label";
475 const std::string filePathString = file.path().string().substr(
476 0, file.path().string().length() - tempLabel.length());
Matt Spinlera26f1522021-08-25 15:50:20 -0500477
478 uint32_t fruTypeValue{0};
479 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800480 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500481 fruTypeValue = readFile<uint32_t>(filePathString + fruTypeSuffix);
482 }
483 catch (const std::system_error& e)
484 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800485 log<level::DEBUG>(
Matt Spinlera26f1522021-08-25 15:50:20 -0500486 fmt::format("readTempSensors: Failed reading {}, errno = {}",
487 filePathString + fruTypeSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +0800488 .c_str());
489 continue;
490 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800491
492 std::string sensorPath =
493 OCC_SENSORS_ROOT + std::string("/temperature/");
494
495 if (fruTypeValue == VRMVdd)
496 {
497 sensorPath.append("vrm_vdd" + std::to_string(id) + "_temp");
498 }
499 else
500 {
Matt Spinler14d14022021-08-25 15:38:29 -0500501 uint16_t type = (labelValue & 0xFF000000) >> 24;
502 uint16_t instanceID = labelValue & 0x0000FFFF;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800503
504 if (type == OCC_DIMM_TEMP_SENSOR_TYPE)
505 {
Matt Spinler8b8abee2021-08-25 15:18:21 -0500506 if (fruTypeValue == fruTypeNotAvailable)
507 {
508 // Not all DIMM related temps are available to read
509 // (no _input file in this case)
510 continue;
511 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800512 auto iter = dimmTempSensorName.find(fruTypeValue);
513 if (iter == dimmTempSensorName.end())
514 {
George Liub5ca1012021-09-10 12:53:11 +0800515 log<level::ERR>(
516 fmt::format(
517 "readTempSensors: Fru type error! fruTypeValue = {}) ",
518 fruTypeValue)
519 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800520 continue;
521 }
522
523 sensorPath.append("dimm" + std::to_string(instanceID) +
524 iter->second);
525 }
526 else if (type == OCC_CPU_TEMP_SENSOR_TYPE)
527 {
528 if (fruTypeValue != processorCore)
529 {
Matt Spinlerabbcfc52021-08-25 15:22:22 -0500530 // TODO: support IO ring temp
Chicago Duanbb895cb2021-06-18 19:37:16 +0800531 continue;
532 }
533
Matt Spinlerff7afd92021-09-17 13:23:58 -0500534 // The OCC reports small core temps, of which there are
535 // two per big core. All current P10 systems are in big
536 // core mode, so use a big core name.
537 uint16_t coreNum = instanceID / 2;
538 uint16_t tempNum = instanceID % 2;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800539 sensorPath.append("proc" + std::to_string(id) + "_core" +
Matt Spinlerff7afd92021-09-17 13:23:58 -0500540 std::to_string(coreNum) + "_" +
541 std::to_string(tempNum) + "_temp");
Chicago Duanbb895cb2021-06-18 19:37:16 +0800542 }
543 else
544 {
545 continue;
546 }
547 }
548
Matt Spinlera26f1522021-08-25 15:50:20 -0500549 uint32_t faultValue{0};
550 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800551 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500552 faultValue = readFile<uint32_t>(filePathString + faultSuffix);
553 }
554 catch (const std::system_error& e)
555 {
556 log<level::DEBUG>(
557 fmt::format("readTempSensors: Failed reading {}, errno = {}",
558 filePathString + faultSuffix, e.code().value())
559 .c_str());
560 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800561 }
562
Matt Spinler5901abd2021-09-23 13:50:03 -0500563 // At this point, the sensor will be created for sure.
564 if (existingSensors.find(sensorPath) == existingSensors.end())
565 {
566 open_power::occ::dbus::OccDBusSensors::getOccDBus()
567 .setChassisAssociation(sensorPath);
568 }
569
Matt Spinlera26f1522021-08-25 15:50:20 -0500570 if (faultValue != 0)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800571 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800572 open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue(
Matt Spinlera26f1522021-08-25 15:50:20 -0500573 sensorPath, std::numeric_limits<double>::quiet_NaN());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800574
575 open_power::occ::dbus::OccDBusSensors::getOccDBus()
Matt Spinlera26f1522021-08-25 15:50:20 -0500576 .setOperationalStatus(sensorPath, false);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800577
Matt Spinlera26f1522021-08-25 15:50:20 -0500578 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800579 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500580
581 double tempValue{0};
582
583 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800584 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500585 tempValue = readFile<double>(filePathString + inputSuffix);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800586 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500587 catch (const std::system_error& e)
588 {
589 log<level::DEBUG>(
590 fmt::format("readTempSensors: Failed reading {}, errno = {}",
591 filePathString + inputSuffix, e.code().value())
592 .c_str());
593 continue;
594 }
595
596 open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue(
597 sensorPath, tempValue * std::pow(10, -3));
598
599 open_power::occ::dbus::OccDBusSensors::getOccDBus()
600 .setOperationalStatus(sensorPath, true);
601
602 existingSensors[sensorPath] = id;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800603 }
604 return;
605}
606
607std::optional<std::string>
608 Manager::getPowerLabelFunctionID(const std::string& value)
609{
610 // If the value is "system", then the FunctionID is "system".
611 if (value == "system")
612 {
613 return value;
614 }
615
616 // If the value is not "system", then the label value have 3 numbers, of
617 // which we only care about the middle one:
618 // <sensor id>_<function id>_<apss channel>
619 // eg: The value is "0_10_5" , then the FunctionID is "10".
620 if (value.find("_") == std::string::npos)
621 {
622 return std::nullopt;
623 }
624
625 auto powerLabelValue = value.substr((value.find("_") + 1));
626
627 if (powerLabelValue.find("_") == std::string::npos)
628 {
629 return std::nullopt;
630 }
631
632 return powerLabelValue.substr(0, powerLabelValue.find("_"));
633}
634
635void Manager::readPowerSensors(const fs::path& path, uint32_t id)
636{
Chicago Duanbb895cb2021-06-18 19:37:16 +0800637 std::regex expr{"power\\d+_label$"}; // Example: power5_label
638 for (auto& file : fs::directory_iterator(path))
639 {
640 if (!std::regex_search(file.path().string(), expr))
641 {
642 continue;
643 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800644
Matt Spinlera26f1522021-08-25 15:50:20 -0500645 std::string labelValue;
646 try
647 {
648 labelValue = readFile<std::string>(file.path());
649 }
650 catch (const std::system_error& e)
651 {
652 log<level::DEBUG>(
653 fmt::format("readPowerSensors: Failed reading {}, errno = {}",
654 file.path().string(), e.code().value())
655 .c_str());
Chicago Duanbb895cb2021-06-18 19:37:16 +0800656 continue;
657 }
Chicago Duanbb895cb2021-06-18 19:37:16 +0800658
659 auto functionID = getPowerLabelFunctionID(labelValue);
660 if (functionID == std::nullopt)
661 {
662 continue;
663 }
664
665 const std::string& tempLabel = "label";
666 const std::string filePathString = file.path().string().substr(
667 0, file.path().string().length() - tempLabel.length());
668
669 std::string sensorPath = OCC_SENSORS_ROOT + std::string("/power/");
670
671 auto iter = powerSensorName.find(*functionID);
672 if (iter == powerSensorName.end())
673 {
674 continue;
675 }
676 sensorPath.append(iter->second);
677
Matt Spinlera26f1522021-08-25 15:50:20 -0500678 double tempValue{0};
679
680 try
Chicago Duanbb895cb2021-06-18 19:37:16 +0800681 {
Matt Spinlera26f1522021-08-25 15:50:20 -0500682 tempValue = readFile<double>(filePathString + inputSuffix);
Chicago Duanbb895cb2021-06-18 19:37:16 +0800683 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500684 catch (const std::system_error& e)
Chicago Duanbb895cb2021-06-18 19:37:16 +0800685 {
Chicago Duanbb895cb2021-06-18 19:37:16 +0800686 log<level::DEBUG>(
Matt Spinlera26f1522021-08-25 15:50:20 -0500687 fmt::format("readTempSensors: Failed reading {}, errno = {}",
688 filePathString + inputSuffix, e.code().value())
Chicago Duanbb895cb2021-06-18 19:37:16 +0800689 .c_str());
Matt Spinlera26f1522021-08-25 15:50:20 -0500690 continue;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800691 }
Matt Spinlera26f1522021-08-25 15:50:20 -0500692
693 open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue(
694 sensorPath, tempValue * std::pow(10, -3) * std::pow(10, -3));
695
696 open_power::occ::dbus::OccDBusSensors::getOccDBus()
697 .setOperationalStatus(sensorPath, true);
698
Matt Spinler5901abd2021-09-23 13:50:03 -0500699 if (existingSensors.find(sensorPath) == existingSensors.end())
700 {
701 open_power::occ::dbus::OccDBusSensors::getOccDBus()
702 .setChassisAssociation(sensorPath);
703 }
704
Matt Spinlera26f1522021-08-25 15:50:20 -0500705 existingSensors[sensorPath] = id;
Chicago Duanbb895cb2021-06-18 19:37:16 +0800706 }
707 return;
708}
709
710void Manager::setSensorValueToNaN(uint32_t id)
711{
712 for (const auto& [sensorPath, occId] : existingSensors)
713 {
714 if (occId == id)
715 {
716 open_power::occ::dbus::OccDBusSensors::getOccDBus().setValue(
717 sensorPath, std::numeric_limits<double>::quiet_NaN());
718 }
719 }
720 return;
721}
722
723void Manager::getSensorValues(uint32_t id, bool masterOcc)
724{
725 const auto occ = std::string("occ-hwmon.") + std::to_string(id + 1);
726
727 fs::path fileName{OCC_HWMON_PATH + occ + "/hwmon/"};
728
729 // Need to get the hwmonXX directory name, there better only be 1 dir
730 assert(std::distance(fs::directory_iterator(fileName),
731 fs::directory_iterator{}) == 1);
732 // Now set our path to this full path, including this hwmonXX directory
733 fileName = fs::path(*fs::directory_iterator(fileName));
734
735 // Read temperature sensors
736 readTempSensors(fileName, id);
737
738 if (masterOcc)
739 {
740 // Read power sensors
741 readPowerSensors(fileName, id);
742 }
743
744 return;
745}
746#endif
Vishwanatha Subbannadfc7ec72017-09-07 18:18:01 +0530747} // namespace occ
748} // namespace open_power