Add support for power supply off when it should be on
If the power good bit indicates false, or the UNIT_IS_OFF bit is on,
create an error log and attach STATUS_WORD, STATUS_INPUT, STATUS_VOUT,
STATUS_IOUT, and MFR_SPECIFIC values to the metadata. The combination of
those PMBus command results should give an indication as to why the
power supply has turned off.
Change-Id: I692a8fdeac3fe208a5eb70964db7b5094cfb587c
Signed-off-by: Brandon Wyman <bjwyman@gmail.com>
diff --git a/power-supply/power_supply.cpp b/power-supply/power_supply.cpp
index 1510753..467144b 100644
--- a/power-supply/power_supply.cpp
+++ b/power-supply/power_supply.cpp
@@ -90,7 +90,12 @@
{
if (present)
{
- auto curUVFault = pmbusIntf.readBit(VIN_UV_FAULT, Type::Hwmon);
+ std::uint16_t statusWord = 0;
+ std::uint8_t statusInput = 0;
+
+ // Read the 2 byte STATUS_WORD value to check for faults.
+ statusWord = pmbusIntf.read(STATUS_WORD, Type::Debug);
+
//TODO: 3 consecutive reads should be performed.
// If 3 consecutive reads are seen, log the fault.
// Driver gives cached value, read once a second.
@@ -98,63 +103,96 @@
// If count reaches 3, we have fault. If count reaches 0, fault is
// cleared.
- auto curInputFault = pmbusIntf.readBit(INPUT_FAULT_WARN,
- Type::Hwmon);
-
- if (curUVFault != vinUVFault)
+ if ((statusWord & status_word::VIN_UV_FAULT) && !vinUVFault)
{
- vinUVFault = curUVFault;
+ vinUVFault = true;
- if (curUVFault)
- {
- std::uint16_t statusWord = 0;
- statusWord = pmbusIntf.read(STATUS_WORD, Type::Debug);
+ util::NamesValues nv;
+ nv.add("STATUS_WORD", statusWord);
- util::NamesValues nv;
- nv.add("STATUS_WORD", statusWord);
+ using metadata = xyz::openbmc_project::Power::Fault::
+ PowerSupplyUnderVoltageFault;
- using metadata = xyz::openbmc_project::Power::Fault::
- PowerSupplyUnderVoltageFault;
+ report<PowerSupplyUnderVoltageFault>(
+ metadata::RAW_STATUS(nv.get().c_str()));
- report<PowerSupplyUnderVoltageFault>(
- metadata::RAW_STATUS(nv.get().c_str()));
-
- vinUVFault = true;
- }
- else
- {
- log<level::INFO>("VIN_UV_FAULT cleared",
- entry("POWERSUPPLY=%s",
- inventoryPath.c_str()));
- }
-
+ vinUVFault = true;
+ }
+ else
+ {
+ vinUVFault = false;
+ log<level::INFO>("VIN_UV_FAULT cleared",
+ entry("POWERSUPPLY=%s",
+ inventoryPath.c_str()));
}
- if (curInputFault != inputFault)
+ if ((statusWord & status_word::INPUT_FAULT_WARN) && !inputFault)
{
- if (curInputFault)
- {
- std::uint16_t statusWord = 0;
- std::uint8_t statusInput = 0;
+ inputFault = true;
- statusWord = pmbusIntf.read(STATUS_WORD, Type::Debug);
+ statusInput = pmbusIntf.read(STATUS_INPUT, Type::Debug);
+
+ util::NamesValues nv;
+ nv.add("STATUS_WORD", statusWord);
+ nv.add("STATUS_INPUT", statusInput);
+
+ using metadata = xyz::openbmc_project::Power::Fault::
+ PowerSupplyInputFault;
+
+ report<PowerSupplyInputFault>(metadata::RAW_STATUS(
+ nv.get().c_str()));
+ }
+ else
+ {
+ if ((inputFault) &&
+ !(statusWord & status_word::INPUT_FAULT_WARN))
+ {
+ inputFault = false;
+
statusInput = pmbusIntf.read(STATUS_INPUT, Type::Debug);
+ log<level::INFO>("INPUT_FAULT_WARN cleared",
+ entry("POWERSUPPLY=%s",
+ inventoryPath.c_str()),
+ entry("STATUS_WORD=0x%04X", statusWord),
+ entry("STATUS_INPUT=0x%02X", statusInput));
+ }
+ }
+
+ if (powerOn)
+ {
+ // Check PG# and UNIT_IS_OFF
+ if (((statusWord & status_word::POWER_GOOD_NEGATED) ||
+ (statusWord & status_word::UNIT_IS_OFF)) &&
+ !powerOnFault)
+ {
+ std::uint8_t statusVout = 0;
+ std::uint8_t statusIout = 0;
+ std::uint8_t statusMFR = 0;
+
+ statusInput = pmbusIntf.read(STATUS_INPUT, Type::Debug);
+ auto status0Vout = pmbusIntf.insertPageNum(STATUS_VOUT, 0);
+ statusVout = pmbusIntf.read(status0Vout, Type::Debug);
+ statusIout = pmbusIntf.read(STATUS_IOUT, Type::Debug);
+ statusMFR = pmbusIntf.read(STATUS_MFR, Type::Debug);
+
util::NamesValues nv;
nv.add("STATUS_WORD", statusWord);
nv.add("STATUS_INPUT", statusInput);
+ nv.add("STATUS_VOUT", statusVout);
+ nv.add("STATUS_IOUT", statusIout);
+ nv.add("MFR_SPECIFIC", statusMFR);
using metadata = xyz::openbmc_project::Power::Fault::
- PowerSupplyInputFault;
+ PowerSupplyShouldBeOn;
- report<PowerSupplyInputFault>(
- metadata::RAW_STATUS(nv.get().c_str()));
+ // A power supply is OFF (or pgood low) but should be on.
+ report<PowerSupplyShouldBeOn>(
+ metadata::RAW_STATUS(nv.get().c_str()),
+ metadata::CALLOUT_INVENTORY_PATH(
+ inventoryPath.c_str()));
- inputFault = true;
- }
- else
- {
- inputFault = false;
+ powerOnFault = true;
}
}
@@ -239,6 +277,7 @@
readFailLogged = false;
vinUVFault = false;
inputFault = false;
+ powerOnFault = false;
powerOnTimer.start(powerOnInterval, Timer::TimerType::oneshot);
}
else
diff --git a/power-supply/power_supply.hpp b/power-supply/power_supply.hpp
index 317c20b..e9bd9f3 100644
--- a/power-supply/power_supply.hpp
+++ b/power-supply/power_supply.hpp
@@ -96,6 +96,9 @@
/** @brief True if the power is on. */
bool powerOn = false;
+ /** @brief True if power on fault has been detected/reported. */
+ bool powerOnFault = false;
+
/** @brief The sd_event structure used by the power on timer. */
event::Event& event;
@@ -119,9 +122,7 @@
/** @brief Used to subscribe to D-Bus power on state changes **/
std::unique_ptr<sdbusplus::bus::match_t> powerOnMatch;
- /**
- * @brief Has a PMBus read failure already been logged?
- */
+ /** @brief Has a PMBus read failure already been logged? */
bool readFailLogged = false;
/**
@@ -140,7 +141,8 @@
*/
bool inputFault = false;
- /** @brief Callback for inventory property changes
+ /**
+ * @brief Callback for inventory property changes
*
* Process change of Present property for power supply.
*
@@ -166,7 +168,9 @@
*/
void updatePowerState();
- /** @brief Callback for power state property changes
+ /**
+ * @brief Callback for power state property changes
+ *
* Process changes to the powered on stat property for the system.
*
* @param[in] msg - Data associated with the power state signal