blob: 1648bd30d4d68f2d30a780d96bd2e8875b8f9fcb [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 Wyman1d7a7df2020-03-26 10:14:05 -050012#include <chrono> // sleep_for()
13#include <cstdint> // uint8_t...
B. J. Wyman681b2a32021-04-20 22:31:22 +000014#include <fstream>
15#include <thread> // sleep_for()
Brandon Wyman1d7a7df2020-03-26 10:14:05 -050016
Brandon Wyman3f1242f2020-01-28 13:11:25 -060017namespace phosphor::power::psu
Brandon Wymanaed1f752019-11-25 18:10:52 -060018{
B. J. Wyman681b2a32021-04-20 22:31:22 +000019// Amount of time in milliseconds to delay between power supply going from
20// missing to present before running the bind command(s).
21constexpr auto bindDelay = 1000;
Brandon Wymanaed1f752019-11-25 18:10:52 -060022
23using namespace phosphor::logging;
Brandon Wyman3f1242f2020-01-28 13:11:25 -060024using namespace sdbusplus::xyz::openbmc_project::Common::Device::Error;
Brandon Wymanaed1f752019-11-25 18:10:52 -060025
Brandon Wyman510acaa2020-11-05 18:32:04 -060026PowerSupply::PowerSupply(sdbusplus::bus::bus& bus, const std::string& invpath,
B. J. Wyman681b2a32021-04-20 22:31:22 +000027 std::uint8_t i2cbus, std::uint16_t i2caddr,
28 const std::string& gpioLineName) :
Brandon Wyman510acaa2020-11-05 18:32:04 -060029 bus(bus),
B. J. Wyman681b2a32021-04-20 22:31:22 +000030 inventoryPath(invpath), bindPath("/sys/bus/i2c/drivers/ibm-cffps")
Brandon Wyman510acaa2020-11-05 18:32:04 -060031{
32 if (inventoryPath.empty())
33 {
34 throw std::invalid_argument{"Invalid empty inventoryPath"};
35 }
36
B. J. Wyman681b2a32021-04-20 22:31:22 +000037 if (gpioLineName.empty())
38 {
39 throw std::invalid_argument{"Invalid empty gpioLineName"};
40 }
Brandon Wyman510acaa2020-11-05 18:32:04 -060041
Brandon Wyman321a6152022-03-19 00:11:44 +000042 shortName = findShortName(inventoryPath);
43
44 log<level::DEBUG>(
45 fmt::format("{} gpioLineName: {}", shortName, gpioLineName).c_str());
B. J. Wyman681b2a32021-04-20 22:31:22 +000046 presenceGPIO = createGPIO(gpioLineName);
Brandon Wyman510acaa2020-11-05 18:32:04 -060047
48 std::ostringstream ss;
49 ss << std::hex << std::setw(4) << std::setfill('0') << i2caddr;
50 std::string addrStr = ss.str();
B. J. Wyman681b2a32021-04-20 22:31:22 +000051 std::string busStr = std::to_string(i2cbus);
52 bindDevice = busStr;
53 bindDevice.append("-");
54 bindDevice.append(addrStr);
55
Brandon Wyman510acaa2020-11-05 18:32:04 -060056 pmbusIntf = phosphor::pmbus::createPMBus(i2cbus, addrStr);
57
58 // Get the current state of the Present property.
B. J. Wyman681b2a32021-04-20 22:31:22 +000059 try
60 {
61 updatePresenceGPIO();
62 }
63 catch (...)
64 {
65 // If the above attempt to use the GPIO failed, it likely means that the
66 // GPIOs are in use by the kernel, meaning it is using gpio-keys.
67 // So, I should rely on phosphor-gpio-presence to update D-Bus, and
68 // work that way for power supply presence.
69 presenceGPIO = nullptr;
70 // Setup the functions to call when the D-Bus inventory path for the
71 // Present property changes.
72 presentMatch = std::make_unique<sdbusplus::bus::match_t>(
73 bus,
74 sdbusplus::bus::match::rules::propertiesChanged(inventoryPath,
75 INVENTORY_IFACE),
76 [this](auto& msg) { this->inventoryChanged(msg); });
77
78 presentAddedMatch = std::make_unique<sdbusplus::bus::match_t>(
79 bus,
80 sdbusplus::bus::match::rules::interfacesAdded() +
81 sdbusplus::bus::match::rules::argNpath(0, inventoryPath),
82 [this](auto& msg) { this->inventoryAdded(msg); });
83
84 updatePresence();
85 updateInventory();
86 }
87}
88
89void PowerSupply::bindOrUnbindDriver(bool present)
90{
91 auto action = (present) ? "bind" : "unbind";
92 auto path = bindPath / action;
93
94 if (present)
95 {
96 log<level::INFO>(
97 fmt::format("Binding device driver. path: {} device: {}",
98 path.string(), bindDevice)
99 .c_str());
100 }
101 else
102 {
103 log<level::INFO>(
104 fmt::format("Unbinding device driver. path: {} device: {}",
105 path.string(), bindDevice)
106 .c_str());
107 }
108
109 std::ofstream file;
110
111 file.exceptions(std::ofstream::failbit | std::ofstream::badbit |
112 std::ofstream::eofbit);
113
114 try
115 {
116 file.open(path);
117 file << bindDevice;
118 file.close();
119 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500120 catch (const std::exception& e)
B. J. Wyman681b2a32021-04-20 22:31:22 +0000121 {
122 auto err = errno;
123
124 log<level::ERR>(
125 fmt::format("Failed binding or unbinding device. errno={}", err)
126 .c_str());
127 }
Brandon Wyman510acaa2020-11-05 18:32:04 -0600128}
129
Brandon Wymanaed1f752019-11-25 18:10:52 -0600130void PowerSupply::updatePresence()
131{
132 try
133 {
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600134 present = getPresence(bus, inventoryPath);
Brandon Wymanaed1f752019-11-25 18:10:52 -0600135 }
Patrick Williams69f10ad2021-09-02 09:46:49 -0500136 catch (const sdbusplus::exception::exception& e)
Brandon Wymanaed1f752019-11-25 18:10:52 -0600137 {
138 // Relying on property change or interface added to retry.
139 // Log an informational trace to the journal.
Brandon Wymandf13c3a2020-12-15 14:25:22 -0600140 log<level::INFO>(
141 fmt::format("D-Bus property {} access failure exception",
142 inventoryPath)
143 .c_str());
Brandon Wymanaed1f752019-11-25 18:10:52 -0600144 }
145}
146
B. J. Wyman681b2a32021-04-20 22:31:22 +0000147void PowerSupply::updatePresenceGPIO()
148{
149 bool presentOld = present;
150
151 try
152 {
153 if (presenceGPIO->read() > 0)
154 {
155 present = true;
156 }
157 else
158 {
159 present = false;
160 }
161 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500162 catch (const std::exception& e)
B. J. Wyman681b2a32021-04-20 22:31:22 +0000163 {
164 log<level::ERR>(
165 fmt::format("presenceGPIO read fail: {}", e.what()).c_str());
166 throw;
167 }
168
169 if (presentOld != present)
170 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000171 log<level::DEBUG>(fmt::format("{} presentOld: {} present: {}",
172 shortName, presentOld, present)
173 .c_str());
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600174
175 auto invpath = inventoryPath.substr(strlen(INVENTORY_OBJ_PATH));
Brandon Wyman321a6152022-03-19 00:11:44 +0000176 setPresence(bus, invpath, present, shortName);
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600177 updateInventory();
178
179 // Need Functional to already be correct before calling this
180 checkAvailability();
181
B. J. Wyman681b2a32021-04-20 22:31:22 +0000182 if (present)
183 {
184 std::this_thread::sleep_for(std::chrono::milliseconds(bindDelay));
185 bindOrUnbindDriver(present);
186 pmbusIntf->findHwmonDir();
187 onOffConfig(phosphor::pmbus::ON_OFF_CONFIG_CONTROL_PIN_ONLY);
188 clearFaults();
189 }
190 else
191 {
192 bindOrUnbindDriver(present);
193 }
B. J. Wyman681b2a32021-04-20 22:31:22 +0000194 }
195}
196
Brandon Wymanc2203432021-12-21 23:09:48 +0000197void PowerSupply::analyzeCMLFault()
198{
199 if (statusWord & phosphor::pmbus::status_word::CML_FAULT)
200 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000201 if (cmlFault < DEGLITCH_LIMIT)
Brandon Wymanc2203432021-12-21 23:09:48 +0000202 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000203 if (statusWord != statusWordOld)
204 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000205 log<level::ERR>(
206 fmt::format("{} CML fault: STATUS_WORD = {:#06x}, "
207 "STATUS_CML = {:#02x}",
208 shortName, statusWord, statusCML)
209 .c_str());
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000210 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000211 cmlFault++;
212 }
213 }
214 else
215 {
216 cmlFault = 0;
Brandon Wymanc2203432021-12-21 23:09:48 +0000217 }
218}
219
Brandon Wymane3b0bb02021-12-21 23:16:48 +0000220void PowerSupply::analyzeInputFault()
221{
222 if (statusWord & phosphor::pmbus::status_word::INPUT_FAULT_WARN)
223 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000224 if (inputFault < DEGLITCH_LIMIT)
Brandon Wymane3b0bb02021-12-21 23:16:48 +0000225 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000226 if (statusWord != statusWordOld)
227 {
228 log<level::ERR>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000229 fmt::format("{} INPUT fault: STATUS_WORD = {:#06x}, "
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000230 "STATUS_MFR_SPECIFIC = {:#04x}, "
231 "STATUS_INPUT = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000232 shortName, statusWord, statusMFR, statusInput)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000233 .c_str());
234 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000235 inputFault++;
236 }
Brandon Wymane3b0bb02021-12-21 23:16:48 +0000237 }
Brandon Wyman82affd92021-11-24 19:12:49 +0000238
239 // If had INPUT/VIN_UV fault, and now off.
240 // Trace that odd behavior.
241 if (inputFault &&
242 !(statusWord & phosphor::pmbus::status_word::INPUT_FAULT_WARN))
243 {
244 log<level::INFO>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000245 fmt::format("{} INPUT fault cleared: STATUS_WORD = {:#06x}, "
Brandon Wyman6f939a32022-03-10 18:42:20 +0000246 "STATUS_MFR_SPECIFIC = {:#04x}, "
247 "STATUS_INPUT = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000248 shortName, statusWord, statusMFR, statusInput)
Brandon Wyman82affd92021-11-24 19:12:49 +0000249 .c_str());
Brandon Wymanc2906f42021-12-21 20:14:56 +0000250 inputFault = 0;
Brandon Wyman82affd92021-11-24 19:12:49 +0000251 }
Brandon Wymane3b0bb02021-12-21 23:16:48 +0000252}
253
Brandon Wymanc2c87132021-12-21 23:22:18 +0000254void PowerSupply::analyzeVoutOVFault()
255{
256 if (statusWord & phosphor::pmbus::status_word::VOUT_OV_FAULT)
257 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000258 if (voutOVFault < DEGLITCH_LIMIT)
Brandon Wymanc2c87132021-12-21 23:22:18 +0000259 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000260 if (statusWord != statusWordOld)
261 {
262 log<level::ERR>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000263 fmt::format(
264 "{} VOUT_OV_FAULT fault: STATUS_WORD = {:#06x}, "
265 "STATUS_MFR_SPECIFIC = {:#04x}, "
266 "STATUS_VOUT = {:#02x}",
267 shortName, statusWord, statusMFR, statusVout)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000268 .c_str());
269 }
Brandon Wymanc2c87132021-12-21 23:22:18 +0000270
Brandon Wymanc2906f42021-12-21 20:14:56 +0000271 voutOVFault++;
272 }
273 }
274 else
275 {
276 voutOVFault = 0;
Brandon Wymanc2c87132021-12-21 23:22:18 +0000277 }
278}
279
Brandon Wymana00e7302021-12-21 23:28:29 +0000280void PowerSupply::analyzeIoutOCFault()
281{
282 if (statusWord & phosphor::pmbus::status_word::IOUT_OC_FAULT)
283 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000284 if (ioutOCFault < DEGLITCH_LIMIT)
Brandon Wymana00e7302021-12-21 23:28:29 +0000285 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000286 if (statusWord != statusWordOld)
287 {
288 log<level::ERR>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000289 fmt::format("{} IOUT fault: STATUS_WORD = {:#06x}, "
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000290 "STATUS_MFR_SPECIFIC = {:#04x}, "
291 "STATUS_IOUT = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000292 shortName, statusWord, statusMFR, statusIout)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000293 .c_str());
294 }
Brandon Wymana00e7302021-12-21 23:28:29 +0000295
Brandon Wymanc2906f42021-12-21 20:14:56 +0000296 ioutOCFault++;
297 }
298 }
299 else
300 {
301 ioutOCFault = 0;
Brandon Wymana00e7302021-12-21 23:28:29 +0000302 }
303}
304
Brandon Wyman08378782021-12-21 23:48:15 +0000305void PowerSupply::analyzeVoutUVFault()
306{
307 if ((statusWord & phosphor::pmbus::status_word::VOUT_FAULT) &&
308 !(statusWord & phosphor::pmbus::status_word::VOUT_OV_FAULT))
309 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000310 if (voutUVFault < DEGLITCH_LIMIT)
Brandon Wyman08378782021-12-21 23:48:15 +0000311 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000312 if (statusWord != statusWordOld)
313 {
314 log<level::ERR>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000315 fmt::format(
316 "{} VOUT_UV_FAULT fault: STATUS_WORD = {:#06x}, "
317 "STATUS_MFR_SPECIFIC = {:#04x}, "
318 "STATUS_VOUT = {:#04x}",
319 shortName, statusWord, statusMFR, statusVout)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000320 .c_str());
321 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000322 voutUVFault++;
323 }
324 }
325 else
326 {
327 voutUVFault = 0;
Brandon Wyman08378782021-12-21 23:48:15 +0000328 }
329}
330
Brandon Wymand5d9a222021-12-21 23:59:05 +0000331void PowerSupply::analyzeFanFault()
332{
333 if (statusWord & phosphor::pmbus::status_word::FAN_FAULT)
334 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000335 if (fanFault < DEGLITCH_LIMIT)
Brandon Wymand5d9a222021-12-21 23:59:05 +0000336 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000337 if (statusWord != statusWordOld)
338 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000339 log<level::ERR>(fmt::format("{} FANS fault/warning: "
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000340 "STATUS_WORD = {:#06x}, "
341 "STATUS_MFR_SPECIFIC = {:#04x}, "
342 "STATUS_FANS_1_2 = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000343 shortName, statusWord, statusMFR,
344 statusFans12)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000345 .c_str());
346 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000347 fanFault++;
348 }
349 }
350 else
351 {
352 fanFault = 0;
Brandon Wymand5d9a222021-12-21 23:59:05 +0000353 }
354}
355
Brandon Wyman52cb3f22021-12-21 23:02:47 +0000356void PowerSupply::analyzeTemperatureFault()
357{
358 if (statusWord & phosphor::pmbus::status_word::TEMPERATURE_FAULT_WARN)
359 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000360 if (tempFault < DEGLITCH_LIMIT)
Brandon Wyman52cb3f22021-12-21 23:02:47 +0000361 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000362 if (statusWord != statusWordOld)
363 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000364 log<level::ERR>(fmt::format("{} TEMPERATURE fault/warning: "
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000365 "STATUS_WORD = {:#06x}, "
366 "STATUS_MFR_SPECIFIC = {:#04x}, "
367 "STATUS_TEMPERATURE = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000368 shortName, statusWord, statusMFR,
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000369 statusTemperature)
370 .c_str());
371 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000372 tempFault++;
373 }
374 }
375 else
376 {
377 tempFault = 0;
Brandon Wyman52cb3f22021-12-21 23:02:47 +0000378 }
379}
380
Brandon Wyman993b5542021-12-21 22:55:16 +0000381void PowerSupply::analyzePgoodFault()
382{
383 if ((statusWord & phosphor::pmbus::status_word::POWER_GOOD_NEGATED) ||
384 (statusWord & phosphor::pmbus::status_word::UNIT_IS_OFF))
385 {
386 if (pgoodFault < DEGLITCH_LIMIT)
387 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000388 if (statusWord != statusWordOld)
389 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000390 log<level::ERR>(fmt::format("{} PGOOD fault: "
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000391 "STATUS_WORD = {:#06x}, "
392 "STATUS_MFR_SPECIFIC = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000393 shortName, statusWord, statusMFR)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000394 .c_str());
395 }
Brandon Wyman993b5542021-12-21 22:55:16 +0000396 pgoodFault++;
397 }
398 }
399 else
400 {
401 pgoodFault = 0;
402 }
403}
404
Brandon Wyman39ea02b2021-11-23 23:22:23 +0000405void PowerSupply::determineMFRFault()
406{
407 if (bindPath.string().find("ibm-cffps") != std::string::npos)
408 {
409 // IBM MFR_SPECIFIC[4] is PS_Kill fault
410 if (statusMFR & 0x10)
411 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000412 if (psKillFault < DEGLITCH_LIMIT)
413 {
414 psKillFault++;
415 }
416 }
417 else
418 {
419 psKillFault = 0;
Brandon Wyman39ea02b2021-11-23 23:22:23 +0000420 }
421 // IBM MFR_SPECIFIC[6] is 12Vcs fault.
422 if (statusMFR & 0x40)
423 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000424 if (ps12VcsFault < DEGLITCH_LIMIT)
425 {
426 ps12VcsFault++;
427 }
428 }
429 else
430 {
431 ps12VcsFault = 0;
Brandon Wyman39ea02b2021-11-23 23:22:23 +0000432 }
433 // IBM MFR_SPECIFIC[7] is 12V Current-Share fault.
434 if (statusMFR & 0x80)
435 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000436 if (psCS12VFault < DEGLITCH_LIMIT)
437 {
438 psCS12VFault++;
439 }
440 }
441 else
442 {
443 psCS12VFault = 0;
Brandon Wyman39ea02b2021-11-23 23:22:23 +0000444 }
445 }
446}
447
Brandon Wyman6c2ac392021-12-21 22:23:06 +0000448void PowerSupply::analyzeMFRFault()
449{
450 if (statusWord & phosphor::pmbus::status_word::MFR_SPECIFIC_FAULT)
451 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000452 if (mfrFault < DEGLITCH_LIMIT)
Brandon Wyman6c2ac392021-12-21 22:23:06 +0000453 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000454 if (statusWord != statusWordOld)
455 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000456 log<level::ERR>(fmt::format("{} MFR fault: "
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000457 "STATUS_WORD = {:#06x} "
458 "STATUS_MFR_SPECIFIC = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000459 shortName, statusWord, statusMFR)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000460 .c_str());
461 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000462 mfrFault++;
Brandon Wyman6c2ac392021-12-21 22:23:06 +0000463 }
464
Brandon Wyman6c2ac392021-12-21 22:23:06 +0000465 determineMFRFault();
466 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000467 else
468 {
469 mfrFault = 0;
470 }
Brandon Wyman6c2ac392021-12-21 22:23:06 +0000471}
472
Brandon Wymanf087f472021-12-22 00:04:27 +0000473void PowerSupply::analyzeVinUVFault()
474{
475 if (statusWord & phosphor::pmbus::status_word::VIN_UV_FAULT)
476 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000477 if (vinUVFault < DEGLITCH_LIMIT)
Brandon Wymanf087f472021-12-22 00:04:27 +0000478 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000479 if (statusWord != statusWordOld)
480 {
481 log<level::ERR>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000482 fmt::format("{} VIN_UV fault: STATUS_WORD = {:#06x}, "
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000483 "STATUS_MFR_SPECIFIC = {:#04x}, "
484 "STATUS_INPUT = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000485 shortName, statusWord, statusMFR, statusInput)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000486 .c_str());
487 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000488 vinUVFault++;
Brandon Wymanf087f472021-12-22 00:04:27 +0000489 }
Brandon Wymanf087f472021-12-22 00:04:27 +0000490 }
Brandon Wyman82affd92021-11-24 19:12:49 +0000491
492 if (vinUVFault &&
493 !(statusWord & phosphor::pmbus::status_word::VIN_UV_FAULT))
494 {
495 log<level::INFO>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000496 fmt::format("{} VIN_UV fault cleared: STATUS_WORD = {:#06x}, "
Brandon Wyman6f939a32022-03-10 18:42:20 +0000497 "STATUS_MFR_SPECIFIC = {:#04x}, "
498 "STATUS_INPUT = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000499 shortName, statusWord, statusMFR, statusInput)
Brandon Wyman82affd92021-11-24 19:12:49 +0000500 .c_str());
Brandon Wymanc2906f42021-12-21 20:14:56 +0000501 vinUVFault = 0;
Brandon Wyman82affd92021-11-24 19:12:49 +0000502 }
Brandon Wymanf087f472021-12-22 00:04:27 +0000503}
504
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600505void PowerSupply::analyze()
506{
507 using namespace phosphor::pmbus;
508
B. J. Wyman681b2a32021-04-20 22:31:22 +0000509 if (presenceGPIO)
510 {
511 updatePresenceGPIO();
512 }
513
Brandon Wyman32453e92021-12-15 19:00:14 +0000514 if (present)
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600515 {
516 try
517 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000518 statusWordOld = statusWord;
Brandon Wyman32453e92021-12-15 19:00:14 +0000519 statusWord = pmbusIntf->read(STATUS_WORD, Type::Debug,
520 (readFail < LOG_LIMIT));
Brandon Wymanf65c4062020-08-19 13:15:53 -0500521 // Read worked, reset the fail count.
522 readFail = 0;
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600523
524 if (statusWord)
525 {
Brandon Wymanf07bc792021-10-12 19:00:35 +0000526 statusInput = pmbusIntf->read(STATUS_INPUT, Type::Debug);
Jay Meyer10d94052020-11-30 14:41:21 -0600527 statusMFR = pmbusIntf->read(STATUS_MFR, Type::Debug);
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000528 statusCML = pmbusIntf->read(STATUS_CML, Type::Debug);
Brandon Wyman6710ba22021-10-27 17:39:31 +0000529 auto status0Vout = pmbusIntf->insertPageNum(STATUS_VOUT, 0);
530 statusVout = pmbusIntf->read(status0Vout, Type::Debug);
Brandon Wymanb10b3be2021-11-09 22:12:15 +0000531 statusIout = pmbusIntf->read(STATUS_IOUT, Type::Debug);
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000532 statusFans12 = pmbusIntf->read(STATUS_FANS_1_2, Type::Debug);
Brandon Wyman96893a42021-11-05 19:56:57 +0000533 statusTemperature =
534 pmbusIntf->read(STATUS_TEMPERATURE, Type::Debug);
Brandon Wyman9ddc6222021-10-28 17:28:01 +0000535
Brandon Wymanc2203432021-12-21 23:09:48 +0000536 analyzeCMLFault();
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000537
Brandon Wymane3b0bb02021-12-21 23:16:48 +0000538 analyzeInputFault();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600539
Brandon Wymanc2c87132021-12-21 23:22:18 +0000540 analyzeVoutOVFault();
Brandon Wyman6710ba22021-10-27 17:39:31 +0000541
Brandon Wymana00e7302021-12-21 23:28:29 +0000542 analyzeIoutOCFault();
Brandon Wymanb10b3be2021-11-09 22:12:15 +0000543
Brandon Wyman08378782021-12-21 23:48:15 +0000544 analyzeVoutUVFault();
Brandon Wyman2cf46942021-10-28 19:09:16 +0000545
Brandon Wymand5d9a222021-12-21 23:59:05 +0000546 analyzeFanFault();
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000547
Brandon Wyman52cb3f22021-12-21 23:02:47 +0000548 analyzeTemperatureFault();
Brandon Wyman96893a42021-11-05 19:56:57 +0000549
Brandon Wyman993b5542021-12-21 22:55:16 +0000550 analyzePgoodFault();
Brandon Wyman2916ea52021-11-06 03:31:18 +0000551
Brandon Wyman6c2ac392021-12-21 22:23:06 +0000552 analyzeMFRFault();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600553
Brandon Wymanf087f472021-12-22 00:04:27 +0000554 analyzeVinUVFault();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600555 }
556 else
557 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000558 if (statusWord != statusWordOld)
559 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000560 log<level::INFO>(fmt::format("{} STATUS_WORD = {:#06x}",
561 shortName, statusWord)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000562 .c_str());
563 }
564
Brandon Wymane3f7ad22021-12-21 20:27:45 +0000565 // if INPUT/VIN_UV fault was on, it cleared, trace it.
566 if (inputFault)
567 {
568 log<level::INFO>(
569 fmt::format(
Brandon Wyman321a6152022-03-19 00:11:44 +0000570 "{} INPUT fault cleared: STATUS_WORD = {:#06x}",
571 shortName, statusWord)
Brandon Wymane3f7ad22021-12-21 20:27:45 +0000572 .c_str());
573 }
574
575 if (vinUVFault)
576 {
577 log<level::INFO>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000578 fmt::format("{} VIN_UV cleared: STATUS_WORD = {:#06x}",
579 shortName, statusWord)
Brandon Wymane3f7ad22021-12-21 20:27:45 +0000580 .c_str());
581 }
582
Brandon Wyman06ca4592021-12-06 22:52:23 +0000583 if (pgoodFault > 0)
Brandon Wyman4aecc292021-11-10 22:40:41 +0000584 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000585 log<level::INFO>(
586 fmt::format("{} pgoodFault cleared", shortName)
587 .c_str());
Brandon Wyman4aecc292021-11-10 22:40:41 +0000588 }
Brandon Wymane3f7ad22021-12-21 20:27:45 +0000589
590 clearFaultFlags();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600591 }
Brandon Wyman82affd92021-11-24 19:12:49 +0000592
593 // Save off old inputVoltage value.
594 // Get latest inputVoltage.
595 // If voltage went from below minimum, and now is not, clear faults.
596 // Note: getInputVoltage() has its own try/catch.
597 int inputVoltageOld = inputVoltage;
598 double actualInputVoltage;
599 getInputVoltage(actualInputVoltage, inputVoltage);
600 if ((inputVoltageOld == in_input::VIN_VOLTAGE_0) &&
601 (inputVoltage != in_input::VIN_VOLTAGE_0))
602 {
603 log<level::INFO>(
604 fmt::format(
Brandon Wyman321a6152022-03-19 00:11:44 +0000605 "{} READ_VIN back in range: inputVoltageOld = {} inputVoltage = {}",
606 shortName, inputVoltageOld, inputVoltage)
Brandon Wyman82affd92021-11-24 19:12:49 +0000607 .c_str());
608 clearFaults();
609 }
Matt Spinler0975eaf2022-02-14 15:38:30 -0600610
611 checkAvailability();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600612 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500613 catch (const ReadFailure& e)
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600614 {
Brandon Wyman32453e92021-12-15 19:00:14 +0000615 if (readFail < SIZE_MAX)
616 {
617 readFail++;
618 }
619 if (readFail == LOG_LIMIT)
620 {
621 phosphor::logging::commit<ReadFailure>();
622 }
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600623 }
624 }
625}
626
Brandon Wyman59a35792020-06-04 12:37:40 -0500627void PowerSupply::onOffConfig(uint8_t data)
628{
629 using namespace phosphor::pmbus;
630
631 if (present)
632 {
633 log<level::INFO>("ON_OFF_CONFIG write", entry("DATA=0x%02X", data));
634 try
635 {
636 std::vector<uint8_t> configData{data};
637 pmbusIntf->writeBinary(ON_OFF_CONFIG, configData,
638 Type::HwmonDeviceDebug);
639 }
640 catch (...)
641 {
642 // The underlying code in writeBinary will log a message to the
B. J. Wyman681b2a32021-04-20 22:31:22 +0000643 // journal if the write fails. If the ON_OFF_CONFIG is not setup
644 // as desired, later fault detection and analysis code should
645 // catch any of the fall out. We should not need to terminate
646 // the application if this write fails.
Brandon Wyman59a35792020-06-04 12:37:40 -0500647 }
648 }
649}
650
Brandon Wyman3c208462020-05-13 16:25:58 -0500651void PowerSupply::clearFaults()
652{
Brandon Wyman82affd92021-11-24 19:12:49 +0000653 log<level::DEBUG>(
654 fmt::format("clearFaults() inventoryPath: {}", inventoryPath).c_str());
Brandon Wyman5474c912021-02-23 14:39:43 -0600655 faultLogged = false;
Brandon Wyman3c208462020-05-13 16:25:58 -0500656 // The PMBus device driver does not allow for writing CLEAR_FAULTS
657 // directly. However, the pmbus hwmon device driver code will send a
658 // CLEAR_FAULTS after reading from any of the hwmon "files" in sysfs, so
659 // reading in1_input should result in clearing the fault bits in
660 // STATUS_BYTE/STATUS_WORD.
661 // I do not care what the return value is.
Brandon Wyman11151532020-11-10 13:45:57 -0600662 if (present)
Brandon Wyman3c208462020-05-13 16:25:58 -0500663 {
Brandon Wymane3f7ad22021-12-21 20:27:45 +0000664 clearFaultFlags();
Matt Spinler0975eaf2022-02-14 15:38:30 -0600665 checkAvailability();
Brandon Wyman9564e942020-11-10 14:01:42 -0600666 readFail = 0;
Brandon Wyman9564e942020-11-10 14:01:42 -0600667
Brandon Wyman11151532020-11-10 13:45:57 -0600668 try
669 {
670 static_cast<void>(
671 pmbusIntf->read("in1_input", phosphor::pmbus::Type::Hwmon));
672 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500673 catch (const ReadFailure& e)
Brandon Wyman11151532020-11-10 13:45:57 -0600674 {
675 // Since I do not care what the return value is, I really do not
B. J. Wyman681b2a32021-04-20 22:31:22 +0000676 // care much if it gets a ReadFailure either. However, this
677 // should not prevent the application from continuing to run, so
678 // catching the read failure.
Brandon Wyman11151532020-11-10 13:45:57 -0600679 }
Brandon Wyman3c208462020-05-13 16:25:58 -0500680 }
681}
682
Brandon Wymanaed1f752019-11-25 18:10:52 -0600683void PowerSupply::inventoryChanged(sdbusplus::message::message& msg)
684{
685 std::string msgSensor;
Patrick Williamsabe49412020-05-13 17:59:47 -0500686 std::map<std::string, std::variant<uint32_t, bool>> msgData;
Brandon Wymanaed1f752019-11-25 18:10:52 -0600687 msg.read(msgSensor, msgData);
688
689 // Check if it was the Present property that changed.
690 auto valPropMap = msgData.find(PRESENT_PROP);
691 if (valPropMap != msgData.end())
692 {
693 if (std::get<bool>(valPropMap->second))
694 {
695 present = true;
B. J. Wyman681b2a32021-04-20 22:31:22 +0000696 // TODO: Immediately trying to read or write the "files" causes
697 // read or write failures.
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500698 using namespace std::chrono_literals;
699 std::this_thread::sleep_for(20ms);
Brandon Wyman9564e942020-11-10 14:01:42 -0600700 pmbusIntf->findHwmonDir();
Brandon Wyman59a35792020-06-04 12:37:40 -0500701 onOffConfig(phosphor::pmbus::ON_OFF_CONFIG_CONTROL_PIN_ONLY);
Brandon Wymanaed1f752019-11-25 18:10:52 -0600702 clearFaults();
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500703 updateInventory();
Brandon Wymanaed1f752019-11-25 18:10:52 -0600704 }
705 else
706 {
707 present = false;
708
709 // Clear out the now outdated inventory properties
710 updateInventory();
711 }
Matt Spinler0975eaf2022-02-14 15:38:30 -0600712 checkAvailability();
Brandon Wymanaed1f752019-11-25 18:10:52 -0600713 }
714}
715
Brandon Wyman9a507db2021-02-25 16:15:22 -0600716void PowerSupply::inventoryAdded(sdbusplus::message::message& msg)
717{
718 sdbusplus::message::object_path path;
719 msg.read(path);
720 // Make sure the signal is for the PSU inventory path
721 if (path == inventoryPath)
722 {
723 std::map<std::string, std::map<std::string, std::variant<bool>>>
724 interfaces;
725 // Get map of interfaces and their properties
726 msg.read(interfaces);
727
728 auto properties = interfaces.find(INVENTORY_IFACE);
729 if (properties != interfaces.end())
730 {
731 auto property = properties->second.find(PRESENT_PROP);
732 if (property != properties->second.end())
733 {
734 present = std::get<bool>(property->second);
735
736 log<level::INFO>(fmt::format("Power Supply {} Present {}",
737 inventoryPath, present)
738 .c_str());
739
740 updateInventory();
Matt Spinler0975eaf2022-02-14 15:38:30 -0600741 checkAvailability();
Brandon Wyman9a507db2021-02-25 16:15:22 -0600742 }
743 }
744 }
745}
746
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500747void PowerSupply::updateInventory()
748{
749 using namespace phosphor::pmbus;
750
Chanh Nguyenc12c53b2021-04-06 17:24:47 +0700751#if IBM_VPD
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500752 std::string ccin;
753 std::string pn;
754 std::string fn;
755 std::string header;
756 std::string sn;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500757 using PropertyMap =
George Liu070c1bc2020-10-12 11:28:01 +0800758 std::map<std::string,
759 std::variant<std::string, std::vector<uint8_t>, bool>>;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500760 PropertyMap assetProps;
George Liu070c1bc2020-10-12 11:28:01 +0800761 PropertyMap operProps;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500762 PropertyMap versionProps;
763 PropertyMap ipzvpdDINFProps;
764 PropertyMap ipzvpdVINIProps;
765 using InterfaceMap = std::map<std::string, PropertyMap>;
766 InterfaceMap interfaces;
767 using ObjectMap = std::map<sdbusplus::message::object_path, InterfaceMap>;
768 ObjectMap object;
769#endif
B. J. Wyman681b2a32021-04-20 22:31:22 +0000770 log<level::DEBUG>(
771 fmt::format("updateInventory() inventoryPath: {}", inventoryPath)
772 .c_str());
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500773
774 if (present)
775 {
776 // TODO: non-IBM inventory updates?
777
Chanh Nguyenc12c53b2021-04-06 17:24:47 +0700778#if IBM_VPD
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500779 try
780 {
781 ccin = pmbusIntf->readString(CCIN, Type::HwmonDeviceDebug);
782 assetProps.emplace(MODEL_PROP, ccin);
Adriana Kobylak572a9052021-03-30 15:58:07 +0000783 modelName = ccin;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500784 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500785 catch (const ReadFailure& e)
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500786 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000787 // Ignore the read failure, let pmbus code indicate failure,
788 // path...
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500789 // TODO - ibm918
790 // https://github.com/openbmc/docs/blob/master/designs/vpd-collection.md
791 // The BMC must log errors if any of the VPD cannot be properly
792 // parsed or fails ECC checks.
793 }
794
795 try
796 {
797 pn = pmbusIntf->readString(PART_NUMBER, Type::HwmonDeviceDebug);
798 assetProps.emplace(PN_PROP, pn);
799 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500800 catch (const ReadFailure& e)
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500801 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000802 // Ignore the read failure, let pmbus code indicate failure,
803 // path...
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500804 }
805
806 try
807 {
808 fn = pmbusIntf->readString(FRU_NUMBER, Type::HwmonDeviceDebug);
Brandon Wymana169b0f2021-12-07 20:18:06 +0000809 assetProps.emplace(SPARE_PN_PROP, fn);
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500810 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500811 catch (const ReadFailure& e)
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500812 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000813 // Ignore the read failure, let pmbus code indicate failure,
814 // path...
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500815 }
816
817 try
818 {
819 header =
820 pmbusIntf->readString(SERIAL_HEADER, Type::HwmonDeviceDebug);
821 sn = pmbusIntf->readString(SERIAL_NUMBER, Type::HwmonDeviceDebug);
Mike Capps1cb0f132022-03-14 11:40:30 -0400822 assetProps.emplace(SN_PROP, header + sn);
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500823 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500824 catch (const ReadFailure& e)
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500825 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000826 // Ignore the read failure, let pmbus code indicate failure,
827 // path...
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500828 }
829
830 try
831 {
Brandon Wymanc9efe412020-10-09 15:42:50 -0500832 fwVersion =
833 pmbusIntf->readString(FW_VERSION, Type::HwmonDeviceDebug);
834 versionProps.emplace(VERSION_PROP, fwVersion);
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500835 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500836 catch (const ReadFailure& e)
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500837 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000838 // Ignore the read failure, let pmbus code indicate failure,
839 // path...
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500840 }
841
842 ipzvpdVINIProps.emplace("CC",
843 std::vector<uint8_t>(ccin.begin(), ccin.end()));
844 ipzvpdVINIProps.emplace("PN",
845 std::vector<uint8_t>(pn.begin(), pn.end()));
846 ipzvpdVINIProps.emplace("FN",
847 std::vector<uint8_t>(fn.begin(), fn.end()));
848 std::string header_sn = header + sn + '\0';
849 ipzvpdVINIProps.emplace(
850 "SN", std::vector<uint8_t>(header_sn.begin(), header_sn.end()));
851 std::string description = "IBM PS";
852 ipzvpdVINIProps.emplace(
853 "DR", std::vector<uint8_t>(description.begin(), description.end()));
854
Ben Tynerf8d8c462022-01-27 16:09:45 -0600855 // Populate the VINI Resource Type (RT) keyword
856 ipzvpdVINIProps.emplace("RT", std::vector<uint8_t>{'V', 'I', 'N', 'I'});
857
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500858 // Update the Resource Identifier (RI) keyword
859 // 2 byte FRC: 0x0003
860 // 2 byte RID: 0x1000, 0x1001...
861 std::uint8_t num = std::stoul(
862 inventoryPath.substr(inventoryPath.size() - 1, 1), nullptr, 0);
863 std::vector<uint8_t> ri{0x00, 0x03, 0x10, num};
864 ipzvpdDINFProps.emplace("RI", ri);
865
866 // Fill in the FRU Label (FL) keyword.
867 std::string fl = "E";
868 fl.push_back(inventoryPath.back());
869 fl.resize(FL_KW_SIZE, ' ');
870 ipzvpdDINFProps.emplace("FL",
871 std::vector<uint8_t>(fl.begin(), fl.end()));
872
Ben Tynerf8d8c462022-01-27 16:09:45 -0600873 // Populate the DINF Resource Type (RT) keyword
874 ipzvpdDINFProps.emplace("RT", std::vector<uint8_t>{'D', 'I', 'N', 'F'});
875
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500876 interfaces.emplace(ASSET_IFACE, std::move(assetProps));
877 interfaces.emplace(VERSION_IFACE, std::move(versionProps));
878 interfaces.emplace(DINF_IFACE, std::move(ipzvpdDINFProps));
879 interfaces.emplace(VINI_IFACE, std::move(ipzvpdVINIProps));
880
George Liu070c1bc2020-10-12 11:28:01 +0800881 // Update the Functional
882 operProps.emplace(FUNCTIONAL_PROP, present);
883 interfaces.emplace(OPERATIONAL_STATE_IFACE, std::move(operProps));
884
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500885 auto path = inventoryPath.substr(strlen(INVENTORY_OBJ_PATH));
886 object.emplace(path, std::move(interfaces));
887
888 try
889 {
890 auto service =
891 util::getService(INVENTORY_OBJ_PATH, INVENTORY_MGR_IFACE, bus);
892
893 if (service.empty())
894 {
895 log<level::ERR>("Unable to get inventory manager service");
896 return;
897 }
898
899 auto method =
900 bus.new_method_call(service.c_str(), INVENTORY_OBJ_PATH,
901 INVENTORY_MGR_IFACE, "Notify");
902
903 method.append(std::move(object));
904
905 auto reply = bus.call(method);
906 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500907 catch (const std::exception& e)
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500908 {
Jay Meyer6a3fd2c2020-08-25 16:37:16 -0500909 log<level::ERR>(
910 std::string(e.what() + std::string(" PATH=") + inventoryPath)
911 .c_str());
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500912 }
913#endif
914 }
915}
916
Adriana Kobylak4175ffb2021-08-02 14:51:05 +0000917void PowerSupply::getInputVoltage(double& actualInputVoltage,
918 int& inputVoltage) const
919{
920 using namespace phosphor::pmbus;
921
922 actualInputVoltage = in_input::VIN_VOLTAGE_0;
923 inputVoltage = in_input::VIN_VOLTAGE_0;
924
925 if (present)
926 {
927 try
928 {
929 // Read input voltage in millivolts
930 auto inputVoltageStr = pmbusIntf->readString(READ_VIN, Type::Hwmon);
931
932 // Convert to volts
933 actualInputVoltage = std::stod(inputVoltageStr) / 1000;
934
935 // Calculate the voltage based on voltage thresholds
936 if (actualInputVoltage < in_input::VIN_VOLTAGE_MIN)
937 {
938 inputVoltage = in_input::VIN_VOLTAGE_0;
939 }
940 else if (actualInputVoltage < in_input::VIN_VOLTAGE_110_THRESHOLD)
941 {
942 inputVoltage = in_input::VIN_VOLTAGE_110;
943 }
944 else
945 {
946 inputVoltage = in_input::VIN_VOLTAGE_220;
947 }
948 }
949 catch (const std::exception& e)
950 {
951 log<level::ERR>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000952 fmt::format("{} READ_VIN read error: {}", shortName, e.what())
953 .c_str());
Adriana Kobylak4175ffb2021-08-02 14:51:05 +0000954 }
955 }
956}
957
Matt Spinler0975eaf2022-02-14 15:38:30 -0600958void PowerSupply::checkAvailability()
959{
960 bool origAvailability = available;
961 available = present && !hasInputFault() && !hasVINUVFault() &&
962 !hasPSKillFault() && !hasIoutOCFault();
963
964 if (origAvailability != available)
965 {
966 auto invpath = inventoryPath.substr(strlen(INVENTORY_OBJ_PATH));
967 phosphor::power::psu::setAvailable(bus, invpath, available);
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600968
969 // Check if the health rollup needs to change based on the
970 // new availability value.
971 phosphor::power::psu::handleChassisHealthRollup(bus, inventoryPath,
972 !available);
Matt Spinler0975eaf2022-02-14 15:38:30 -0600973 }
974}
975
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600976} // namespace phosphor::power::psu