blob: af0af69dad4815265ea9915bbd7860c70a1ec189 [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 {
Brandon Wymanb1ee60f2022-03-22 22:37:12 +000097 std::this_thread::sleep_for(std::chrono::milliseconds(bindDelay));
B. J. Wyman681b2a32021-04-20 22:31:22 +000098 log<level::INFO>(
99 fmt::format("Binding device driver. path: {} device: {}",
100 path.string(), bindDevice)
101 .c_str());
102 }
103 else
104 {
105 log<level::INFO>(
106 fmt::format("Unbinding device driver. path: {} device: {}",
107 path.string(), bindDevice)
108 .c_str());
109 }
110
111 std::ofstream file;
112
113 file.exceptions(std::ofstream::failbit | std::ofstream::badbit |
114 std::ofstream::eofbit);
115
116 try
117 {
118 file.open(path);
119 file << bindDevice;
120 file.close();
121 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500122 catch (const std::exception& e)
B. J. Wyman681b2a32021-04-20 22:31:22 +0000123 {
124 auto err = errno;
125
126 log<level::ERR>(
127 fmt::format("Failed binding or unbinding device. errno={}", err)
128 .c_str());
129 }
Brandon Wyman510acaa2020-11-05 18:32:04 -0600130}
131
Brandon Wymanaed1f752019-11-25 18:10:52 -0600132void PowerSupply::updatePresence()
133{
134 try
135 {
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600136 present = getPresence(bus, inventoryPath);
Brandon Wymanaed1f752019-11-25 18:10:52 -0600137 }
Patrick Williams69f10ad2021-09-02 09:46:49 -0500138 catch (const sdbusplus::exception::exception& e)
Brandon Wymanaed1f752019-11-25 18:10:52 -0600139 {
140 // Relying on property change or interface added to retry.
141 // Log an informational trace to the journal.
Brandon Wymandf13c3a2020-12-15 14:25:22 -0600142 log<level::INFO>(
143 fmt::format("D-Bus property {} access failure exception",
144 inventoryPath)
145 .c_str());
Brandon Wymanaed1f752019-11-25 18:10:52 -0600146 }
147}
148
B. J. Wyman681b2a32021-04-20 22:31:22 +0000149void PowerSupply::updatePresenceGPIO()
150{
151 bool presentOld = present;
152
153 try
154 {
155 if (presenceGPIO->read() > 0)
156 {
157 present = true;
158 }
159 else
160 {
161 present = false;
162 }
163 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500164 catch (const std::exception& e)
B. J. Wyman681b2a32021-04-20 22:31:22 +0000165 {
166 log<level::ERR>(
167 fmt::format("presenceGPIO read fail: {}", e.what()).c_str());
168 throw;
169 }
170
171 if (presentOld != present)
172 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000173 log<level::DEBUG>(fmt::format("{} presentOld: {} present: {}",
174 shortName, presentOld, present)
175 .c_str());
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600176
177 auto invpath = inventoryPath.substr(strlen(INVENTORY_OBJ_PATH));
Brandon Wyman321a6152022-03-19 00:11:44 +0000178 setPresence(bus, invpath, present, shortName);
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600179 updateInventory();
180
181 // Need Functional to already be correct before calling this
182 checkAvailability();
183
B. J. Wyman681b2a32021-04-20 22:31:22 +0000184 if (present)
185 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000186 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());
Brandon Wyman3225a452022-03-18 18:51:49 +0000610 clearVinUVFault();
Brandon Wyman82affd92021-11-24 19:12:49 +0000611 }
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
Brandon Wyman3225a452022-03-18 18:51:49 +0000620 // due to voltage back in range? Attempt to clear the fault(s),
621 // re-check faults on next call.
622 clearVinUVFault();
Brandon Wyman4fc191f2022-03-10 23:07:13 +0000623 }
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 Wyman3225a452022-03-18 18:51:49 +0000673void PowerSupply::clearVinUVFault()
674{
675 // Read in1_lcrit_alarm to clear bits 3 and 4 of STATUS_INPUT.
676 // The fault bits in STAUTS_INPUT roll-up to STATUS_WORD. Clearing those
677 // bits in STATUS_INPUT should result in the corresponding STATUS_WORD bits
678 // also clearing.
679 //
680 // Do not care about return value. Should be 1 if active, 0 if not.
681 static_cast<void>(
682 pmbusIntf->read("in1_lcrit_alarm", phosphor::pmbus::Type::Hwmon));
683 vinUVFault = 0;
684}
685
Brandon Wyman3c208462020-05-13 16:25:58 -0500686void PowerSupply::clearFaults()
687{
Brandon Wyman82affd92021-11-24 19:12:49 +0000688 log<level::DEBUG>(
689 fmt::format("clearFaults() inventoryPath: {}", inventoryPath).c_str());
Brandon Wyman5474c912021-02-23 14:39:43 -0600690 faultLogged = false;
Brandon Wyman3c208462020-05-13 16:25:58 -0500691 // The PMBus device driver does not allow for writing CLEAR_FAULTS
692 // directly. However, the pmbus hwmon device driver code will send a
693 // CLEAR_FAULTS after reading from any of the hwmon "files" in sysfs, so
694 // reading in1_input should result in clearing the fault bits in
695 // STATUS_BYTE/STATUS_WORD.
696 // I do not care what the return value is.
Brandon Wyman11151532020-11-10 13:45:57 -0600697 if (present)
Brandon Wyman3c208462020-05-13 16:25:58 -0500698 {
Brandon Wymane3f7ad22021-12-21 20:27:45 +0000699 clearFaultFlags();
Matt Spinler0975eaf2022-02-14 15:38:30 -0600700 checkAvailability();
Brandon Wyman9564e942020-11-10 14:01:42 -0600701 readFail = 0;
Brandon Wyman9564e942020-11-10 14:01:42 -0600702
Brandon Wyman11151532020-11-10 13:45:57 -0600703 try
704 {
Brandon Wyman3225a452022-03-18 18:51:49 +0000705 clearVinUVFault();
Brandon Wyman11151532020-11-10 13:45:57 -0600706 static_cast<void>(
707 pmbusIntf->read("in1_input", phosphor::pmbus::Type::Hwmon));
708 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500709 catch (const ReadFailure& e)
Brandon Wyman11151532020-11-10 13:45:57 -0600710 {
711 // Since I do not care what the return value is, I really do not
B. J. Wyman681b2a32021-04-20 22:31:22 +0000712 // care much if it gets a ReadFailure either. However, this
713 // should not prevent the application from continuing to run, so
714 // catching the read failure.
Brandon Wyman11151532020-11-10 13:45:57 -0600715 }
Brandon Wyman3c208462020-05-13 16:25:58 -0500716 }
717}
718
Brandon Wymanaed1f752019-11-25 18:10:52 -0600719void PowerSupply::inventoryChanged(sdbusplus::message::message& msg)
720{
721 std::string msgSensor;
Patrick Williamsabe49412020-05-13 17:59:47 -0500722 std::map<std::string, std::variant<uint32_t, bool>> msgData;
Brandon Wymanaed1f752019-11-25 18:10:52 -0600723 msg.read(msgSensor, msgData);
724
725 // Check if it was the Present property that changed.
726 auto valPropMap = msgData.find(PRESENT_PROP);
727 if (valPropMap != msgData.end())
728 {
729 if (std::get<bool>(valPropMap->second))
730 {
731 present = true;
B. J. Wyman681b2a32021-04-20 22:31:22 +0000732 // TODO: Immediately trying to read or write the "files" causes
733 // read or write failures.
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500734 using namespace std::chrono_literals;
735 std::this_thread::sleep_for(20ms);
Brandon Wyman9564e942020-11-10 14:01:42 -0600736 pmbusIntf->findHwmonDir();
Brandon Wyman59a35792020-06-04 12:37:40 -0500737 onOffConfig(phosphor::pmbus::ON_OFF_CONFIG_CONTROL_PIN_ONLY);
Brandon Wymanaed1f752019-11-25 18:10:52 -0600738 clearFaults();
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500739 updateInventory();
Brandon Wymanaed1f752019-11-25 18:10:52 -0600740 }
741 else
742 {
743 present = false;
744
745 // Clear out the now outdated inventory properties
746 updateInventory();
747 }
Matt Spinler0975eaf2022-02-14 15:38:30 -0600748 checkAvailability();
Brandon Wymanaed1f752019-11-25 18:10:52 -0600749 }
750}
751
Brandon Wyman9a507db2021-02-25 16:15:22 -0600752void PowerSupply::inventoryAdded(sdbusplus::message::message& msg)
753{
754 sdbusplus::message::object_path path;
755 msg.read(path);
756 // Make sure the signal is for the PSU inventory path
757 if (path == inventoryPath)
758 {
759 std::map<std::string, std::map<std::string, std::variant<bool>>>
760 interfaces;
761 // Get map of interfaces and their properties
762 msg.read(interfaces);
763
764 auto properties = interfaces.find(INVENTORY_IFACE);
765 if (properties != interfaces.end())
766 {
767 auto property = properties->second.find(PRESENT_PROP);
768 if (property != properties->second.end())
769 {
770 present = std::get<bool>(property->second);
771
772 log<level::INFO>(fmt::format("Power Supply {} Present {}",
773 inventoryPath, present)
774 .c_str());
775
776 updateInventory();
Matt Spinler0975eaf2022-02-14 15:38:30 -0600777 checkAvailability();
Brandon Wyman9a507db2021-02-25 16:15:22 -0600778 }
779 }
780 }
781}
782
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500783void PowerSupply::updateInventory()
784{
785 using namespace phosphor::pmbus;
786
Chanh Nguyenc12c53b2021-04-06 17:24:47 +0700787#if IBM_VPD
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500788 std::string ccin;
789 std::string pn;
790 std::string fn;
791 std::string header;
792 std::string sn;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500793 using PropertyMap =
George Liu070c1bc2020-10-12 11:28:01 +0800794 std::map<std::string,
795 std::variant<std::string, std::vector<uint8_t>, bool>>;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500796 PropertyMap assetProps;
George Liu070c1bc2020-10-12 11:28:01 +0800797 PropertyMap operProps;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500798 PropertyMap versionProps;
799 PropertyMap ipzvpdDINFProps;
800 PropertyMap ipzvpdVINIProps;
801 using InterfaceMap = std::map<std::string, PropertyMap>;
802 InterfaceMap interfaces;
803 using ObjectMap = std::map<sdbusplus::message::object_path, InterfaceMap>;
804 ObjectMap object;
805#endif
B. J. Wyman681b2a32021-04-20 22:31:22 +0000806 log<level::DEBUG>(
807 fmt::format("updateInventory() inventoryPath: {}", inventoryPath)
808 .c_str());
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500809
810 if (present)
811 {
812 // TODO: non-IBM inventory updates?
813
Chanh Nguyenc12c53b2021-04-06 17:24:47 +0700814#if IBM_VPD
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500815 try
816 {
817 ccin = pmbusIntf->readString(CCIN, Type::HwmonDeviceDebug);
818 assetProps.emplace(MODEL_PROP, ccin);
Adriana Kobylak572a9052021-03-30 15:58:07 +0000819 modelName = ccin;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500820 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500821 catch (const ReadFailure& e)
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500822 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000823 // Ignore the read failure, let pmbus code indicate failure,
824 // path...
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500825 // TODO - ibm918
826 // https://github.com/openbmc/docs/blob/master/designs/vpd-collection.md
827 // The BMC must log errors if any of the VPD cannot be properly
828 // parsed or fails ECC checks.
829 }
830
831 try
832 {
833 pn = pmbusIntf->readString(PART_NUMBER, Type::HwmonDeviceDebug);
834 assetProps.emplace(PN_PROP, pn);
835 }
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 try
843 {
844 fn = pmbusIntf->readString(FRU_NUMBER, Type::HwmonDeviceDebug);
Brandon Wymana169b0f2021-12-07 20:18:06 +0000845 assetProps.emplace(SPARE_PN_PROP, fn);
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500846 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500847 catch (const ReadFailure& e)
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500848 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000849 // Ignore the read failure, let pmbus code indicate failure,
850 // path...
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500851 }
852
853 try
854 {
855 header =
856 pmbusIntf->readString(SERIAL_HEADER, Type::HwmonDeviceDebug);
857 sn = pmbusIntf->readString(SERIAL_NUMBER, Type::HwmonDeviceDebug);
Mike Capps1cb0f132022-03-14 11:40:30 -0400858 assetProps.emplace(SN_PROP, header + sn);
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500859 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500860 catch (const ReadFailure& e)
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500861 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000862 // Ignore the read failure, let pmbus code indicate failure,
863 // path...
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500864 }
865
866 try
867 {
Brandon Wymanc9efe412020-10-09 15:42:50 -0500868 fwVersion =
869 pmbusIntf->readString(FW_VERSION, Type::HwmonDeviceDebug);
870 versionProps.emplace(VERSION_PROP, fwVersion);
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500871 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500872 catch (const ReadFailure& e)
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500873 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000874 // Ignore the read failure, let pmbus code indicate failure,
875 // path...
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500876 }
877
878 ipzvpdVINIProps.emplace("CC",
879 std::vector<uint8_t>(ccin.begin(), ccin.end()));
880 ipzvpdVINIProps.emplace("PN",
881 std::vector<uint8_t>(pn.begin(), pn.end()));
882 ipzvpdVINIProps.emplace("FN",
883 std::vector<uint8_t>(fn.begin(), fn.end()));
884 std::string header_sn = header + sn + '\0';
885 ipzvpdVINIProps.emplace(
886 "SN", std::vector<uint8_t>(header_sn.begin(), header_sn.end()));
887 std::string description = "IBM PS";
888 ipzvpdVINIProps.emplace(
889 "DR", std::vector<uint8_t>(description.begin(), description.end()));
890
Ben Tynerf8d8c462022-01-27 16:09:45 -0600891 // Populate the VINI Resource Type (RT) keyword
892 ipzvpdVINIProps.emplace("RT", std::vector<uint8_t>{'V', 'I', 'N', 'I'});
893
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500894 // Update the Resource Identifier (RI) keyword
895 // 2 byte FRC: 0x0003
896 // 2 byte RID: 0x1000, 0x1001...
897 std::uint8_t num = std::stoul(
898 inventoryPath.substr(inventoryPath.size() - 1, 1), nullptr, 0);
899 std::vector<uint8_t> ri{0x00, 0x03, 0x10, num};
900 ipzvpdDINFProps.emplace("RI", ri);
901
902 // Fill in the FRU Label (FL) keyword.
903 std::string fl = "E";
904 fl.push_back(inventoryPath.back());
905 fl.resize(FL_KW_SIZE, ' ');
906 ipzvpdDINFProps.emplace("FL",
907 std::vector<uint8_t>(fl.begin(), fl.end()));
908
Ben Tynerf8d8c462022-01-27 16:09:45 -0600909 // Populate the DINF Resource Type (RT) keyword
910 ipzvpdDINFProps.emplace("RT", std::vector<uint8_t>{'D', 'I', 'N', 'F'});
911
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500912 interfaces.emplace(ASSET_IFACE, std::move(assetProps));
913 interfaces.emplace(VERSION_IFACE, std::move(versionProps));
914 interfaces.emplace(DINF_IFACE, std::move(ipzvpdDINFProps));
915 interfaces.emplace(VINI_IFACE, std::move(ipzvpdVINIProps));
916
George Liu070c1bc2020-10-12 11:28:01 +0800917 // Update the Functional
918 operProps.emplace(FUNCTIONAL_PROP, present);
919 interfaces.emplace(OPERATIONAL_STATE_IFACE, std::move(operProps));
920
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500921 auto path = inventoryPath.substr(strlen(INVENTORY_OBJ_PATH));
922 object.emplace(path, std::move(interfaces));
923
924 try
925 {
926 auto service =
927 util::getService(INVENTORY_OBJ_PATH, INVENTORY_MGR_IFACE, bus);
928
929 if (service.empty())
930 {
931 log<level::ERR>("Unable to get inventory manager service");
932 return;
933 }
934
935 auto method =
936 bus.new_method_call(service.c_str(), INVENTORY_OBJ_PATH,
937 INVENTORY_MGR_IFACE, "Notify");
938
939 method.append(std::move(object));
940
941 auto reply = bus.call(method);
942 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500943 catch (const std::exception& e)
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500944 {
Jay Meyer6a3fd2c2020-08-25 16:37:16 -0500945 log<level::ERR>(
946 std::string(e.what() + std::string(" PATH=") + inventoryPath)
947 .c_str());
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500948 }
949#endif
950 }
951}
952
Adriana Kobylak4175ffb2021-08-02 14:51:05 +0000953void PowerSupply::getInputVoltage(double& actualInputVoltage,
954 int& inputVoltage) const
955{
956 using namespace phosphor::pmbus;
957
958 actualInputVoltage = in_input::VIN_VOLTAGE_0;
959 inputVoltage = in_input::VIN_VOLTAGE_0;
960
961 if (present)
962 {
963 try
964 {
965 // Read input voltage in millivolts
966 auto inputVoltageStr = pmbusIntf->readString(READ_VIN, Type::Hwmon);
967
968 // Convert to volts
969 actualInputVoltage = std::stod(inputVoltageStr) / 1000;
970
971 // Calculate the voltage based on voltage thresholds
972 if (actualInputVoltage < in_input::VIN_VOLTAGE_MIN)
973 {
974 inputVoltage = in_input::VIN_VOLTAGE_0;
975 }
976 else if (actualInputVoltage < in_input::VIN_VOLTAGE_110_THRESHOLD)
977 {
978 inputVoltage = in_input::VIN_VOLTAGE_110;
979 }
980 else
981 {
982 inputVoltage = in_input::VIN_VOLTAGE_220;
983 }
984 }
985 catch (const std::exception& e)
986 {
987 log<level::ERR>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000988 fmt::format("{} READ_VIN read error: {}", shortName, e.what())
989 .c_str());
Adriana Kobylak4175ffb2021-08-02 14:51:05 +0000990 }
991 }
992}
993
Matt Spinler0975eaf2022-02-14 15:38:30 -0600994void PowerSupply::checkAvailability()
995{
996 bool origAvailability = available;
997 available = present && !hasInputFault() && !hasVINUVFault() &&
998 !hasPSKillFault() && !hasIoutOCFault();
999
1000 if (origAvailability != available)
1001 {
1002 auto invpath = inventoryPath.substr(strlen(INVENTORY_OBJ_PATH));
1003 phosphor::power::psu::setAvailable(bus, invpath, available);
Matt Spinlerca1e9ea2022-02-18 14:03:08 -06001004
1005 // Check if the health rollup needs to change based on the
1006 // new availability value.
1007 phosphor::power::psu::handleChassisHealthRollup(bus, inventoryPath,
1008 !available);
Matt Spinler0975eaf2022-02-14 15:38:30 -06001009 }
1010}
1011
Brandon Wyman3f1242f2020-01-28 13:11:25 -06001012} // namespace phosphor::power::psu