blob: 7c8c646944670daddec43c1f00b153357f965c44 [file] [log] [blame]
Brandon Wyman1d7a7df2020-03-26 10:14:05 -05001#include "config.h"
2
Brandon Wymanaed1f752019-11-25 18:10:52 -06003#include "power_supply.hpp"
4
5#include "types.hpp"
Brandon Wyman3f1242f2020-01-28 13:11:25 -06006#include "util.hpp"
Brandon Wymanaed1f752019-11-25 18:10:52 -06007
Brandon Wymandf13c3a2020-12-15 14:25:22 -06008#include <fmt/format.h>
9
Brandon Wyman3f1242f2020-01-28 13:11:25 -060010#include <xyz/openbmc_project/Common/Device/error.hpp>
11
Brandon Wyman4fc191f2022-03-10 23:07:13 +000012#include <chrono> // sleep_for()
13#include <cmath>
Brandon Wyman1d7a7df2020-03-26 10:14:05 -050014#include <cstdint> // uint8_t...
B. J. Wyman681b2a32021-04-20 22:31:22 +000015#include <fstream>
16#include <thread> // sleep_for()
Brandon Wyman1d7a7df2020-03-26 10:14:05 -050017
Brandon Wyman3f1242f2020-01-28 13:11:25 -060018namespace phosphor::power::psu
Brandon Wymanaed1f752019-11-25 18:10:52 -060019{
B. J. Wyman681b2a32021-04-20 22:31:22 +000020// Amount of time in milliseconds to delay between power supply going from
21// missing to present before running the bind command(s).
22constexpr auto bindDelay = 1000;
Brandon Wymanaed1f752019-11-25 18:10:52 -060023
24using namespace phosphor::logging;
Brandon Wyman3f1242f2020-01-28 13:11:25 -060025using namespace sdbusplus::xyz::openbmc_project::Common::Device::Error;
Brandon Wymanaed1f752019-11-25 18:10:52 -060026
Brandon Wyman510acaa2020-11-05 18:32:04 -060027PowerSupply::PowerSupply(sdbusplus::bus::bus& bus, const std::string& invpath,
B. J. Wyman681b2a32021-04-20 22:31:22 +000028 std::uint8_t i2cbus, std::uint16_t i2caddr,
29 const std::string& gpioLineName) :
Brandon Wyman510acaa2020-11-05 18:32:04 -060030 bus(bus),
B. J. Wyman681b2a32021-04-20 22:31:22 +000031 inventoryPath(invpath), bindPath("/sys/bus/i2c/drivers/ibm-cffps")
Brandon Wyman510acaa2020-11-05 18:32:04 -060032{
33 if (inventoryPath.empty())
34 {
35 throw std::invalid_argument{"Invalid empty inventoryPath"};
36 }
37
B. J. Wyman681b2a32021-04-20 22:31:22 +000038 if (gpioLineName.empty())
39 {
40 throw std::invalid_argument{"Invalid empty gpioLineName"};
41 }
Brandon Wyman510acaa2020-11-05 18:32:04 -060042
Brandon Wyman321a6152022-03-19 00:11:44 +000043 shortName = findShortName(inventoryPath);
44
45 log<level::DEBUG>(
46 fmt::format("{} gpioLineName: {}", shortName, gpioLineName).c_str());
B. J. Wyman681b2a32021-04-20 22:31:22 +000047 presenceGPIO = createGPIO(gpioLineName);
Brandon Wyman510acaa2020-11-05 18:32:04 -060048
49 std::ostringstream ss;
50 ss << std::hex << std::setw(4) << std::setfill('0') << i2caddr;
51 std::string addrStr = ss.str();
B. J. Wyman681b2a32021-04-20 22:31:22 +000052 std::string busStr = std::to_string(i2cbus);
53 bindDevice = busStr;
54 bindDevice.append("-");
55 bindDevice.append(addrStr);
56
Brandon Wyman510acaa2020-11-05 18:32:04 -060057 pmbusIntf = phosphor::pmbus::createPMBus(i2cbus, addrStr);
58
59 // Get the current state of the Present property.
B. J. Wyman681b2a32021-04-20 22:31:22 +000060 try
61 {
62 updatePresenceGPIO();
63 }
64 catch (...)
65 {
66 // If the above attempt to use the GPIO failed, it likely means that the
67 // GPIOs are in use by the kernel, meaning it is using gpio-keys.
68 // So, I should rely on phosphor-gpio-presence to update D-Bus, and
69 // work that way for power supply presence.
70 presenceGPIO = nullptr;
71 // Setup the functions to call when the D-Bus inventory path for the
72 // Present property changes.
73 presentMatch = std::make_unique<sdbusplus::bus::match_t>(
74 bus,
75 sdbusplus::bus::match::rules::propertiesChanged(inventoryPath,
76 INVENTORY_IFACE),
77 [this](auto& msg) { this->inventoryChanged(msg); });
78
79 presentAddedMatch = std::make_unique<sdbusplus::bus::match_t>(
80 bus,
81 sdbusplus::bus::match::rules::interfacesAdded() +
82 sdbusplus::bus::match::rules::argNpath(0, inventoryPath),
83 [this](auto& msg) { this->inventoryAdded(msg); });
84
85 updatePresence();
86 updateInventory();
87 }
88}
89
90void PowerSupply::bindOrUnbindDriver(bool present)
91{
92 auto action = (present) ? "bind" : "unbind";
93 auto path = bindPath / action;
94
95 if (present)
96 {
97 log<level::INFO>(
98 fmt::format("Binding device driver. path: {} device: {}",
99 path.string(), bindDevice)
100 .c_str());
101 }
102 else
103 {
104 log<level::INFO>(
105 fmt::format("Unbinding device driver. path: {} device: {}",
106 path.string(), bindDevice)
107 .c_str());
108 }
109
110 std::ofstream file;
111
112 file.exceptions(std::ofstream::failbit | std::ofstream::badbit |
113 std::ofstream::eofbit);
114
115 try
116 {
117 file.open(path);
118 file << bindDevice;
119 file.close();
120 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500121 catch (const std::exception& e)
B. J. Wyman681b2a32021-04-20 22:31:22 +0000122 {
123 auto err = errno;
124
125 log<level::ERR>(
126 fmt::format("Failed binding or unbinding device. errno={}", err)
127 .c_str());
128 }
Brandon Wyman510acaa2020-11-05 18:32:04 -0600129}
130
Brandon Wymanaed1f752019-11-25 18:10:52 -0600131void PowerSupply::updatePresence()
132{
133 try
134 {
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600135 present = getPresence(bus, inventoryPath);
Brandon Wymanaed1f752019-11-25 18:10:52 -0600136 }
Patrick Williams69f10ad2021-09-02 09:46:49 -0500137 catch (const sdbusplus::exception::exception& e)
Brandon Wymanaed1f752019-11-25 18:10:52 -0600138 {
139 // Relying on property change or interface added to retry.
140 // Log an informational trace to the journal.
Brandon Wymandf13c3a2020-12-15 14:25:22 -0600141 log<level::INFO>(
142 fmt::format("D-Bus property {} access failure exception",
143 inventoryPath)
144 .c_str());
Brandon Wymanaed1f752019-11-25 18:10:52 -0600145 }
146}
147
B. J. Wyman681b2a32021-04-20 22:31:22 +0000148void PowerSupply::updatePresenceGPIO()
149{
150 bool presentOld = present;
151
152 try
153 {
154 if (presenceGPIO->read() > 0)
155 {
156 present = true;
157 }
158 else
159 {
160 present = false;
161 }
162 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500163 catch (const std::exception& e)
B. J. Wyman681b2a32021-04-20 22:31:22 +0000164 {
165 log<level::ERR>(
166 fmt::format("presenceGPIO read fail: {}", e.what()).c_str());
167 throw;
168 }
169
170 if (presentOld != present)
171 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000172 log<level::DEBUG>(fmt::format("{} presentOld: {} present: {}",
173 shortName, presentOld, present)
174 .c_str());
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600175
176 auto invpath = inventoryPath.substr(strlen(INVENTORY_OBJ_PATH));
Brandon Wyman321a6152022-03-19 00:11:44 +0000177 setPresence(bus, invpath, present, shortName);
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600178 updateInventory();
179
180 // Need Functional to already be correct before calling this
181 checkAvailability();
182
B. J. Wyman681b2a32021-04-20 22:31:22 +0000183 if (present)
184 {
185 std::this_thread::sleep_for(std::chrono::milliseconds(bindDelay));
186 bindOrUnbindDriver(present);
187 pmbusIntf->findHwmonDir();
188 onOffConfig(phosphor::pmbus::ON_OFF_CONFIG_CONTROL_PIN_ONLY);
189 clearFaults();
190 }
191 else
192 {
193 bindOrUnbindDriver(present);
194 }
B. J. Wyman681b2a32021-04-20 22:31:22 +0000195 }
196}
197
Brandon Wymanc2203432021-12-21 23:09:48 +0000198void PowerSupply::analyzeCMLFault()
199{
200 if (statusWord & phosphor::pmbus::status_word::CML_FAULT)
201 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000202 if (cmlFault < DEGLITCH_LIMIT)
Brandon Wymanc2203432021-12-21 23:09:48 +0000203 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000204 if (statusWord != statusWordOld)
205 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000206 log<level::ERR>(
207 fmt::format("{} CML fault: STATUS_WORD = {:#06x}, "
208 "STATUS_CML = {:#02x}",
209 shortName, statusWord, statusCML)
210 .c_str());
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000211 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000212 cmlFault++;
213 }
214 }
215 else
216 {
217 cmlFault = 0;
Brandon Wymanc2203432021-12-21 23:09:48 +0000218 }
219}
220
Brandon Wymane3b0bb02021-12-21 23:16:48 +0000221void PowerSupply::analyzeInputFault()
222{
223 if (statusWord & phosphor::pmbus::status_word::INPUT_FAULT_WARN)
224 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000225 if (inputFault < DEGLITCH_LIMIT)
Brandon Wymane3b0bb02021-12-21 23:16:48 +0000226 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000227 if (statusWord != statusWordOld)
228 {
229 log<level::ERR>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000230 fmt::format("{} INPUT fault: STATUS_WORD = {:#06x}, "
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000231 "STATUS_MFR_SPECIFIC = {:#04x}, "
232 "STATUS_INPUT = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000233 shortName, statusWord, statusMFR, statusInput)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000234 .c_str());
235 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000236 inputFault++;
237 }
Brandon Wymane3b0bb02021-12-21 23:16:48 +0000238 }
Brandon Wyman82affd92021-11-24 19:12:49 +0000239
240 // If had INPUT/VIN_UV fault, and now off.
241 // Trace that odd behavior.
242 if (inputFault &&
243 !(statusWord & phosphor::pmbus::status_word::INPUT_FAULT_WARN))
244 {
245 log<level::INFO>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000246 fmt::format("{} INPUT fault cleared: STATUS_WORD = {:#06x}, "
Brandon Wyman6f939a32022-03-10 18:42:20 +0000247 "STATUS_MFR_SPECIFIC = {:#04x}, "
248 "STATUS_INPUT = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000249 shortName, statusWord, statusMFR, statusInput)
Brandon Wyman82affd92021-11-24 19:12:49 +0000250 .c_str());
Brandon Wymanc2906f42021-12-21 20:14:56 +0000251 inputFault = 0;
Brandon Wyman82affd92021-11-24 19:12:49 +0000252 }
Brandon Wymane3b0bb02021-12-21 23:16:48 +0000253}
254
Brandon Wymanc2c87132021-12-21 23:22:18 +0000255void PowerSupply::analyzeVoutOVFault()
256{
257 if (statusWord & phosphor::pmbus::status_word::VOUT_OV_FAULT)
258 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000259 if (voutOVFault < DEGLITCH_LIMIT)
Brandon Wymanc2c87132021-12-21 23:22:18 +0000260 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000261 if (statusWord != statusWordOld)
262 {
263 log<level::ERR>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000264 fmt::format(
265 "{} VOUT_OV_FAULT fault: STATUS_WORD = {:#06x}, "
266 "STATUS_MFR_SPECIFIC = {:#04x}, "
267 "STATUS_VOUT = {:#02x}",
268 shortName, statusWord, statusMFR, statusVout)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000269 .c_str());
270 }
Brandon Wymanc2c87132021-12-21 23:22:18 +0000271
Brandon Wymanc2906f42021-12-21 20:14:56 +0000272 voutOVFault++;
273 }
274 }
275 else
276 {
277 voutOVFault = 0;
Brandon Wymanc2c87132021-12-21 23:22:18 +0000278 }
279}
280
Brandon Wymana00e7302021-12-21 23:28:29 +0000281void PowerSupply::analyzeIoutOCFault()
282{
283 if (statusWord & phosphor::pmbus::status_word::IOUT_OC_FAULT)
284 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000285 if (ioutOCFault < DEGLITCH_LIMIT)
Brandon Wymana00e7302021-12-21 23:28:29 +0000286 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000287 if (statusWord != statusWordOld)
288 {
289 log<level::ERR>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000290 fmt::format("{} IOUT fault: STATUS_WORD = {:#06x}, "
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000291 "STATUS_MFR_SPECIFIC = {:#04x}, "
292 "STATUS_IOUT = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000293 shortName, statusWord, statusMFR, statusIout)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000294 .c_str());
295 }
Brandon Wymana00e7302021-12-21 23:28:29 +0000296
Brandon Wymanc2906f42021-12-21 20:14:56 +0000297 ioutOCFault++;
298 }
299 }
300 else
301 {
302 ioutOCFault = 0;
Brandon Wymana00e7302021-12-21 23:28:29 +0000303 }
304}
305
Brandon Wyman08378782021-12-21 23:48:15 +0000306void PowerSupply::analyzeVoutUVFault()
307{
308 if ((statusWord & phosphor::pmbus::status_word::VOUT_FAULT) &&
309 !(statusWord & phosphor::pmbus::status_word::VOUT_OV_FAULT))
310 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000311 if (voutUVFault < DEGLITCH_LIMIT)
Brandon Wyman08378782021-12-21 23:48:15 +0000312 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000313 if (statusWord != statusWordOld)
314 {
315 log<level::ERR>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000316 fmt::format(
317 "{} VOUT_UV_FAULT fault: STATUS_WORD = {:#06x}, "
318 "STATUS_MFR_SPECIFIC = {:#04x}, "
319 "STATUS_VOUT = {:#04x}",
320 shortName, statusWord, statusMFR, statusVout)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000321 .c_str());
322 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000323 voutUVFault++;
324 }
325 }
326 else
327 {
328 voutUVFault = 0;
Brandon Wyman08378782021-12-21 23:48:15 +0000329 }
330}
331
Brandon Wymand5d9a222021-12-21 23:59:05 +0000332void PowerSupply::analyzeFanFault()
333{
334 if (statusWord & phosphor::pmbus::status_word::FAN_FAULT)
335 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000336 if (fanFault < DEGLITCH_LIMIT)
Brandon Wymand5d9a222021-12-21 23:59:05 +0000337 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000338 if (statusWord != statusWordOld)
339 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000340 log<level::ERR>(fmt::format("{} FANS fault/warning: "
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000341 "STATUS_WORD = {:#06x}, "
342 "STATUS_MFR_SPECIFIC = {:#04x}, "
343 "STATUS_FANS_1_2 = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000344 shortName, statusWord, statusMFR,
345 statusFans12)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000346 .c_str());
347 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000348 fanFault++;
349 }
350 }
351 else
352 {
353 fanFault = 0;
Brandon Wymand5d9a222021-12-21 23:59:05 +0000354 }
355}
356
Brandon Wyman52cb3f22021-12-21 23:02:47 +0000357void PowerSupply::analyzeTemperatureFault()
358{
359 if (statusWord & phosphor::pmbus::status_word::TEMPERATURE_FAULT_WARN)
360 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000361 if (tempFault < DEGLITCH_LIMIT)
Brandon Wyman52cb3f22021-12-21 23:02:47 +0000362 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000363 if (statusWord != statusWordOld)
364 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000365 log<level::ERR>(fmt::format("{} TEMPERATURE fault/warning: "
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000366 "STATUS_WORD = {:#06x}, "
367 "STATUS_MFR_SPECIFIC = {:#04x}, "
368 "STATUS_TEMPERATURE = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000369 shortName, statusWord, statusMFR,
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000370 statusTemperature)
371 .c_str());
372 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000373 tempFault++;
374 }
375 }
376 else
377 {
378 tempFault = 0;
Brandon Wyman52cb3f22021-12-21 23:02:47 +0000379 }
380}
381
Brandon Wyman993b5542021-12-21 22:55:16 +0000382void PowerSupply::analyzePgoodFault()
383{
384 if ((statusWord & phosphor::pmbus::status_word::POWER_GOOD_NEGATED) ||
385 (statusWord & phosphor::pmbus::status_word::UNIT_IS_OFF))
386 {
387 if (pgoodFault < DEGLITCH_LIMIT)
388 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000389 if (statusWord != statusWordOld)
390 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000391 log<level::ERR>(fmt::format("{} PGOOD fault: "
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000392 "STATUS_WORD = {:#06x}, "
393 "STATUS_MFR_SPECIFIC = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000394 shortName, statusWord, statusMFR)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000395 .c_str());
396 }
Brandon Wyman993b5542021-12-21 22:55:16 +0000397 pgoodFault++;
398 }
399 }
400 else
401 {
402 pgoodFault = 0;
403 }
404}
405
Brandon Wyman39ea02b2021-11-23 23:22:23 +0000406void PowerSupply::determineMFRFault()
407{
408 if (bindPath.string().find("ibm-cffps") != std::string::npos)
409 {
410 // IBM MFR_SPECIFIC[4] is PS_Kill fault
411 if (statusMFR & 0x10)
412 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000413 if (psKillFault < DEGLITCH_LIMIT)
414 {
415 psKillFault++;
416 }
417 }
418 else
419 {
420 psKillFault = 0;
Brandon Wyman39ea02b2021-11-23 23:22:23 +0000421 }
422 // IBM MFR_SPECIFIC[6] is 12Vcs fault.
423 if (statusMFR & 0x40)
424 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000425 if (ps12VcsFault < DEGLITCH_LIMIT)
426 {
427 ps12VcsFault++;
428 }
429 }
430 else
431 {
432 ps12VcsFault = 0;
Brandon Wyman39ea02b2021-11-23 23:22:23 +0000433 }
434 // IBM MFR_SPECIFIC[7] is 12V Current-Share fault.
435 if (statusMFR & 0x80)
436 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000437 if (psCS12VFault < DEGLITCH_LIMIT)
438 {
439 psCS12VFault++;
440 }
441 }
442 else
443 {
444 psCS12VFault = 0;
Brandon Wyman39ea02b2021-11-23 23:22:23 +0000445 }
446 }
447}
448
Brandon Wyman6c2ac392021-12-21 22:23:06 +0000449void PowerSupply::analyzeMFRFault()
450{
451 if (statusWord & phosphor::pmbus::status_word::MFR_SPECIFIC_FAULT)
452 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000453 if (mfrFault < DEGLITCH_LIMIT)
Brandon Wyman6c2ac392021-12-21 22:23:06 +0000454 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000455 if (statusWord != statusWordOld)
456 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000457 log<level::ERR>(fmt::format("{} MFR fault: "
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000458 "STATUS_WORD = {:#06x} "
459 "STATUS_MFR_SPECIFIC = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000460 shortName, statusWord, statusMFR)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000461 .c_str());
462 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000463 mfrFault++;
Brandon Wyman6c2ac392021-12-21 22:23:06 +0000464 }
465
Brandon Wyman6c2ac392021-12-21 22:23:06 +0000466 determineMFRFault();
467 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000468 else
469 {
470 mfrFault = 0;
471 }
Brandon Wyman6c2ac392021-12-21 22:23:06 +0000472}
473
Brandon Wymanf087f472021-12-22 00:04:27 +0000474void PowerSupply::analyzeVinUVFault()
475{
476 if (statusWord & phosphor::pmbus::status_word::VIN_UV_FAULT)
477 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000478 if (vinUVFault < DEGLITCH_LIMIT)
Brandon Wymanf087f472021-12-22 00:04:27 +0000479 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000480 if (statusWord != statusWordOld)
481 {
482 log<level::ERR>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000483 fmt::format("{} VIN_UV fault: STATUS_WORD = {:#06x}, "
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000484 "STATUS_MFR_SPECIFIC = {:#04x}, "
485 "STATUS_INPUT = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000486 shortName, statusWord, statusMFR, statusInput)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000487 .c_str());
488 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000489 vinUVFault++;
Brandon Wymanf087f472021-12-22 00:04:27 +0000490 }
Brandon Wymanf087f472021-12-22 00:04:27 +0000491 }
Brandon Wyman82affd92021-11-24 19:12:49 +0000492
493 if (vinUVFault &&
494 !(statusWord & phosphor::pmbus::status_word::VIN_UV_FAULT))
495 {
496 log<level::INFO>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000497 fmt::format("{} VIN_UV fault cleared: STATUS_WORD = {:#06x}, "
Brandon Wyman6f939a32022-03-10 18:42:20 +0000498 "STATUS_MFR_SPECIFIC = {:#04x}, "
499 "STATUS_INPUT = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000500 shortName, statusWord, statusMFR, statusInput)
Brandon Wyman82affd92021-11-24 19:12:49 +0000501 .c_str());
Brandon Wymanc2906f42021-12-21 20:14:56 +0000502 vinUVFault = 0;
Brandon Wyman82affd92021-11-24 19:12:49 +0000503 }
Brandon Wymanf087f472021-12-22 00:04:27 +0000504}
505
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600506void PowerSupply::analyze()
507{
508 using namespace phosphor::pmbus;
509
B. J. Wyman681b2a32021-04-20 22:31:22 +0000510 if (presenceGPIO)
511 {
512 updatePresenceGPIO();
513 }
514
Brandon Wyman32453e92021-12-15 19:00:14 +0000515 if (present)
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600516 {
517 try
518 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000519 statusWordOld = statusWord;
Brandon Wyman32453e92021-12-15 19:00:14 +0000520 statusWord = pmbusIntf->read(STATUS_WORD, Type::Debug,
521 (readFail < LOG_LIMIT));
Brandon Wymanf65c4062020-08-19 13:15:53 -0500522 // Read worked, reset the fail count.
523 readFail = 0;
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600524
525 if (statusWord)
526 {
Brandon Wymanf07bc792021-10-12 19:00:35 +0000527 statusInput = pmbusIntf->read(STATUS_INPUT, Type::Debug);
Jay Meyer10d94052020-11-30 14:41:21 -0600528 statusMFR = pmbusIntf->read(STATUS_MFR, Type::Debug);
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000529 statusCML = pmbusIntf->read(STATUS_CML, Type::Debug);
Brandon Wyman6710ba22021-10-27 17:39:31 +0000530 auto status0Vout = pmbusIntf->insertPageNum(STATUS_VOUT, 0);
531 statusVout = pmbusIntf->read(status0Vout, Type::Debug);
Brandon Wymanb10b3be2021-11-09 22:12:15 +0000532 statusIout = pmbusIntf->read(STATUS_IOUT, Type::Debug);
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000533 statusFans12 = pmbusIntf->read(STATUS_FANS_1_2, Type::Debug);
Brandon Wyman96893a42021-11-05 19:56:57 +0000534 statusTemperature =
535 pmbusIntf->read(STATUS_TEMPERATURE, Type::Debug);
Brandon Wyman9ddc6222021-10-28 17:28:01 +0000536
Brandon Wymanc2203432021-12-21 23:09:48 +0000537 analyzeCMLFault();
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000538
Brandon Wymane3b0bb02021-12-21 23:16:48 +0000539 analyzeInputFault();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600540
Brandon Wymanc2c87132021-12-21 23:22:18 +0000541 analyzeVoutOVFault();
Brandon Wyman6710ba22021-10-27 17:39:31 +0000542
Brandon Wymana00e7302021-12-21 23:28:29 +0000543 analyzeIoutOCFault();
Brandon Wymanb10b3be2021-11-09 22:12:15 +0000544
Brandon Wyman08378782021-12-21 23:48:15 +0000545 analyzeVoutUVFault();
Brandon Wyman2cf46942021-10-28 19:09:16 +0000546
Brandon Wymand5d9a222021-12-21 23:59:05 +0000547 analyzeFanFault();
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000548
Brandon Wyman52cb3f22021-12-21 23:02:47 +0000549 analyzeTemperatureFault();
Brandon Wyman96893a42021-11-05 19:56:57 +0000550
Brandon Wyman993b5542021-12-21 22:55:16 +0000551 analyzePgoodFault();
Brandon Wyman2916ea52021-11-06 03:31:18 +0000552
Brandon Wyman6c2ac392021-12-21 22:23:06 +0000553 analyzeMFRFault();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600554
Brandon Wymanf087f472021-12-22 00:04:27 +0000555 analyzeVinUVFault();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600556 }
557 else
558 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000559 if (statusWord != statusWordOld)
560 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000561 log<level::INFO>(fmt::format("{} STATUS_WORD = {:#06x}",
562 shortName, statusWord)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000563 .c_str());
564 }
565
Brandon Wymane3f7ad22021-12-21 20:27:45 +0000566 // if INPUT/VIN_UV fault was on, it cleared, trace it.
567 if (inputFault)
568 {
569 log<level::INFO>(
570 fmt::format(
Brandon Wyman321a6152022-03-19 00:11:44 +0000571 "{} INPUT fault cleared: STATUS_WORD = {:#06x}",
572 shortName, statusWord)
Brandon Wymane3f7ad22021-12-21 20:27:45 +0000573 .c_str());
574 }
575
576 if (vinUVFault)
577 {
578 log<level::INFO>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000579 fmt::format("{} VIN_UV cleared: STATUS_WORD = {:#06x}",
580 shortName, statusWord)
Brandon Wymane3f7ad22021-12-21 20:27:45 +0000581 .c_str());
582 }
583
Brandon Wyman06ca4592021-12-06 22:52:23 +0000584 if (pgoodFault > 0)
Brandon Wyman4aecc292021-11-10 22:40:41 +0000585 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000586 log<level::INFO>(
587 fmt::format("{} pgoodFault cleared", shortName)
588 .c_str());
Brandon Wyman4aecc292021-11-10 22:40:41 +0000589 }
Brandon Wymane3f7ad22021-12-21 20:27:45 +0000590
591 clearFaultFlags();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600592 }
Brandon Wyman82affd92021-11-24 19:12:49 +0000593
594 // Save off old inputVoltage value.
595 // Get latest inputVoltage.
596 // If voltage went from below minimum, and now is not, clear faults.
597 // Note: getInputVoltage() has its own try/catch.
598 int inputVoltageOld = inputVoltage;
Brandon Wyman4fc191f2022-03-10 23:07:13 +0000599 double actualInputVoltageOld = actualInputVoltage;
Brandon Wyman82affd92021-11-24 19:12:49 +0000600 getInputVoltage(actualInputVoltage, inputVoltage);
601 if ((inputVoltageOld == in_input::VIN_VOLTAGE_0) &&
602 (inputVoltage != in_input::VIN_VOLTAGE_0))
603 {
604 log<level::INFO>(
605 fmt::format(
Brandon Wyman4fc191f2022-03-10 23:07:13 +0000606 "{} READ_VIN back in range: actualInputVoltageOld = {} "
607 "actualInputVoltage = {}",
608 shortName, actualInputVoltageOld, actualInputVoltage)
Brandon Wyman82affd92021-11-24 19:12:49 +0000609 .c_str());
610 clearFaults();
611 }
Brandon Wyman4fc191f2022-03-10 23:07:13 +0000612 else if (vinUVFault && (inputVoltage != in_input::VIN_VOLTAGE_0))
613 {
614 log<level::INFO>(
615 fmt::format(
616 "{} CLEAR_FAULTS: vinUVFault {} actualInputVoltage {}",
617 shortName, vinUVFault, actualInputVoltage)
618 .c_str());
619 // Do we have a VIN_UV fault latched that can now be cleared
620 // due to voltage back in range? Attempt to clear all
621 // faults, re-check faults on next call.
622 clearFaults();
623 }
624 else if (std::abs(actualInputVoltageOld - actualInputVoltage) > 1.0)
625 {
626 log<level::INFO>(
627 fmt::format(
628 "{} actualInputVoltageOld = {} actualInputVoltage = {}",
629 shortName, actualInputVoltageOld, actualInputVoltage)
630 .c_str());
631 }
Matt Spinler0975eaf2022-02-14 15:38:30 -0600632
633 checkAvailability();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600634 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500635 catch (const ReadFailure& e)
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600636 {
Brandon Wyman32453e92021-12-15 19:00:14 +0000637 if (readFail < SIZE_MAX)
638 {
639 readFail++;
640 }
641 if (readFail == LOG_LIMIT)
642 {
643 phosphor::logging::commit<ReadFailure>();
644 }
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600645 }
646 }
647}
648
Brandon Wyman59a35792020-06-04 12:37:40 -0500649void PowerSupply::onOffConfig(uint8_t data)
650{
651 using namespace phosphor::pmbus;
652
653 if (present)
654 {
655 log<level::INFO>("ON_OFF_CONFIG write", entry("DATA=0x%02X", data));
656 try
657 {
658 std::vector<uint8_t> configData{data};
659 pmbusIntf->writeBinary(ON_OFF_CONFIG, configData,
660 Type::HwmonDeviceDebug);
661 }
662 catch (...)
663 {
664 // The underlying code in writeBinary will log a message to the
B. J. Wyman681b2a32021-04-20 22:31:22 +0000665 // journal if the write fails. If the ON_OFF_CONFIG is not setup
666 // as desired, later fault detection and analysis code should
667 // catch any of the fall out. We should not need to terminate
668 // the application if this write fails.
Brandon Wyman59a35792020-06-04 12:37:40 -0500669 }
670 }
671}
672
Brandon Wyman3c208462020-05-13 16:25:58 -0500673void PowerSupply::clearFaults()
674{
Brandon Wyman82affd92021-11-24 19:12:49 +0000675 log<level::DEBUG>(
676 fmt::format("clearFaults() inventoryPath: {}", inventoryPath).c_str());
Brandon Wyman5474c912021-02-23 14:39:43 -0600677 faultLogged = false;
Brandon Wyman3c208462020-05-13 16:25:58 -0500678 // The PMBus device driver does not allow for writing CLEAR_FAULTS
679 // directly. However, the pmbus hwmon device driver code will send a
680 // CLEAR_FAULTS after reading from any of the hwmon "files" in sysfs, so
681 // reading in1_input should result in clearing the fault bits in
682 // STATUS_BYTE/STATUS_WORD.
683 // I do not care what the return value is.
Brandon Wyman11151532020-11-10 13:45:57 -0600684 if (present)
Brandon Wyman3c208462020-05-13 16:25:58 -0500685 {
Brandon Wymane3f7ad22021-12-21 20:27:45 +0000686 clearFaultFlags();
Matt Spinler0975eaf2022-02-14 15:38:30 -0600687 checkAvailability();
Brandon Wyman9564e942020-11-10 14:01:42 -0600688 readFail = 0;
Brandon Wyman9564e942020-11-10 14:01:42 -0600689
Brandon Wyman11151532020-11-10 13:45:57 -0600690 try
691 {
692 static_cast<void>(
693 pmbusIntf->read("in1_input", phosphor::pmbus::Type::Hwmon));
694 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500695 catch (const ReadFailure& e)
Brandon Wyman11151532020-11-10 13:45:57 -0600696 {
697 // Since I do not care what the return value is, I really do not
B. J. Wyman681b2a32021-04-20 22:31:22 +0000698 // care much if it gets a ReadFailure either. However, this
699 // should not prevent the application from continuing to run, so
700 // catching the read failure.
Brandon Wyman11151532020-11-10 13:45:57 -0600701 }
Brandon Wyman3c208462020-05-13 16:25:58 -0500702 }
703}
704
Brandon Wymanaed1f752019-11-25 18:10:52 -0600705void PowerSupply::inventoryChanged(sdbusplus::message::message& msg)
706{
707 std::string msgSensor;
Patrick Williamsabe49412020-05-13 17:59:47 -0500708 std::map<std::string, std::variant<uint32_t, bool>> msgData;
Brandon Wymanaed1f752019-11-25 18:10:52 -0600709 msg.read(msgSensor, msgData);
710
711 // Check if it was the Present property that changed.
712 auto valPropMap = msgData.find(PRESENT_PROP);
713 if (valPropMap != msgData.end())
714 {
715 if (std::get<bool>(valPropMap->second))
716 {
717 present = true;
B. J. Wyman681b2a32021-04-20 22:31:22 +0000718 // TODO: Immediately trying to read or write the "files" causes
719 // read or write failures.
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500720 using namespace std::chrono_literals;
721 std::this_thread::sleep_for(20ms);
Brandon Wyman9564e942020-11-10 14:01:42 -0600722 pmbusIntf->findHwmonDir();
Brandon Wyman59a35792020-06-04 12:37:40 -0500723 onOffConfig(phosphor::pmbus::ON_OFF_CONFIG_CONTROL_PIN_ONLY);
Brandon Wymanaed1f752019-11-25 18:10:52 -0600724 clearFaults();
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500725 updateInventory();
Brandon Wymanaed1f752019-11-25 18:10:52 -0600726 }
727 else
728 {
729 present = false;
730
731 // Clear out the now outdated inventory properties
732 updateInventory();
733 }
Matt Spinler0975eaf2022-02-14 15:38:30 -0600734 checkAvailability();
Brandon Wymanaed1f752019-11-25 18:10:52 -0600735 }
736}
737
Brandon Wyman9a507db2021-02-25 16:15:22 -0600738void PowerSupply::inventoryAdded(sdbusplus::message::message& msg)
739{
740 sdbusplus::message::object_path path;
741 msg.read(path);
742 // Make sure the signal is for the PSU inventory path
743 if (path == inventoryPath)
744 {
745 std::map<std::string, std::map<std::string, std::variant<bool>>>
746 interfaces;
747 // Get map of interfaces and their properties
748 msg.read(interfaces);
749
750 auto properties = interfaces.find(INVENTORY_IFACE);
751 if (properties != interfaces.end())
752 {
753 auto property = properties->second.find(PRESENT_PROP);
754 if (property != properties->second.end())
755 {
756 present = std::get<bool>(property->second);
757
758 log<level::INFO>(fmt::format("Power Supply {} Present {}",
759 inventoryPath, present)
760 .c_str());
761
762 updateInventory();
Matt Spinler0975eaf2022-02-14 15:38:30 -0600763 checkAvailability();
Brandon Wyman9a507db2021-02-25 16:15:22 -0600764 }
765 }
766 }
767}
768
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500769void PowerSupply::updateInventory()
770{
771 using namespace phosphor::pmbus;
772
Chanh Nguyenc12c53b2021-04-06 17:24:47 +0700773#if IBM_VPD
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500774 std::string ccin;
775 std::string pn;
776 std::string fn;
777 std::string header;
778 std::string sn;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500779 using PropertyMap =
George Liu070c1bc2020-10-12 11:28:01 +0800780 std::map<std::string,
781 std::variant<std::string, std::vector<uint8_t>, bool>>;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500782 PropertyMap assetProps;
George Liu070c1bc2020-10-12 11:28:01 +0800783 PropertyMap operProps;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500784 PropertyMap versionProps;
785 PropertyMap ipzvpdDINFProps;
786 PropertyMap ipzvpdVINIProps;
787 using InterfaceMap = std::map<std::string, PropertyMap>;
788 InterfaceMap interfaces;
789 using ObjectMap = std::map<sdbusplus::message::object_path, InterfaceMap>;
790 ObjectMap object;
791#endif
B. J. Wyman681b2a32021-04-20 22:31:22 +0000792 log<level::DEBUG>(
793 fmt::format("updateInventory() inventoryPath: {}", inventoryPath)
794 .c_str());
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500795
796 if (present)
797 {
798 // TODO: non-IBM inventory updates?
799
Chanh Nguyenc12c53b2021-04-06 17:24:47 +0700800#if IBM_VPD
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500801 try
802 {
803 ccin = pmbusIntf->readString(CCIN, Type::HwmonDeviceDebug);
804 assetProps.emplace(MODEL_PROP, ccin);
Adriana Kobylak572a9052021-03-30 15:58:07 +0000805 modelName = ccin;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500806 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500807 catch (const ReadFailure& e)
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500808 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000809 // Ignore the read failure, let pmbus code indicate failure,
810 // path...
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500811 // TODO - ibm918
812 // https://github.com/openbmc/docs/blob/master/designs/vpd-collection.md
813 // The BMC must log errors if any of the VPD cannot be properly
814 // parsed or fails ECC checks.
815 }
816
817 try
818 {
819 pn = pmbusIntf->readString(PART_NUMBER, Type::HwmonDeviceDebug);
820 assetProps.emplace(PN_PROP, pn);
821 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500822 catch (const ReadFailure& e)
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500823 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000824 // Ignore the read failure, let pmbus code indicate failure,
825 // path...
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500826 }
827
828 try
829 {
830 fn = pmbusIntf->readString(FRU_NUMBER, Type::HwmonDeviceDebug);
Brandon Wymana169b0f2021-12-07 20:18:06 +0000831 assetProps.emplace(SPARE_PN_PROP, fn);
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500832 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500833 catch (const ReadFailure& e)
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500834 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000835 // Ignore the read failure, let pmbus code indicate failure,
836 // path...
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500837 }
838
839 try
840 {
841 header =
842 pmbusIntf->readString(SERIAL_HEADER, Type::HwmonDeviceDebug);
843 sn = pmbusIntf->readString(SERIAL_NUMBER, Type::HwmonDeviceDebug);
Mike Capps1cb0f132022-03-14 11:40:30 -0400844 assetProps.emplace(SN_PROP, header + sn);
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500845 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500846 catch (const ReadFailure& e)
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500847 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000848 // Ignore the read failure, let pmbus code indicate failure,
849 // path...
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500850 }
851
852 try
853 {
Brandon Wymanc9efe412020-10-09 15:42:50 -0500854 fwVersion =
855 pmbusIntf->readString(FW_VERSION, Type::HwmonDeviceDebug);
856 versionProps.emplace(VERSION_PROP, fwVersion);
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500857 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500858 catch (const ReadFailure& e)
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500859 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000860 // Ignore the read failure, let pmbus code indicate failure,
861 // path...
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500862 }
863
864 ipzvpdVINIProps.emplace("CC",
865 std::vector<uint8_t>(ccin.begin(), ccin.end()));
866 ipzvpdVINIProps.emplace("PN",
867 std::vector<uint8_t>(pn.begin(), pn.end()));
868 ipzvpdVINIProps.emplace("FN",
869 std::vector<uint8_t>(fn.begin(), fn.end()));
870 std::string header_sn = header + sn + '\0';
871 ipzvpdVINIProps.emplace(
872 "SN", std::vector<uint8_t>(header_sn.begin(), header_sn.end()));
873 std::string description = "IBM PS";
874 ipzvpdVINIProps.emplace(
875 "DR", std::vector<uint8_t>(description.begin(), description.end()));
876
Ben Tynerf8d8c462022-01-27 16:09:45 -0600877 // Populate the VINI Resource Type (RT) keyword
878 ipzvpdVINIProps.emplace("RT", std::vector<uint8_t>{'V', 'I', 'N', 'I'});
879
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500880 // Update the Resource Identifier (RI) keyword
881 // 2 byte FRC: 0x0003
882 // 2 byte RID: 0x1000, 0x1001...
883 std::uint8_t num = std::stoul(
884 inventoryPath.substr(inventoryPath.size() - 1, 1), nullptr, 0);
885 std::vector<uint8_t> ri{0x00, 0x03, 0x10, num};
886 ipzvpdDINFProps.emplace("RI", ri);
887
888 // Fill in the FRU Label (FL) keyword.
889 std::string fl = "E";
890 fl.push_back(inventoryPath.back());
891 fl.resize(FL_KW_SIZE, ' ');
892 ipzvpdDINFProps.emplace("FL",
893 std::vector<uint8_t>(fl.begin(), fl.end()));
894
Ben Tynerf8d8c462022-01-27 16:09:45 -0600895 // Populate the DINF Resource Type (RT) keyword
896 ipzvpdDINFProps.emplace("RT", std::vector<uint8_t>{'D', 'I', 'N', 'F'});
897
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500898 interfaces.emplace(ASSET_IFACE, std::move(assetProps));
899 interfaces.emplace(VERSION_IFACE, std::move(versionProps));
900 interfaces.emplace(DINF_IFACE, std::move(ipzvpdDINFProps));
901 interfaces.emplace(VINI_IFACE, std::move(ipzvpdVINIProps));
902
George Liu070c1bc2020-10-12 11:28:01 +0800903 // Update the Functional
904 operProps.emplace(FUNCTIONAL_PROP, present);
905 interfaces.emplace(OPERATIONAL_STATE_IFACE, std::move(operProps));
906
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500907 auto path = inventoryPath.substr(strlen(INVENTORY_OBJ_PATH));
908 object.emplace(path, std::move(interfaces));
909
910 try
911 {
912 auto service =
913 util::getService(INVENTORY_OBJ_PATH, INVENTORY_MGR_IFACE, bus);
914
915 if (service.empty())
916 {
917 log<level::ERR>("Unable to get inventory manager service");
918 return;
919 }
920
921 auto method =
922 bus.new_method_call(service.c_str(), INVENTORY_OBJ_PATH,
923 INVENTORY_MGR_IFACE, "Notify");
924
925 method.append(std::move(object));
926
927 auto reply = bus.call(method);
928 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500929 catch (const std::exception& e)
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500930 {
Jay Meyer6a3fd2c2020-08-25 16:37:16 -0500931 log<level::ERR>(
932 std::string(e.what() + std::string(" PATH=") + inventoryPath)
933 .c_str());
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500934 }
935#endif
936 }
937}
938
Adriana Kobylak4175ffb2021-08-02 14:51:05 +0000939void PowerSupply::getInputVoltage(double& actualInputVoltage,
940 int& inputVoltage) const
941{
942 using namespace phosphor::pmbus;
943
944 actualInputVoltage = in_input::VIN_VOLTAGE_0;
945 inputVoltage = in_input::VIN_VOLTAGE_0;
946
947 if (present)
948 {
949 try
950 {
951 // Read input voltage in millivolts
952 auto inputVoltageStr = pmbusIntf->readString(READ_VIN, Type::Hwmon);
953
954 // Convert to volts
955 actualInputVoltage = std::stod(inputVoltageStr) / 1000;
956
957 // Calculate the voltage based on voltage thresholds
958 if (actualInputVoltage < in_input::VIN_VOLTAGE_MIN)
959 {
960 inputVoltage = in_input::VIN_VOLTAGE_0;
961 }
962 else if (actualInputVoltage < in_input::VIN_VOLTAGE_110_THRESHOLD)
963 {
964 inputVoltage = in_input::VIN_VOLTAGE_110;
965 }
966 else
967 {
968 inputVoltage = in_input::VIN_VOLTAGE_220;
969 }
970 }
971 catch (const std::exception& e)
972 {
973 log<level::ERR>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000974 fmt::format("{} READ_VIN read error: {}", shortName, e.what())
975 .c_str());
Adriana Kobylak4175ffb2021-08-02 14:51:05 +0000976 }
977 }
978}
979
Matt Spinler0975eaf2022-02-14 15:38:30 -0600980void PowerSupply::checkAvailability()
981{
982 bool origAvailability = available;
983 available = present && !hasInputFault() && !hasVINUVFault() &&
984 !hasPSKillFault() && !hasIoutOCFault();
985
986 if (origAvailability != available)
987 {
988 auto invpath = inventoryPath.substr(strlen(INVENTORY_OBJ_PATH));
989 phosphor::power::psu::setAvailable(bus, invpath, available);
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600990
991 // Check if the health rollup needs to change based on the
992 // new availability value.
993 phosphor::power::psu::handleChassisHealthRollup(bus, inventoryPath,
994 !available);
Matt Spinler0975eaf2022-02-14 15:38:30 -0600995 }
996}
997
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600998} // namespace phosphor::power::psu