psu-ng: Add in detection of PGOOD fault
If STATUS_WORD has bit 11 high (POWER_GOOD# is inactive) or bit 6 high
(unit is OFF), consider that a PGOOD fault. Lowest priority error to
check, log an error if a power supply has a PGOOD fault, call out the
power supply.
Tested:
Simulated POWER_GOOD# / OFF and verified error logged.
Verified normal operations on real hardware do not log error.
Get power supply in bad state via i2cset commands:
1. Write 0x19 to 0x02 (ON_OFF_CONFIG, OPERATION command only).
2. Write 0x00 to 0x01 (Immediate off OPERATION command).
3. Restart service, error logged for STATUS_WORD = 0x0800.
4. Write 0x19 to 0x02, 0x00 to 0x01 while powered on.
5. Error logged for STATUS_WORD=0x0840.
Change-Id: I24dd1db780510d39dc245e76977099f790a2e59e
Signed-off-by: Brandon Wyman <bjwyman@gmail.com>
diff --git a/phosphor-power-supply/test/power_supply_tests.cpp b/phosphor-power-supply/test/power_supply_tests.cpp
index 7fb7d03..5d96fea 100644
--- a/phosphor-power-supply/test/power_supply_tests.cpp
+++ b/phosphor-power-supply/test/power_supply_tests.cpp
@@ -147,6 +147,7 @@
EXPECT_EQ(psu->hasVINUVFault(), false);
EXPECT_EQ(psu->hasVoutOVFault(), false);
EXPECT_EQ(psu->hasTempFault(), false);
+ EXPECT_EQ(psu->hasPgoodFault(), false);
}
catch (...)
{
@@ -193,6 +194,7 @@
EXPECT_EQ(psu.hasCommFault(), false);
EXPECT_EQ(psu.hasVoutOVFault(), false);
EXPECT_EQ(psu.hasTempFault(), false);
+ EXPECT_EQ(psu.hasPgoodFault(), false);
}
PowerSupply psu2{bus, PSUInventoryPath, 5, 0x6a, PSUGPIOLineName};
@@ -226,6 +228,7 @@
EXPECT_EQ(psu2.hasCommFault(), false);
EXPECT_EQ(psu2.hasVoutOVFault(), false);
EXPECT_EQ(psu2.hasTempFault(), false);
+ EXPECT_EQ(psu2.hasPgoodFault(), false);
// Update expectations for STATUS_WORD input fault/warn
// STATUS_INPUT fault bits ... on.
@@ -241,6 +244,7 @@
EXPECT_EQ(psu2.hasCommFault(), false);
EXPECT_EQ(psu2.hasVoutOVFault(), false);
EXPECT_EQ(psu2.hasTempFault(), false);
+ EXPECT_EQ(psu2.hasPgoodFault(), false);
}
// STATUS_WORD INPUT/UV fault.
@@ -264,6 +268,7 @@
EXPECT_EQ(psu2.hasCommFault(), false);
EXPECT_EQ(psu2.hasVoutOVFault(), false);
EXPECT_EQ(psu2.hasTempFault(), false);
+ EXPECT_EQ(psu2.hasPgoodFault(), false);
}
// STATUS_WORD MFR fault.
@@ -286,6 +291,7 @@
EXPECT_EQ(psu2.hasCommFault(), false);
EXPECT_EQ(psu2.hasVoutOVFault(), false);
EXPECT_EQ(psu2.hasTempFault(), false);
+ EXPECT_EQ(psu2.hasPgoodFault(), false);
}
// Temperature fault.
@@ -308,6 +314,7 @@
EXPECT_EQ(psu2.hasCommFault(), false);
EXPECT_EQ(psu2.hasVoutOVFault(), false);
EXPECT_EQ(psu2.hasTempFault(), true);
+ EXPECT_EQ(psu2.hasPgoodFault(), false);
}
// CML fault
@@ -330,6 +337,7 @@
EXPECT_EQ(psu2.hasCommFault(), true);
EXPECT_EQ(psu2.hasVoutOVFault(), false);
EXPECT_EQ(psu2.hasTempFault(), false);
+ EXPECT_EQ(psu2.hasPgoodFault(), false);
}
// VOUT_OV_FAULT fault
@@ -354,6 +362,7 @@
EXPECT_EQ(psu2.hasCommFault(), false);
EXPECT_EQ(psu2.hasVoutOVFault(), true);
EXPECT_EQ(psu2.hasTempFault(), false);
+ EXPECT_EQ(psu2.hasPgoodFault(), false);
}
// Ignore fan fault
@@ -373,7 +382,34 @@
EXPECT_EQ(psu2.hasCommFault(), false);
EXPECT_EQ(psu2.hasVoutOVFault(), false);
EXPECT_EQ(psu2.hasTempFault(), false);
+ EXPECT_EQ(psu2.hasPgoodFault(), false);
}
+
+ {
+ // PGOOD/OFF fault.
+ // First STATUS_WORD with no bits set.
+ PMBusExpectations expectations;
+ setPMBusExpectations(mockPMBus, expectations);
+ psu2.analyze();
+ EXPECT_EQ(psu2.isFaulted(), false);
+ // POWER_GOOD# inactive, and OFF bit on.
+ expectations.statusWordValue =
+ ((status_word::POWER_GOOD_NEGATED) | (status_word::UNIT_IS_OFF));
+ // STATUS_INPUT, STATUS_MFR, STATUS_CML, STATUS_VOUT, and
+ // STATUS_TEMPERATURE: Don't care if bits set or not (defaults).
+ setPMBusExpectations(mockPMBus, expectations);
+ psu2.analyze();
+ EXPECT_EQ(psu2.isPresent(), true);
+ EXPECT_EQ(psu2.isFaulted(), true);
+ EXPECT_EQ(psu2.hasInputFault(), false);
+ EXPECT_EQ(psu2.hasMFRFault(), false);
+ EXPECT_EQ(psu2.hasVINUVFault(), false);
+ EXPECT_EQ(psu2.hasCommFault(), false);
+ EXPECT_EQ(psu2.hasVoutOVFault(), false);
+ EXPECT_EQ(psu2.hasTempFault(), false);
+ EXPECT_EQ(psu2.hasPgoodFault(), true);
+ }
+
// TODO: ReadFailure
}
@@ -446,6 +482,7 @@
EXPECT_EQ(psu.hasCommFault(), false);
EXPECT_EQ(psu.hasVoutOVFault(), false);
EXPECT_EQ(psu.hasTempFault(), false);
+ EXPECT_EQ(psu.hasPgoodFault(), false);
// STATUS_WORD with fault bits galore!
expectations.statusWordValue = 0xFFFF;
@@ -469,6 +506,7 @@
EXPECT_EQ(psu.hasCommFault(), true);
EXPECT_EQ(psu.hasVoutOVFault(), true);
EXPECT_EQ(psu.hasTempFault(), true);
+ EXPECT_EQ(psu.hasPgoodFault(), true);
EXPECT_CALL(mockPMBus, read("in1_input", _))
.Times(1)
.WillOnce(Return(209000));
@@ -481,6 +519,7 @@
EXPECT_EQ(psu.hasCommFault(), false);
EXPECT_EQ(psu.hasVoutOVFault(), false);
EXPECT_EQ(psu.hasTempFault(), false);
+ EXPECT_EQ(psu.hasPgoodFault(), false);
// TODO: Faults clear on missing/present?
}
@@ -734,3 +773,42 @@
psu.analyze();
EXPECT_EQ(psu.hasTempFault(), false);
}
+
+TEST_F(PowerSupplyTests, HasPgoodFault)
+{
+ auto bus = sdbusplus::bus::new_default();
+
+ PowerSupply psu{bus, PSUInventoryPath, 3, 0x6b, PSUGPIOLineName};
+ MockedGPIOInterface* mockPresenceGPIO =
+ static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
+ // Always return 1 to indicate present.
+ EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
+ psu.analyze();
+ MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
+ EXPECT_EQ(psu.hasPgoodFault(), false);
+ // STATUS_WORD 0x0000 is powered on, no faults.
+ PMBusExpectations expectations;
+ setPMBusExpectations(mockPMBus, expectations);
+ psu.analyze();
+ EXPECT_EQ(psu.hasPgoodFault(), false);
+ // Turn PGOOD# off (fault on).
+ expectations.statusWordValue = (status_word::POWER_GOOD_NEGATED);
+ setPMBusExpectations(mockPMBus, expectations);
+ psu.analyze();
+ EXPECT_EQ(psu.hasPgoodFault(), true);
+ // Back to no fault bits on in STATUS_WORD
+ expectations.statusWordValue = 0;
+ setPMBusExpectations(mockPMBus, expectations);
+ psu.analyze();
+ EXPECT_EQ(psu.hasPgoodFault(), false);
+ // Turn OFF bit on
+ expectations.statusWordValue = (status_word::UNIT_IS_OFF);
+ setPMBusExpectations(mockPMBus, expectations);
+ psu.analyze();
+ EXPECT_EQ(psu.hasPgoodFault(), true);
+ // Back to no fault bits on in STATUS_WORD
+ expectations.statusWordValue = 0;
+ setPMBusExpectations(mockPMBus, expectations);
+ psu.analyze();
+ EXPECT_EQ(psu.hasPgoodFault(), false);
+}