Update analyze function to check STATUS_WORD
The STATUS_WORD PMBus command response will be the start of the power
supply fault analysis. Update the analyze() function to read its value
and process (select) fault bits.
Signed-off-by: Brandon Wyman <bjwyman@gmail.com>
Change-Id: If7274ad237c0604a56008676ae64804a5fd2854e
diff --git a/phosphor-power-supply/meson.build b/phosphor-power-supply/meson.build
index 9554dd9..922a67e 100644
--- a/phosphor-power-supply/meson.build
+++ b/phosphor-power-supply/meson.build
@@ -1,9 +1,10 @@
-executable(
+phosphor_psu_monitor = executable(
'phosphor-psu-monitor',
'main.cpp',
'psu_manager.cpp',
'power_supply.cpp',
+ 'util.cpp',
dependencies: [
sdbusplus,
sdeventplus,
@@ -14,3 +15,9 @@
libpower,
]
)
+
+power_supply = phosphor_psu_monitor.extract_objects('power_supply.cpp')
+
+if get_option('tests').enabled()
+ subdir('test')
+endif
diff --git a/phosphor-power-supply/power_supply.cpp b/phosphor-power-supply/power_supply.cpp
index a6be9f5..7e617a9 100644
--- a/phosphor-power-supply/power_supply.cpp
+++ b/phosphor-power-supply/power_supply.cpp
@@ -1,24 +1,21 @@
#include "power_supply.hpp"
#include "types.hpp"
-#include "utility.hpp"
+#include "util.hpp"
-namespace phosphor
-{
-namespace power
-{
-namespace psu
+#include <xyz/openbmc_project/Common/Device/error.hpp>
+
+namespace phosphor::power::psu
{
using namespace phosphor::logging;
+using namespace sdbusplus::xyz::openbmc_project::Common::Device::Error;
void PowerSupply::updatePresence()
{
try
{
- // Use getProperty utility function to get presence status.
- util::getProperty(INVENTORY_IFACE, PRESENT_PROP, inventoryPath,
- INVENTORY_MGR_IFACE, bus, this->present);
+ present = getPresence(bus, inventoryPath);
}
catch (const sdbusplus::exception::SdBusError& e)
{
@@ -28,6 +25,74 @@
}
}
+void PowerSupply::analyze()
+{
+ using namespace phosphor::pmbus;
+
+ if (present)
+ {
+ try
+ {
+ auto statusWord{pmbusIntf->read(STATUS_WORD, Type::Debug)};
+
+ if (statusWord)
+ {
+ if (statusWord & status_word::INPUT_FAULT_WARN)
+ {
+ if (!inputFault)
+ {
+ log<level::INFO>(
+ "INPUT fault",
+ entry("STATUS_WORD=0x%04X",
+ static_cast<uint16_t>(statusWord)));
+ }
+
+ faultFound = true;
+ inputFault = true;
+ }
+
+ if (statusWord & status_word::MFR_SPECIFIC_FAULT)
+ {
+ if (!mfrFault)
+ {
+ log<level::INFO>(
+ "MFRSPECIFIC fault",
+ entry("STATUS_WORD=0x%04X",
+ static_cast<uint16_t>(statusWord)));
+ }
+ faultFound = true;
+ mfrFault = true;
+ }
+
+ if (statusWord & status_word::VIN_UV_FAULT)
+ {
+ if (!vinUVFault)
+ {
+ log<level::INFO>(
+ "VIN_UV fault",
+ entry("STATUS_WORD=0x%04X",
+ static_cast<uint16_t>(statusWord)));
+ }
+
+ faultFound = true;
+ vinUVFault = true;
+ }
+ }
+ else
+ {
+ faultFound = false;
+ inputFault = false;
+ mfrFault = false;
+ vinUVFault = false;
+ }
+ }
+ catch (ReadFailure& e)
+ {
+ phosphor::logging::commit<ReadFailure>();
+ }
+ }
+}
+
void PowerSupply::inventoryChanged(sdbusplus::message::message& msg)
{
std::string msgSensor;
@@ -53,6 +118,4 @@
}
}
-} // namespace psu
-} // namespace power
-} // namespace phosphor
+} // namespace phosphor::power::psu
diff --git a/phosphor-power-supply/power_supply.hpp b/phosphor-power-supply/power_supply.hpp
index c3ff051..30fbf74 100644
--- a/phosphor-power-supply/power_supply.hpp
+++ b/phosphor-power-supply/power_supply.hpp
@@ -2,11 +2,13 @@
#include "pmbus.hpp"
#include "types.hpp"
+#include "utility.hpp"
#include <sdbusplus/bus/match.hpp>
namespace phosphor::power::psu
{
+
/**
* @class PowerSupply
* Represents a PMBus power supply device.
@@ -48,6 +50,11 @@
updatePresence();
}
+ phosphor::pmbus::PMBusBase& getPMBus()
+ {
+ return *pmbusIntf;
+ }
+
/**
* Power supply specific function to analyze for faults/errors.
*
@@ -55,9 +62,7 @@
* If a certain fault bits are on, the appropriate error will be
* committed.
*/
- void analyze()
- {
- }
+ void analyze();
/**
* Write PMBus CLEAR_FAULTS
@@ -69,6 +74,10 @@
*/
void clearFaults()
{
+ faultFound = false;
+ inputFault = false;
+ mfrFault = false;
+ vinUVFault = false;
}
/**
@@ -98,6 +107,38 @@
return present;
}
+ /**
+ * @brief Returns true if a fault was found.
+ */
+ bool isFaulted() const
+ {
+ return faultFound;
+ }
+
+ /**
+ * @brief Returns true if INPUT fault occurred.
+ */
+ bool hasInputFault() const
+ {
+ return inputFault;
+ }
+
+ /**
+ * @brief Returns true if MFRSPECIFIC occurred.
+ */
+ bool hasMFRFault() const
+ {
+ return mfrFault;
+ }
+
+ /**
+ * @brief Returns true if VIN_UV_FAULT occurred.
+ */
+ bool hasVINUVFault() const
+ {
+ return vinUVFault;
+ }
+
private:
/** @brief systemd bus member */
sdbusplus::bus::bus& bus;
@@ -105,6 +146,15 @@
/** @brief True if a fault has already been found and not cleared */
bool faultFound = false;
+ /** @brief True if bit 5 of STATUS_WORD high byte is on. */
+ bool inputFault = false;
+
+ /** @brief True if bit 4 of STATUS_WORD high byte is on. */
+ bool mfrFault = false;
+
+ /** @brief True if bit 3 of STATUS_WORD low byte is on. */
+ bool vinUVFault = false;
+
/**
* @brief D-Bus path to use for this power supply's inventory status.
**/
diff --git a/phosphor-power-supply/psu_manager.hpp b/phosphor-power-supply/psu_manager.hpp
index a4628c4..a3bcae0 100644
--- a/phosphor-power-supply/psu_manager.hpp
+++ b/phosphor-power-supply/psu_manager.hpp
@@ -111,6 +111,8 @@
{
psu->clearFaults();
}
+
+ faultLogged = false;
}
private:
@@ -135,11 +137,36 @@
{
psu->analyze();
}
+
+ for (auto& psu : psus)
+ {
+ // TODO: Fault priorities #918
+ if (!faultLogged && psu->isFaulted())
+ {
+ if (psu->hasInputFault())
+ {
+ // TODO: Create error log
+ }
+
+ if (psu->hasMFRFault())
+ {
+ // TODO: Create error log
+ }
+
+ if (psu->hasVINUVFault())
+ {
+ // TODO: Create error log
+ }
+ }
+ }
}
/** @brief True if the power is on. */
bool powerOn = false;
+ /** @brief True if fault logged. Clear in clearFaults(). */
+ bool faultLogged = false;
+
/** @brief Used as part of subscribing to power on state changes*/
std::string powerService;
diff --git a/phosphor-power-supply/test/meson.build b/phosphor-power-supply/test/meson.build
new file mode 100644
index 0000000..a71ac57
--- /dev/null
+++ b/phosphor-power-supply/test/meson.build
@@ -0,0 +1,22 @@
+test('phosphor-power-supply-tests',
+ executable('phosphor-power-supply-tests',
+ 'power_supply_tests.cpp',
+ 'mock.cpp',
+ dependencies: [
+ gmock,
+ gtest,
+ sdbusplus,
+ sdeventplus,
+ phosphor_logging,
+ ],
+ implicit_include_directories: false,
+ include_directories: [
+ '.',
+ '..',
+ '../..'
+ ],
+ link_args: dynamic_linker,
+ build_rpath: get_option('oe-sdk').enabled() ? rpath : '',
+ objects: power_supply,
+ )
+)
diff --git a/phosphor-power-supply/test/mock.cpp b/phosphor-power-supply/test/mock.cpp
new file mode 100644
index 0000000..e13db2b
--- /dev/null
+++ b/phosphor-power-supply/test/mock.cpp
@@ -0,0 +1,15 @@
+#include <mock.hpp>
+
+namespace phosphor
+{
+namespace pmbus
+{
+
+std::unique_ptr<PMBusBase> createPMBus(std::uint8_t /*bus*/,
+ const std::string& /*address*/)
+{
+ return std::make_unique<MockedPMBus>();
+}
+
+} // namespace pmbus
+} // namespace phosphor
diff --git a/phosphor-power-supply/test/mock.hpp b/phosphor-power-supply/test/mock.hpp
new file mode 100644
index 0000000..0c64e00
--- /dev/null
+++ b/phosphor-power-supply/test/mock.hpp
@@ -0,0 +1,55 @@
+#pragma once
+
+#include "pmbus.hpp"
+#include "util_base.hpp"
+
+#include <gmock/gmock.h>
+
+namespace phosphor
+{
+namespace pmbus
+{
+class MockedPMBus : public PMBusBase
+{
+
+ public:
+ virtual ~MockedPMBus() = default;
+
+ MOCK_METHOD(uint64_t, read, (const std::string& name, Type type),
+ (override));
+};
+} // namespace pmbus
+
+namespace power
+{
+namespace psu
+{
+class MockedUtil : public UtilBase
+{
+ public:
+ virtual ~MockedUtil() = default;
+
+ MOCK_METHOD(bool, getPresence,
+ (sdbusplus::bus::bus & bus, const std::string& invpath),
+ (const, override));
+};
+
+static std::unique_ptr<MockedUtil> util;
+inline const UtilBase& getUtils()
+{
+ if (!util)
+ {
+ util = std::make_unique<MockedUtil>();
+ }
+ return *util;
+}
+
+inline void freeUtils()
+{
+ util.reset();
+}
+
+} // namespace psu
+} // namespace power
+
+} // namespace phosphor
diff --git a/phosphor-power-supply/test/power_supply_tests.cpp b/phosphor-power-supply/test/power_supply_tests.cpp
new file mode 100644
index 0000000..9674153
--- /dev/null
+++ b/phosphor-power-supply/test/power_supply_tests.cpp
@@ -0,0 +1,277 @@
+#include "../power_supply.hpp"
+#include "mock.hpp"
+
+#include <xyz/openbmc_project/Common/Device/error.hpp>
+#include <xyz/openbmc_project/Common/error.hpp>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace phosphor::power::psu;
+using namespace phosphor::pmbus;
+
+using ::testing::_;
+using ::testing::Assign;
+using ::testing::DoAll;
+using ::testing::Return;
+using ::testing::StrEq;
+
+static auto PSUInventoryPath = "/xyz/bmc/inv/sys/chassis/board/powersupply0";
+
+class PowerSupplyTests : public ::testing::Test
+{
+ public:
+ PowerSupplyTests() :
+ mockedUtil(reinterpret_cast<const MockedUtil&>(getUtils()))
+ {
+ ON_CALL(mockedUtil, getPresence(_, _)).WillByDefault(Return(false));
+ }
+
+ ~PowerSupplyTests() override
+ {
+ freeUtils();
+ }
+
+ const MockedUtil& mockedUtil;
+};
+
+TEST_F(PowerSupplyTests, Constructor)
+{
+ /**
+ * @param[in] invpath - String for inventory path to use
+ * @param[in] i2cbus - The bus number this power supply is on
+ * @param[in] i2caddr - The 16-bit I2C address of the power supply
+ */
+ auto bus = sdbusplus::bus::new_default();
+ EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath))).Times(1);
+ auto psu = std::make_unique<PowerSupply>(bus, PSUInventoryPath, 3, "0068");
+
+ EXPECT_EQ(psu->isPresent(), false);
+ EXPECT_EQ(psu->isFaulted(), false);
+ EXPECT_EQ(psu->hasInputFault(), false);
+ EXPECT_EQ(psu->hasMFRFault(), false);
+ EXPECT_EQ(psu->hasVINUVFault(), false);
+}
+
+TEST_F(PowerSupplyTests, Analyze)
+{
+ auto bus = sdbusplus::bus::new_default();
+
+ EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath))).Times(1);
+ PowerSupply psu{bus, PSUInventoryPath, 4, "0069"};
+ psu.analyze();
+ // By default, nothing should change.
+ EXPECT_EQ(psu.isPresent(), false);
+ EXPECT_EQ(psu.isFaulted(), false);
+ EXPECT_EQ(psu.hasInputFault(), false);
+ EXPECT_EQ(psu.hasMFRFault(), false);
+ EXPECT_EQ(psu.hasVINUVFault(), false);
+
+ // In order to get the various faults tested, the power supply needs to be
+ // present in order to read from the PMBus device(s).
+ EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath)))
+ .Times(1)
+ .WillOnce(Return(true)); // present
+ PowerSupply psu2{bus, PSUInventoryPath, 5, "006a"};
+ EXPECT_EQ(psu2.isPresent(), true);
+
+ // STATUS_WORD 0x0000 is powered on, no faults.
+ MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu2.getPMBus());
+ EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
+ psu2.analyze();
+ EXPECT_EQ(psu2.isPresent(), true);
+ EXPECT_EQ(psu2.isFaulted(), false);
+ EXPECT_EQ(psu2.hasInputFault(), false);
+ EXPECT_EQ(psu2.hasMFRFault(), false);
+ EXPECT_EQ(psu2.hasVINUVFault(), false);
+
+ // STATUS_WORD input fault/warn
+ EXPECT_CALL(mockPMBus, read(_, _))
+ .Times(1)
+ .WillOnce(Return(status_word::INPUT_FAULT_WARN));
+ psu2.analyze();
+ EXPECT_EQ(psu2.isPresent(), true);
+ EXPECT_EQ(psu2.isFaulted(), true);
+ EXPECT_EQ(psu2.hasInputFault(), true);
+ EXPECT_EQ(psu2.hasMFRFault(), false);
+ EXPECT_EQ(psu2.hasVINUVFault(), false);
+
+ // STATUS_WORD INPUT/UV fault.
+ // First need it to return good status, then the fault
+ EXPECT_CALL(mockPMBus, read(_, _))
+ .WillOnce(Return(0x0000))
+ .WillOnce(Return(status_word::VIN_UV_FAULT));
+ psu2.analyze();
+ 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(), true);
+
+ // STATUS_WORD MFR fault.
+ EXPECT_CALL(mockPMBus, read(_, _))
+ .WillOnce(Return(0x0000))
+ .WillOnce(Return(status_word::MFR_SPECIFIC_FAULT));
+ psu2.analyze();
+ psu2.analyze();
+ EXPECT_EQ(psu2.isPresent(), true);
+ EXPECT_EQ(psu2.isFaulted(), true);
+ EXPECT_EQ(psu2.hasInputFault(), false);
+ EXPECT_EQ(psu2.hasMFRFault(), true);
+ EXPECT_EQ(psu2.hasVINUVFault(), false);
+
+ // Ignore Temperature fault.
+ EXPECT_CALL(mockPMBus, read(_, _))
+ .WillOnce(Return(0x0000))
+ .WillOnce(Return(status_word::TEMPERATURE_FAULT_WARN));
+ psu2.analyze();
+ psu2.analyze();
+ EXPECT_EQ(psu2.isPresent(), true);
+ EXPECT_EQ(psu2.isFaulted(), false);
+ EXPECT_EQ(psu2.hasInputFault(), false);
+ EXPECT_EQ(psu2.hasMFRFault(), false);
+ EXPECT_EQ(psu2.hasVINUVFault(), false);
+
+ // Ignore fan fault
+ EXPECT_CALL(mockPMBus, read(_, _))
+ .WillOnce(Return(0x0000))
+ .WillOnce(Return(status_word::FAN_FAULT));
+ psu2.analyze();
+ psu2.analyze();
+ EXPECT_EQ(psu2.isPresent(), true);
+ EXPECT_EQ(psu2.isFaulted(), false);
+ EXPECT_EQ(psu2.hasInputFault(), false);
+ EXPECT_EQ(psu2.hasMFRFault(), false);
+ EXPECT_EQ(psu2.hasVINUVFault(), false);
+
+ // TODO: ReadFailure
+}
+
+TEST_F(PowerSupplyTests, ClearFaults)
+{
+ auto bus = sdbusplus::bus::new_default();
+ EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath)))
+ .Times(1)
+ .WillOnce(Return(true)); // present
+ PowerSupply psu{bus, PSUInventoryPath, 13, "0068"};
+ EXPECT_EQ(psu.isPresent(), true);
+ EXPECT_EQ(psu.isFaulted(), false);
+ EXPECT_EQ(psu.hasInputFault(), false);
+ EXPECT_EQ(psu.hasMFRFault(), false);
+ EXPECT_EQ(psu.hasVINUVFault(), false);
+ MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
+ EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0xFFFF));
+ psu.analyze();
+ EXPECT_EQ(psu.isPresent(), true);
+ EXPECT_EQ(psu.isFaulted(), true);
+ EXPECT_EQ(psu.hasInputFault(), true);
+ EXPECT_EQ(psu.hasMFRFault(), true);
+ EXPECT_EQ(psu.hasVINUVFault(), true);
+ psu.clearFaults();
+ EXPECT_EQ(psu.isPresent(), true);
+ EXPECT_EQ(psu.isFaulted(), false);
+ EXPECT_EQ(psu.hasInputFault(), false);
+ EXPECT_EQ(psu.hasMFRFault(), false);
+ EXPECT_EQ(psu.hasVINUVFault(), false);
+}
+
+TEST_F(PowerSupplyTests, UpdateInventory)
+{
+ auto bus = sdbusplus::bus::new_default();
+ EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath)))
+ .Times(1)
+ .WillOnce(Return(true)); // present
+ PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
+ psu.updateInventory();
+ // TODO: Checks / Story #921
+}
+
+TEST_F(PowerSupplyTests, IsPresent)
+{
+ auto bus = sdbusplus::bus::new_default();
+ EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath))).Times(1);
+ PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
+ EXPECT_EQ(psu.isPresent(), false);
+
+ EXPECT_CALL(mockedUtil, getPresence(_, _))
+ .WillOnce(Return(true)); // present
+ PowerSupply psu2{bus, PSUInventoryPath, 10, "006b"};
+ EXPECT_EQ(psu2.isPresent(), true);
+}
+
+TEST_F(PowerSupplyTests, IsFaulted)
+{
+ auto bus = sdbusplus::bus::new_default();
+ EXPECT_CALL(mockedUtil, getPresence(_, _))
+ .WillOnce(Return(true)); // present
+ PowerSupply psu{bus, PSUInventoryPath, 11, "006f"};
+ EXPECT_EQ(psu.isFaulted(), false);
+ MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
+ EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0xFFFF));
+ psu.analyze();
+ EXPECT_EQ(psu.isFaulted(), true);
+}
+
+TEST_F(PowerSupplyTests, HasInputFault)
+{
+ auto bus = sdbusplus::bus::new_default();
+ EXPECT_CALL(mockedUtil, getPresence(_, _))
+ .WillOnce(Return(true)); // present
+ PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
+ MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
+ EXPECT_EQ(psu.hasInputFault(), false);
+ EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
+ psu.analyze();
+ EXPECT_EQ(psu.hasInputFault(), false);
+ EXPECT_CALL(mockPMBus, read(_, _))
+ .Times(1)
+ .WillOnce(Return(status_word::INPUT_FAULT_WARN));
+ psu.analyze();
+ EXPECT_EQ(psu.hasInputFault(), true);
+ EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
+ psu.analyze();
+ EXPECT_EQ(psu.hasInputFault(), false);
+}
+
+TEST_F(PowerSupplyTests, HasMFRFault)
+{
+ auto bus = sdbusplus::bus::new_default();
+ EXPECT_CALL(mockedUtil, getPresence(_, _))
+ .WillOnce(Return(true)); // present
+ PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
+ MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
+ EXPECT_EQ(psu.hasMFRFault(), false);
+ EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
+ psu.analyze();
+ EXPECT_EQ(psu.hasMFRFault(), false);
+ EXPECT_CALL(mockPMBus, read(_, _))
+ .Times(1)
+ .WillOnce(Return(status_word::MFR_SPECIFIC_FAULT));
+ psu.analyze();
+ EXPECT_EQ(psu.hasMFRFault(), true);
+ EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
+ psu.analyze();
+ EXPECT_EQ(psu.hasMFRFault(), false);
+}
+
+TEST_F(PowerSupplyTests, HasVINUVFault)
+{
+ auto bus = sdbusplus::bus::new_default();
+ EXPECT_CALL(mockedUtil, getPresence(_, _))
+ .WillOnce(Return(true)); // present
+ PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
+ MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
+ EXPECT_EQ(psu.hasVINUVFault(), false);
+ EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
+ psu.analyze();
+ EXPECT_EQ(psu.hasVINUVFault(), false);
+ EXPECT_CALL(mockPMBus, read(_, _))
+ .Times(1)
+ .WillOnce(Return(status_word::VIN_UV_FAULT));
+ psu.analyze();
+ EXPECT_EQ(psu.hasVINUVFault(), true);
+ EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
+ psu.analyze();
+ EXPECT_EQ(psu.hasVINUVFault(), false);
+}
diff --git a/phosphor-power-supply/util.cpp b/phosphor-power-supply/util.cpp
new file mode 100644
index 0000000..c4555ae
--- /dev/null
+++ b/phosphor-power-supply/util.cpp
@@ -0,0 +1,12 @@
+#include "util.hpp"
+
+namespace phosphor::power::psu
+{
+
+const UtilBase& getUtils()
+{
+ static Util util;
+ return util;
+}
+
+} // namespace phosphor::power::psu
diff --git a/phosphor-power-supply/util.hpp b/phosphor-power-supply/util.hpp
new file mode 100644
index 0000000..2e4afe2
--- /dev/null
+++ b/phosphor-power-supply/util.hpp
@@ -0,0 +1,26 @@
+#pragma once
+
+#include "util_base.hpp"
+#include "utility.hpp"
+
+namespace phosphor::power::psu
+{
+
+class Util : public UtilBase
+{
+ public:
+ //~Util(){};
+ bool getPresence(sdbusplus::bus::bus& bus,
+ const std::string& invpath) const override
+ {
+ bool present = false;
+
+ // Use getProperty utility function to get presence status.
+ util::getProperty(INVENTORY_IFACE, PRESENT_PROP, invpath,
+ INVENTORY_MGR_IFACE, bus, present);
+
+ return present;
+ }
+};
+
+} // namespace phosphor::power::psu
diff --git a/phosphor-power-supply/util_base.hpp b/phosphor-power-supply/util_base.hpp
new file mode 100644
index 0000000..ab1a962
--- /dev/null
+++ b/phosphor-power-supply/util_base.hpp
@@ -0,0 +1,30 @@
+#pragma once
+
+#include "types.hpp"
+
+#include <sdbusplus/bus/match.hpp>
+
+namespace phosphor::power::psu
+{
+
+/**
+ * @class UtilBase
+ * A base class to allow for mocking certain utility functions.
+ */
+class UtilBase
+{
+ public:
+ virtual ~UtilBase() = default;
+
+ virtual bool getPresence(sdbusplus::bus::bus& bus,
+ const std::string& invpath) const = 0;
+};
+
+const UtilBase& getUtils();
+
+inline bool getPresence(sdbusplus::bus::bus& bus, const std::string& invpath)
+{
+ return getUtils().getPresence(bus, invpath);
+}
+
+} // namespace phosphor::power::psu
diff --git a/pmbus.hpp b/pmbus.hpp
index 89c3118..5e252b2 100644
--- a/pmbus.hpp
+++ b/pmbus.hpp
@@ -52,6 +52,10 @@
// to see if the INPUT FAULT OR WARNING bit is on.
constexpr auto INPUT_FAULT_WARN = 0x2000;
+// The bit mask representing the MFRSPECIFIC fault, bit 4 of STATUS_WORD high
+// byte. A manufacturer specific fault or warning has occurred.
+constexpr auto MFR_SPECIFIC_FAULT = 0x1000;
+
// The bit mask representing the POWER_GOOD Negated bit of the STATUS_WORD.
constexpr auto POWER_GOOD_NEGATED = 0x0800;
@@ -118,6 +122,8 @@
{
public:
virtual ~PMBusBase() = default;
+
+ virtual uint64_t read(const std::string& name, Type type) = 0;
};
/**
@@ -233,7 +239,7 @@
*
* @return uint64_t - Up to 8 bytes of data read from file.
*/
- uint64_t read(const std::string& name, Type type);
+ uint64_t read(const std::string& name, Type type) override;
/**
* Read a string from file in sysfs.