blob: 8c80ef3ec826fee3419ee9e43827b429bd55c438 [file] [log] [blame]
#include "power_supply.hpp"
#include "types.hpp"
#include "util.hpp"
#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
{
present = getPresence(bus, inventoryPath);
}
catch (const sdbusplus::exception::SdBusError& e)
{
// Relying on property change or interface added to retry.
// Log an informational trace to the journal.
log<level::INFO>("D-Bus property access failure exception");
}
}
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::onOffConfig(uint8_t data)
{
using namespace phosphor::pmbus;
if (present)
{
log<level::INFO>("ON_OFF_CONFIG write", entry("DATA=0x%02X", data));
try
{
std::vector<uint8_t> configData{data};
pmbusIntf->writeBinary(ON_OFF_CONFIG, configData,
Type::HwmonDeviceDebug);
}
catch (...)
{
// The underlying code in writeBinary will log a message to the
// journal if the write fails. If the ON_OFF_CONFIG is not setup as
// desired, later fault detection and analysis code should catch any
// of the fall out. We should not need to terminate the application
// if this write fails.
}
}
}
void PowerSupply::clearFaults()
{
faultFound = false;
inputFault = false;
mfrFault = false;
vinUVFault = false;
// The PMBus device driver does not allow for writing CLEAR_FAULTS
// directly. However, the pmbus hwmon device driver code will send a
// CLEAR_FAULTS after reading from any of the hwmon "files" in sysfs, so
// reading in1_input should result in clearing the fault bits in
// STATUS_BYTE/STATUS_WORD.
// I do not care what the return value is.
try
{
static_cast<void>(
pmbusIntf->read("in1_input", phosphor::pmbus::Type::Hwmon));
}
catch (ReadFailure& e)
{
// Since I do not care what the return value is, I really do not
// care much if it gets a ReadFailure either. However, this should not
// prevent the application from continuing to run, so catching the read
// failure.
}
}
void PowerSupply::inventoryChanged(sdbusplus::message::message& msg)
{
std::string msgSensor;
std::map<std::string, std::variant<uint32_t, bool>> msgData;
msg.read(msgSensor, msgData);
// Check if it was the Present property that changed.
auto valPropMap = msgData.find(PRESENT_PROP);
if (valPropMap != msgData.end())
{
if (std::get<bool>(valPropMap->second))
{
present = true;
onOffConfig(phosphor::pmbus::ON_OFF_CONFIG_CONTROL_PIN_ONLY);
clearFaults();
}
else
{
present = false;
// Clear out the now outdated inventory properties
updateInventory();
}
}
}
} // namespace phosphor::power::psu