blob: a7e357923d2c468cbb3c47ab5a30cdb08b7b11c7 [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 Wyman90d529a2022-03-22 23:02:54 +0000178
179 bindOrUnbindDriver(present);
180 if (present)
181 {
182 // If the power supply was present, then missing, and present again,
183 // the hwmon path may have changed. We will need the correct/updated
184 // path before any reads or writes are attempted.
185 pmbusIntf->findHwmonDir();
186 }
187
Brandon Wyman321a6152022-03-19 00:11:44 +0000188 setPresence(bus, invpath, present, shortName);
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600189 updateInventory();
190
Brandon Wyman90d529a2022-03-22 23:02:54 +0000191 // Need Functional to already be correct before calling this.
Matt Spinlerca1e9ea2022-02-18 14:03:08 -0600192 checkAvailability();
193
B. J. Wyman681b2a32021-04-20 22:31:22 +0000194 if (present)
195 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000196 onOffConfig(phosphor::pmbus::ON_OFF_CONFIG_CONTROL_PIN_ONLY);
197 clearFaults();
198 }
B. J. Wyman681b2a32021-04-20 22:31:22 +0000199 }
200}
201
Brandon Wymanc2203432021-12-21 23:09:48 +0000202void PowerSupply::analyzeCMLFault()
203{
204 if (statusWord & phosphor::pmbus::status_word::CML_FAULT)
205 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000206 if (cmlFault < DEGLITCH_LIMIT)
Brandon Wymanc2203432021-12-21 23:09:48 +0000207 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000208 if (statusWord != statusWordOld)
209 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000210 log<level::ERR>(
211 fmt::format("{} CML fault: STATUS_WORD = {:#06x}, "
212 "STATUS_CML = {:#02x}",
213 shortName, statusWord, statusCML)
214 .c_str());
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000215 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000216 cmlFault++;
217 }
218 }
219 else
220 {
221 cmlFault = 0;
Brandon Wymanc2203432021-12-21 23:09:48 +0000222 }
223}
224
Brandon Wymane3b0bb02021-12-21 23:16:48 +0000225void PowerSupply::analyzeInputFault()
226{
227 if (statusWord & phosphor::pmbus::status_word::INPUT_FAULT_WARN)
228 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000229 if (inputFault < DEGLITCH_LIMIT)
Brandon Wymane3b0bb02021-12-21 23:16:48 +0000230 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000231 if (statusWord != statusWordOld)
232 {
233 log<level::ERR>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000234 fmt::format("{} INPUT fault: STATUS_WORD = {:#06x}, "
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000235 "STATUS_MFR_SPECIFIC = {:#04x}, "
236 "STATUS_INPUT = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000237 shortName, statusWord, statusMFR, statusInput)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000238 .c_str());
239 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000240 inputFault++;
241 }
Brandon Wymane3b0bb02021-12-21 23:16:48 +0000242 }
Brandon Wyman82affd92021-11-24 19:12:49 +0000243
244 // If had INPUT/VIN_UV fault, and now off.
245 // Trace that odd behavior.
246 if (inputFault &&
247 !(statusWord & phosphor::pmbus::status_word::INPUT_FAULT_WARN))
248 {
249 log<level::INFO>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000250 fmt::format("{} INPUT fault cleared: STATUS_WORD = {:#06x}, "
Brandon Wyman6f939a32022-03-10 18:42:20 +0000251 "STATUS_MFR_SPECIFIC = {:#04x}, "
252 "STATUS_INPUT = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000253 shortName, statusWord, statusMFR, statusInput)
Brandon Wyman82affd92021-11-24 19:12:49 +0000254 .c_str());
Brandon Wymanc2906f42021-12-21 20:14:56 +0000255 inputFault = 0;
Brandon Wyman82affd92021-11-24 19:12:49 +0000256 }
Brandon Wymane3b0bb02021-12-21 23:16:48 +0000257}
258
Brandon Wymanc2c87132021-12-21 23:22:18 +0000259void PowerSupply::analyzeVoutOVFault()
260{
261 if (statusWord & phosphor::pmbus::status_word::VOUT_OV_FAULT)
262 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000263 if (voutOVFault < DEGLITCH_LIMIT)
Brandon Wymanc2c87132021-12-21 23:22:18 +0000264 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000265 if (statusWord != statusWordOld)
266 {
267 log<level::ERR>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000268 fmt::format(
269 "{} VOUT_OV_FAULT fault: STATUS_WORD = {:#06x}, "
270 "STATUS_MFR_SPECIFIC = {:#04x}, "
271 "STATUS_VOUT = {:#02x}",
272 shortName, statusWord, statusMFR, statusVout)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000273 .c_str());
274 }
Brandon Wymanc2c87132021-12-21 23:22:18 +0000275
Brandon Wymanc2906f42021-12-21 20:14:56 +0000276 voutOVFault++;
277 }
278 }
279 else
280 {
281 voutOVFault = 0;
Brandon Wymanc2c87132021-12-21 23:22:18 +0000282 }
283}
284
Brandon Wymana00e7302021-12-21 23:28:29 +0000285void PowerSupply::analyzeIoutOCFault()
286{
287 if (statusWord & phosphor::pmbus::status_word::IOUT_OC_FAULT)
288 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000289 if (ioutOCFault < DEGLITCH_LIMIT)
Brandon Wymana00e7302021-12-21 23:28:29 +0000290 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000291 if (statusWord != statusWordOld)
292 {
293 log<level::ERR>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000294 fmt::format("{} IOUT fault: STATUS_WORD = {:#06x}, "
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000295 "STATUS_MFR_SPECIFIC = {:#04x}, "
296 "STATUS_IOUT = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000297 shortName, statusWord, statusMFR, statusIout)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000298 .c_str());
299 }
Brandon Wymana00e7302021-12-21 23:28:29 +0000300
Brandon Wymanc2906f42021-12-21 20:14:56 +0000301 ioutOCFault++;
302 }
303 }
304 else
305 {
306 ioutOCFault = 0;
Brandon Wymana00e7302021-12-21 23:28:29 +0000307 }
308}
309
Brandon Wyman08378782021-12-21 23:48:15 +0000310void PowerSupply::analyzeVoutUVFault()
311{
312 if ((statusWord & phosphor::pmbus::status_word::VOUT_FAULT) &&
313 !(statusWord & phosphor::pmbus::status_word::VOUT_OV_FAULT))
314 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000315 if (voutUVFault < DEGLITCH_LIMIT)
Brandon Wyman08378782021-12-21 23:48:15 +0000316 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000317 if (statusWord != statusWordOld)
318 {
319 log<level::ERR>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000320 fmt::format(
321 "{} VOUT_UV_FAULT fault: STATUS_WORD = {:#06x}, "
322 "STATUS_MFR_SPECIFIC = {:#04x}, "
323 "STATUS_VOUT = {:#04x}",
324 shortName, statusWord, statusMFR, statusVout)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000325 .c_str());
326 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000327 voutUVFault++;
328 }
329 }
330 else
331 {
332 voutUVFault = 0;
Brandon Wyman08378782021-12-21 23:48:15 +0000333 }
334}
335
Brandon Wymand5d9a222021-12-21 23:59:05 +0000336void PowerSupply::analyzeFanFault()
337{
338 if (statusWord & phosphor::pmbus::status_word::FAN_FAULT)
339 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000340 if (fanFault < DEGLITCH_LIMIT)
Brandon Wymand5d9a222021-12-21 23:59:05 +0000341 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000342 if (statusWord != statusWordOld)
343 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000344 log<level::ERR>(fmt::format("{} FANS fault/warning: "
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000345 "STATUS_WORD = {:#06x}, "
346 "STATUS_MFR_SPECIFIC = {:#04x}, "
347 "STATUS_FANS_1_2 = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000348 shortName, statusWord, statusMFR,
349 statusFans12)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000350 .c_str());
351 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000352 fanFault++;
353 }
354 }
355 else
356 {
357 fanFault = 0;
Brandon Wymand5d9a222021-12-21 23:59:05 +0000358 }
359}
360
Brandon Wyman52cb3f22021-12-21 23:02:47 +0000361void PowerSupply::analyzeTemperatureFault()
362{
363 if (statusWord & phosphor::pmbus::status_word::TEMPERATURE_FAULT_WARN)
364 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000365 if (tempFault < DEGLITCH_LIMIT)
Brandon Wyman52cb3f22021-12-21 23:02:47 +0000366 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000367 if (statusWord != statusWordOld)
368 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000369 log<level::ERR>(fmt::format("{} TEMPERATURE fault/warning: "
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000370 "STATUS_WORD = {:#06x}, "
371 "STATUS_MFR_SPECIFIC = {:#04x}, "
372 "STATUS_TEMPERATURE = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000373 shortName, statusWord, statusMFR,
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000374 statusTemperature)
375 .c_str());
376 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000377 tempFault++;
378 }
379 }
380 else
381 {
382 tempFault = 0;
Brandon Wyman52cb3f22021-12-21 23:02:47 +0000383 }
384}
385
Brandon Wyman993b5542021-12-21 22:55:16 +0000386void PowerSupply::analyzePgoodFault()
387{
388 if ((statusWord & phosphor::pmbus::status_word::POWER_GOOD_NEGATED) ||
389 (statusWord & phosphor::pmbus::status_word::UNIT_IS_OFF))
390 {
391 if (pgoodFault < DEGLITCH_LIMIT)
392 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000393 if (statusWord != statusWordOld)
394 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000395 log<level::ERR>(fmt::format("{} PGOOD fault: "
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000396 "STATUS_WORD = {:#06x}, "
397 "STATUS_MFR_SPECIFIC = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000398 shortName, statusWord, statusMFR)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000399 .c_str());
400 }
Brandon Wyman993b5542021-12-21 22:55:16 +0000401 pgoodFault++;
402 }
403 }
404 else
405 {
406 pgoodFault = 0;
407 }
408}
409
Brandon Wyman39ea02b2021-11-23 23:22:23 +0000410void PowerSupply::determineMFRFault()
411{
412 if (bindPath.string().find("ibm-cffps") != std::string::npos)
413 {
414 // IBM MFR_SPECIFIC[4] is PS_Kill fault
415 if (statusMFR & 0x10)
416 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000417 if (psKillFault < DEGLITCH_LIMIT)
418 {
419 psKillFault++;
420 }
421 }
422 else
423 {
424 psKillFault = 0;
Brandon Wyman39ea02b2021-11-23 23:22:23 +0000425 }
426 // IBM MFR_SPECIFIC[6] is 12Vcs fault.
427 if (statusMFR & 0x40)
428 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000429 if (ps12VcsFault < DEGLITCH_LIMIT)
430 {
431 ps12VcsFault++;
432 }
433 }
434 else
435 {
436 ps12VcsFault = 0;
Brandon Wyman39ea02b2021-11-23 23:22:23 +0000437 }
438 // IBM MFR_SPECIFIC[7] is 12V Current-Share fault.
439 if (statusMFR & 0x80)
440 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000441 if (psCS12VFault < DEGLITCH_LIMIT)
442 {
443 psCS12VFault++;
444 }
445 }
446 else
447 {
448 psCS12VFault = 0;
Brandon Wyman39ea02b2021-11-23 23:22:23 +0000449 }
450 }
451}
452
Brandon Wyman6c2ac392021-12-21 22:23:06 +0000453void PowerSupply::analyzeMFRFault()
454{
455 if (statusWord & phosphor::pmbus::status_word::MFR_SPECIFIC_FAULT)
456 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000457 if (mfrFault < DEGLITCH_LIMIT)
Brandon Wyman6c2ac392021-12-21 22:23:06 +0000458 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000459 if (statusWord != statusWordOld)
460 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000461 log<level::ERR>(fmt::format("{} MFR fault: "
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000462 "STATUS_WORD = {:#06x} "
463 "STATUS_MFR_SPECIFIC = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000464 shortName, statusWord, statusMFR)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000465 .c_str());
466 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000467 mfrFault++;
Brandon Wyman6c2ac392021-12-21 22:23:06 +0000468 }
469
Brandon Wyman6c2ac392021-12-21 22:23:06 +0000470 determineMFRFault();
471 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000472 else
473 {
474 mfrFault = 0;
475 }
Brandon Wyman6c2ac392021-12-21 22:23:06 +0000476}
477
Brandon Wymanf087f472021-12-22 00:04:27 +0000478void PowerSupply::analyzeVinUVFault()
479{
480 if (statusWord & phosphor::pmbus::status_word::VIN_UV_FAULT)
481 {
Brandon Wymanc2906f42021-12-21 20:14:56 +0000482 if (vinUVFault < DEGLITCH_LIMIT)
Brandon Wymanf087f472021-12-22 00:04:27 +0000483 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000484 if (statusWord != statusWordOld)
485 {
486 log<level::ERR>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000487 fmt::format("{} VIN_UV fault: STATUS_WORD = {:#06x}, "
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000488 "STATUS_MFR_SPECIFIC = {:#04x}, "
489 "STATUS_INPUT = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000490 shortName, statusWord, statusMFR, statusInput)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000491 .c_str());
492 }
Brandon Wymanc2906f42021-12-21 20:14:56 +0000493 vinUVFault++;
Brandon Wymanf087f472021-12-22 00:04:27 +0000494 }
Brandon Wymanf087f472021-12-22 00:04:27 +0000495 }
Brandon Wyman82affd92021-11-24 19:12:49 +0000496
497 if (vinUVFault &&
498 !(statusWord & phosphor::pmbus::status_word::VIN_UV_FAULT))
499 {
500 log<level::INFO>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000501 fmt::format("{} VIN_UV fault cleared: STATUS_WORD = {:#06x}, "
Brandon Wyman6f939a32022-03-10 18:42:20 +0000502 "STATUS_MFR_SPECIFIC = {:#04x}, "
503 "STATUS_INPUT = {:#04x}",
Brandon Wyman321a6152022-03-19 00:11:44 +0000504 shortName, statusWord, statusMFR, statusInput)
Brandon Wyman82affd92021-11-24 19:12:49 +0000505 .c_str());
Brandon Wymanc2906f42021-12-21 20:14:56 +0000506 vinUVFault = 0;
Brandon Wyman82affd92021-11-24 19:12:49 +0000507 }
Brandon Wymanf087f472021-12-22 00:04:27 +0000508}
509
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600510void PowerSupply::analyze()
511{
512 using namespace phosphor::pmbus;
513
B. J. Wyman681b2a32021-04-20 22:31:22 +0000514 if (presenceGPIO)
515 {
516 updatePresenceGPIO();
517 }
518
Brandon Wyman32453e92021-12-15 19:00:14 +0000519 if (present)
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600520 {
521 try
522 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000523 statusWordOld = statusWord;
Brandon Wyman32453e92021-12-15 19:00:14 +0000524 statusWord = pmbusIntf->read(STATUS_WORD, Type::Debug,
525 (readFail < LOG_LIMIT));
Brandon Wymanf65c4062020-08-19 13:15:53 -0500526 // Read worked, reset the fail count.
527 readFail = 0;
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600528
529 if (statusWord)
530 {
Brandon Wymanf07bc792021-10-12 19:00:35 +0000531 statusInput = pmbusIntf->read(STATUS_INPUT, Type::Debug);
Jay Meyer10d94052020-11-30 14:41:21 -0600532 statusMFR = pmbusIntf->read(STATUS_MFR, Type::Debug);
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000533 statusCML = pmbusIntf->read(STATUS_CML, Type::Debug);
Brandon Wyman6710ba22021-10-27 17:39:31 +0000534 auto status0Vout = pmbusIntf->insertPageNum(STATUS_VOUT, 0);
535 statusVout = pmbusIntf->read(status0Vout, Type::Debug);
Brandon Wymanb10b3be2021-11-09 22:12:15 +0000536 statusIout = pmbusIntf->read(STATUS_IOUT, Type::Debug);
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000537 statusFans12 = pmbusIntf->read(STATUS_FANS_1_2, Type::Debug);
Brandon Wyman96893a42021-11-05 19:56:57 +0000538 statusTemperature =
539 pmbusIntf->read(STATUS_TEMPERATURE, Type::Debug);
Brandon Wyman9ddc6222021-10-28 17:28:01 +0000540
Brandon Wymanc2203432021-12-21 23:09:48 +0000541 analyzeCMLFault();
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000542
Brandon Wymane3b0bb02021-12-21 23:16:48 +0000543 analyzeInputFault();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600544
Brandon Wymanc2c87132021-12-21 23:22:18 +0000545 analyzeVoutOVFault();
Brandon Wyman6710ba22021-10-27 17:39:31 +0000546
Brandon Wymana00e7302021-12-21 23:28:29 +0000547 analyzeIoutOCFault();
Brandon Wymanb10b3be2021-11-09 22:12:15 +0000548
Brandon Wyman08378782021-12-21 23:48:15 +0000549 analyzeVoutUVFault();
Brandon Wyman2cf46942021-10-28 19:09:16 +0000550
Brandon Wymand5d9a222021-12-21 23:59:05 +0000551 analyzeFanFault();
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000552
Brandon Wyman52cb3f22021-12-21 23:02:47 +0000553 analyzeTemperatureFault();
Brandon Wyman96893a42021-11-05 19:56:57 +0000554
Brandon Wyman993b5542021-12-21 22:55:16 +0000555 analyzePgoodFault();
Brandon Wyman2916ea52021-11-06 03:31:18 +0000556
Brandon Wyman6c2ac392021-12-21 22:23:06 +0000557 analyzeMFRFault();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600558
Brandon Wymanf087f472021-12-22 00:04:27 +0000559 analyzeVinUVFault();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600560 }
561 else
562 {
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000563 if (statusWord != statusWordOld)
564 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000565 log<level::INFO>(fmt::format("{} STATUS_WORD = {:#06x}",
566 shortName, statusWord)
Brandon Wyman9e292ee2022-03-10 22:56:23 +0000567 .c_str());
568 }
569
Brandon Wymane3f7ad22021-12-21 20:27:45 +0000570 // if INPUT/VIN_UV fault was on, it cleared, trace it.
571 if (inputFault)
572 {
573 log<level::INFO>(
574 fmt::format(
Brandon Wyman321a6152022-03-19 00:11:44 +0000575 "{} INPUT fault cleared: STATUS_WORD = {:#06x}",
576 shortName, statusWord)
Brandon Wymane3f7ad22021-12-21 20:27:45 +0000577 .c_str());
578 }
579
580 if (vinUVFault)
581 {
582 log<level::INFO>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000583 fmt::format("{} VIN_UV cleared: STATUS_WORD = {:#06x}",
584 shortName, statusWord)
Brandon Wymane3f7ad22021-12-21 20:27:45 +0000585 .c_str());
586 }
587
Brandon Wyman06ca4592021-12-06 22:52:23 +0000588 if (pgoodFault > 0)
Brandon Wyman4aecc292021-11-10 22:40:41 +0000589 {
Brandon Wyman321a6152022-03-19 00:11:44 +0000590 log<level::INFO>(
591 fmt::format("{} pgoodFault cleared", shortName)
592 .c_str());
Brandon Wyman4aecc292021-11-10 22:40:41 +0000593 }
Brandon Wymane3f7ad22021-12-21 20:27:45 +0000594
595 clearFaultFlags();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600596 }
Brandon Wyman82affd92021-11-24 19:12:49 +0000597
598 // Save off old inputVoltage value.
599 // Get latest inputVoltage.
600 // If voltage went from below minimum, and now is not, clear faults.
601 // Note: getInputVoltage() has its own try/catch.
602 int inputVoltageOld = inputVoltage;
Brandon Wyman4fc191f2022-03-10 23:07:13 +0000603 double actualInputVoltageOld = actualInputVoltage;
Brandon Wyman82affd92021-11-24 19:12:49 +0000604 getInputVoltage(actualInputVoltage, inputVoltage);
605 if ((inputVoltageOld == in_input::VIN_VOLTAGE_0) &&
606 (inputVoltage != in_input::VIN_VOLTAGE_0))
607 {
608 log<level::INFO>(
609 fmt::format(
Brandon Wyman4fc191f2022-03-10 23:07:13 +0000610 "{} READ_VIN back in range: actualInputVoltageOld = {} "
611 "actualInputVoltage = {}",
612 shortName, actualInputVoltageOld, actualInputVoltage)
Brandon Wyman82affd92021-11-24 19:12:49 +0000613 .c_str());
Brandon Wyman3225a452022-03-18 18:51:49 +0000614 clearVinUVFault();
Brandon Wyman82affd92021-11-24 19:12:49 +0000615 }
Brandon Wyman4fc191f2022-03-10 23:07:13 +0000616 else if (vinUVFault && (inputVoltage != in_input::VIN_VOLTAGE_0))
617 {
618 log<level::INFO>(
619 fmt::format(
620 "{} CLEAR_FAULTS: vinUVFault {} actualInputVoltage {}",
621 shortName, vinUVFault, actualInputVoltage)
622 .c_str());
623 // Do we have a VIN_UV fault latched that can now be cleared
Brandon Wyman3225a452022-03-18 18:51:49 +0000624 // due to voltage back in range? Attempt to clear the fault(s),
625 // re-check faults on next call.
626 clearVinUVFault();
Brandon Wyman4fc191f2022-03-10 23:07:13 +0000627 }
628 else if (std::abs(actualInputVoltageOld - actualInputVoltage) > 1.0)
629 {
630 log<level::INFO>(
631 fmt::format(
632 "{} actualInputVoltageOld = {} actualInputVoltage = {}",
633 shortName, actualInputVoltageOld, actualInputVoltage)
634 .c_str());
635 }
Matt Spinler0975eaf2022-02-14 15:38:30 -0600636
637 checkAvailability();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600638 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500639 catch (const ReadFailure& e)
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600640 {
Brandon Wyman32453e92021-12-15 19:00:14 +0000641 if (readFail < SIZE_MAX)
642 {
643 readFail++;
644 }
645 if (readFail == LOG_LIMIT)
646 {
647 phosphor::logging::commit<ReadFailure>();
648 }
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600649 }
650 }
651}
652
Brandon Wyman59a35792020-06-04 12:37:40 -0500653void PowerSupply::onOffConfig(uint8_t data)
654{
655 using namespace phosphor::pmbus;
656
657 if (present)
658 {
659 log<level::INFO>("ON_OFF_CONFIG write", entry("DATA=0x%02X", data));
660 try
661 {
662 std::vector<uint8_t> configData{data};
663 pmbusIntf->writeBinary(ON_OFF_CONFIG, configData,
664 Type::HwmonDeviceDebug);
665 }
666 catch (...)
667 {
668 // The underlying code in writeBinary will log a message to the
B. J. Wyman681b2a32021-04-20 22:31:22 +0000669 // journal if the write fails. If the ON_OFF_CONFIG is not setup
670 // as desired, later fault detection and analysis code should
671 // catch any of the fall out. We should not need to terminate
672 // the application if this write fails.
Brandon Wyman59a35792020-06-04 12:37:40 -0500673 }
674 }
675}
676
Brandon Wyman3225a452022-03-18 18:51:49 +0000677void PowerSupply::clearVinUVFault()
678{
679 // Read in1_lcrit_alarm to clear bits 3 and 4 of STATUS_INPUT.
680 // The fault bits in STAUTS_INPUT roll-up to STATUS_WORD. Clearing those
681 // bits in STATUS_INPUT should result in the corresponding STATUS_WORD bits
682 // also clearing.
683 //
684 // Do not care about return value. Should be 1 if active, 0 if not.
685 static_cast<void>(
686 pmbusIntf->read("in1_lcrit_alarm", phosphor::pmbus::Type::Hwmon));
687 vinUVFault = 0;
688}
689
Brandon Wyman3c208462020-05-13 16:25:58 -0500690void PowerSupply::clearFaults()
691{
Brandon Wyman82affd92021-11-24 19:12:49 +0000692 log<level::DEBUG>(
693 fmt::format("clearFaults() inventoryPath: {}", inventoryPath).c_str());
Brandon Wyman5474c912021-02-23 14:39:43 -0600694 faultLogged = false;
Brandon Wyman3c208462020-05-13 16:25:58 -0500695 // The PMBus device driver does not allow for writing CLEAR_FAULTS
696 // directly. However, the pmbus hwmon device driver code will send a
697 // CLEAR_FAULTS after reading from any of the hwmon "files" in sysfs, so
698 // reading in1_input should result in clearing the fault bits in
699 // STATUS_BYTE/STATUS_WORD.
700 // I do not care what the return value is.
Brandon Wyman11151532020-11-10 13:45:57 -0600701 if (present)
Brandon Wyman3c208462020-05-13 16:25:58 -0500702 {
Brandon Wymane3f7ad22021-12-21 20:27:45 +0000703 clearFaultFlags();
Matt Spinler0975eaf2022-02-14 15:38:30 -0600704 checkAvailability();
Brandon Wyman9564e942020-11-10 14:01:42 -0600705 readFail = 0;
Brandon Wyman9564e942020-11-10 14:01:42 -0600706
Brandon Wyman11151532020-11-10 13:45:57 -0600707 try
708 {
Brandon Wyman3225a452022-03-18 18:51:49 +0000709 clearVinUVFault();
Brandon Wyman11151532020-11-10 13:45:57 -0600710 static_cast<void>(
711 pmbusIntf->read("in1_input", phosphor::pmbus::Type::Hwmon));
712 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500713 catch (const ReadFailure& e)
Brandon Wyman11151532020-11-10 13:45:57 -0600714 {
715 // Since I do not care what the return value is, I really do not
B. J. Wyman681b2a32021-04-20 22:31:22 +0000716 // care much if it gets a ReadFailure either. However, this
717 // should not prevent the application from continuing to run, so
718 // catching the read failure.
Brandon Wyman11151532020-11-10 13:45:57 -0600719 }
Brandon Wyman3c208462020-05-13 16:25:58 -0500720 }
721}
722
Brandon Wymanaed1f752019-11-25 18:10:52 -0600723void PowerSupply::inventoryChanged(sdbusplus::message::message& msg)
724{
725 std::string msgSensor;
Patrick Williamsabe49412020-05-13 17:59:47 -0500726 std::map<std::string, std::variant<uint32_t, bool>> msgData;
Brandon Wymanaed1f752019-11-25 18:10:52 -0600727 msg.read(msgSensor, msgData);
728
729 // Check if it was the Present property that changed.
730 auto valPropMap = msgData.find(PRESENT_PROP);
731 if (valPropMap != msgData.end())
732 {
733 if (std::get<bool>(valPropMap->second))
734 {
735 present = true;
B. J. Wyman681b2a32021-04-20 22:31:22 +0000736 // TODO: Immediately trying to read or write the "files" causes
737 // read or write failures.
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500738 using namespace std::chrono_literals;
739 std::this_thread::sleep_for(20ms);
Brandon Wyman9564e942020-11-10 14:01:42 -0600740 pmbusIntf->findHwmonDir();
Brandon Wyman59a35792020-06-04 12:37:40 -0500741 onOffConfig(phosphor::pmbus::ON_OFF_CONFIG_CONTROL_PIN_ONLY);
Brandon Wymanaed1f752019-11-25 18:10:52 -0600742 clearFaults();
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500743 updateInventory();
Brandon Wymanaed1f752019-11-25 18:10:52 -0600744 }
745 else
746 {
747 present = false;
748
749 // Clear out the now outdated inventory properties
750 updateInventory();
751 }
Matt Spinler0975eaf2022-02-14 15:38:30 -0600752 checkAvailability();
Brandon Wymanaed1f752019-11-25 18:10:52 -0600753 }
754}
755
Brandon Wyman9a507db2021-02-25 16:15:22 -0600756void PowerSupply::inventoryAdded(sdbusplus::message::message& msg)
757{
758 sdbusplus::message::object_path path;
759 msg.read(path);
760 // Make sure the signal is for the PSU inventory path
761 if (path == inventoryPath)
762 {
763 std::map<std::string, std::map<std::string, std::variant<bool>>>
764 interfaces;
765 // Get map of interfaces and their properties
766 msg.read(interfaces);
767
768 auto properties = interfaces.find(INVENTORY_IFACE);
769 if (properties != interfaces.end())
770 {
771 auto property = properties->second.find(PRESENT_PROP);
772 if (property != properties->second.end())
773 {
774 present = std::get<bool>(property->second);
775
776 log<level::INFO>(fmt::format("Power Supply {} Present {}",
777 inventoryPath, present)
778 .c_str());
779
780 updateInventory();
Matt Spinler0975eaf2022-02-14 15:38:30 -0600781 checkAvailability();
Brandon Wyman9a507db2021-02-25 16:15:22 -0600782 }
783 }
784 }
785}
786
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500787void PowerSupply::updateInventory()
788{
789 using namespace phosphor::pmbus;
790
Chanh Nguyenc12c53b2021-04-06 17:24:47 +0700791#if IBM_VPD
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500792 std::string ccin;
793 std::string pn;
794 std::string fn;
795 std::string header;
796 std::string sn;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500797 using PropertyMap =
George Liu070c1bc2020-10-12 11:28:01 +0800798 std::map<std::string,
799 std::variant<std::string, std::vector<uint8_t>, bool>>;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500800 PropertyMap assetProps;
George Liu070c1bc2020-10-12 11:28:01 +0800801 PropertyMap operProps;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500802 PropertyMap versionProps;
803 PropertyMap ipzvpdDINFProps;
804 PropertyMap ipzvpdVINIProps;
805 using InterfaceMap = std::map<std::string, PropertyMap>;
806 InterfaceMap interfaces;
807 using ObjectMap = std::map<sdbusplus::message::object_path, InterfaceMap>;
808 ObjectMap object;
809#endif
B. J. Wyman681b2a32021-04-20 22:31:22 +0000810 log<level::DEBUG>(
811 fmt::format("updateInventory() inventoryPath: {}", inventoryPath)
812 .c_str());
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500813
814 if (present)
815 {
816 // TODO: non-IBM inventory updates?
817
Chanh Nguyenc12c53b2021-04-06 17:24:47 +0700818#if IBM_VPD
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500819 try
820 {
821 ccin = pmbusIntf->readString(CCIN, Type::HwmonDeviceDebug);
822 assetProps.emplace(MODEL_PROP, ccin);
Adriana Kobylak572a9052021-03-30 15:58:07 +0000823 modelName = ccin;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500824 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500825 catch (const ReadFailure& e)
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500826 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000827 // Ignore the read failure, let pmbus code indicate failure,
828 // path...
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500829 // TODO - ibm918
830 // https://github.com/openbmc/docs/blob/master/designs/vpd-collection.md
831 // The BMC must log errors if any of the VPD cannot be properly
832 // parsed or fails ECC checks.
833 }
834
835 try
836 {
837 pn = pmbusIntf->readString(PART_NUMBER, Type::HwmonDeviceDebug);
838 assetProps.emplace(PN_PROP, pn);
839 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500840 catch (const ReadFailure& e)
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500841 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000842 // Ignore the read failure, let pmbus code indicate failure,
843 // path...
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500844 }
845
846 try
847 {
848 fn = pmbusIntf->readString(FRU_NUMBER, Type::HwmonDeviceDebug);
Brandon Wymana169b0f2021-12-07 20:18:06 +0000849 assetProps.emplace(SPARE_PN_PROP, fn);
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500850 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500851 catch (const ReadFailure& e)
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500852 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000853 // Ignore the read failure, let pmbus code indicate failure,
854 // path...
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500855 }
856
857 try
858 {
859 header =
860 pmbusIntf->readString(SERIAL_HEADER, Type::HwmonDeviceDebug);
861 sn = pmbusIntf->readString(SERIAL_NUMBER, Type::HwmonDeviceDebug);
Mike Capps1cb0f132022-03-14 11:40:30 -0400862 assetProps.emplace(SN_PROP, header + sn);
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500863 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500864 catch (const ReadFailure& e)
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500865 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000866 // Ignore the read failure, let pmbus code indicate failure,
867 // path...
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500868 }
869
870 try
871 {
Brandon Wymanc9efe412020-10-09 15:42:50 -0500872 fwVersion =
873 pmbusIntf->readString(FW_VERSION, Type::HwmonDeviceDebug);
874 versionProps.emplace(VERSION_PROP, fwVersion);
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500875 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500876 catch (const ReadFailure& e)
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500877 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000878 // Ignore the read failure, let pmbus code indicate failure,
879 // path...
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500880 }
881
882 ipzvpdVINIProps.emplace("CC",
883 std::vector<uint8_t>(ccin.begin(), ccin.end()));
884 ipzvpdVINIProps.emplace("PN",
885 std::vector<uint8_t>(pn.begin(), pn.end()));
886 ipzvpdVINIProps.emplace("FN",
887 std::vector<uint8_t>(fn.begin(), fn.end()));
Brandon Wyman33d492f2022-03-23 20:45:17 +0000888 std::string header_sn = header + sn;
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500889 ipzvpdVINIProps.emplace(
890 "SN", std::vector<uint8_t>(header_sn.begin(), header_sn.end()));
891 std::string description = "IBM PS";
892 ipzvpdVINIProps.emplace(
893 "DR", std::vector<uint8_t>(description.begin(), description.end()));
894
Ben Tynerf8d8c462022-01-27 16:09:45 -0600895 // Populate the VINI Resource Type (RT) keyword
896 ipzvpdVINIProps.emplace("RT", std::vector<uint8_t>{'V', 'I', 'N', 'I'});
897
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500898 // Update the Resource Identifier (RI) keyword
899 // 2 byte FRC: 0x0003
900 // 2 byte RID: 0x1000, 0x1001...
901 std::uint8_t num = std::stoul(
902 inventoryPath.substr(inventoryPath.size() - 1, 1), nullptr, 0);
903 std::vector<uint8_t> ri{0x00, 0x03, 0x10, num};
904 ipzvpdDINFProps.emplace("RI", ri);
905
906 // Fill in the FRU Label (FL) keyword.
907 std::string fl = "E";
908 fl.push_back(inventoryPath.back());
909 fl.resize(FL_KW_SIZE, ' ');
910 ipzvpdDINFProps.emplace("FL",
911 std::vector<uint8_t>(fl.begin(), fl.end()));
912
Ben Tynerf8d8c462022-01-27 16:09:45 -0600913 // Populate the DINF Resource Type (RT) keyword
914 ipzvpdDINFProps.emplace("RT", std::vector<uint8_t>{'D', 'I', 'N', 'F'});
915
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500916 interfaces.emplace(ASSET_IFACE, std::move(assetProps));
917 interfaces.emplace(VERSION_IFACE, std::move(versionProps));
918 interfaces.emplace(DINF_IFACE, std::move(ipzvpdDINFProps));
919 interfaces.emplace(VINI_IFACE, std::move(ipzvpdVINIProps));
920
George Liu070c1bc2020-10-12 11:28:01 +0800921 // Update the Functional
922 operProps.emplace(FUNCTIONAL_PROP, present);
923 interfaces.emplace(OPERATIONAL_STATE_IFACE, std::move(operProps));
924
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500925 auto path = inventoryPath.substr(strlen(INVENTORY_OBJ_PATH));
926 object.emplace(path, std::move(interfaces));
927
928 try
929 {
930 auto service =
931 util::getService(INVENTORY_OBJ_PATH, INVENTORY_MGR_IFACE, bus);
932
933 if (service.empty())
934 {
935 log<level::ERR>("Unable to get inventory manager service");
936 return;
937 }
938
939 auto method =
940 bus.new_method_call(service.c_str(), INVENTORY_OBJ_PATH,
941 INVENTORY_MGR_IFACE, "Notify");
942
943 method.append(std::move(object));
944
945 auto reply = bus.call(method);
946 }
Patrick Williamsc1d4de52021-10-06 12:45:57 -0500947 catch (const std::exception& e)
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500948 {
Jay Meyer6a3fd2c2020-08-25 16:37:16 -0500949 log<level::ERR>(
950 std::string(e.what() + std::string(" PATH=") + inventoryPath)
951 .c_str());
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500952 }
953#endif
954 }
955}
956
Adriana Kobylak4175ffb2021-08-02 14:51:05 +0000957void PowerSupply::getInputVoltage(double& actualInputVoltage,
958 int& inputVoltage) const
959{
960 using namespace phosphor::pmbus;
961
962 actualInputVoltage = in_input::VIN_VOLTAGE_0;
963 inputVoltage = in_input::VIN_VOLTAGE_0;
964
965 if (present)
966 {
967 try
968 {
969 // Read input voltage in millivolts
970 auto inputVoltageStr = pmbusIntf->readString(READ_VIN, Type::Hwmon);
971
972 // Convert to volts
973 actualInputVoltage = std::stod(inputVoltageStr) / 1000;
974
975 // Calculate the voltage based on voltage thresholds
976 if (actualInputVoltage < in_input::VIN_VOLTAGE_MIN)
977 {
978 inputVoltage = in_input::VIN_VOLTAGE_0;
979 }
980 else if (actualInputVoltage < in_input::VIN_VOLTAGE_110_THRESHOLD)
981 {
982 inputVoltage = in_input::VIN_VOLTAGE_110;
983 }
984 else
985 {
986 inputVoltage = in_input::VIN_VOLTAGE_220;
987 }
988 }
989 catch (const std::exception& e)
990 {
991 log<level::ERR>(
Brandon Wyman321a6152022-03-19 00:11:44 +0000992 fmt::format("{} READ_VIN read error: {}", shortName, e.what())
993 .c_str());
Adriana Kobylak4175ffb2021-08-02 14:51:05 +0000994 }
995 }
996}
997
Matt Spinler0975eaf2022-02-14 15:38:30 -0600998void PowerSupply::checkAvailability()
999{
1000 bool origAvailability = available;
1001 available = present && !hasInputFault() && !hasVINUVFault() &&
1002 !hasPSKillFault() && !hasIoutOCFault();
1003
1004 if (origAvailability != available)
1005 {
1006 auto invpath = inventoryPath.substr(strlen(INVENTORY_OBJ_PATH));
1007 phosphor::power::psu::setAvailable(bus, invpath, available);
Matt Spinlerca1e9ea2022-02-18 14:03:08 -06001008
1009 // Check if the health rollup needs to change based on the
1010 // new availability value.
1011 phosphor::power::psu::handleChassisHealthRollup(bus, inventoryPath,
1012 !available);
Matt Spinler0975eaf2022-02-14 15:38:30 -06001013 }
1014}
1015
Brandon Wyman3f1242f2020-01-28 13:11:25 -06001016} // namespace phosphor::power::psu