blob: 46560a79f7db90e14c1e8f8f189fba7acab28f6b [file] [log] [blame]
#pragma once
#include "power_supply.hpp"
#include "types.hpp"
#include "utility.hpp"
#include <phosphor-logging/log.hpp>
#include <sdbusplus/bus/match.hpp>
#include <sdbusplus/server/manager.hpp>
#include <sdbusplus/server/object.hpp>
#include <sdeventplus/event.hpp>
#include <sdeventplus/utility/timer.hpp>
#include <xyz/openbmc_project/State/Decorator/PowerSystemInputs/server.hpp>
struct sys_properties
{
int powerSupplyCount;
std::vector<uint64_t> inputVoltage;
bool powerConfigFullLoad;
};
using namespace phosphor::power::psu;
using namespace phosphor::logging;
namespace phosphor::power::manager
{
using PowerSystemInputsInterface = sdbusplus::xyz::openbmc_project::State::
Decorator::server::PowerSystemInputs;
using PowerSystemInputsObject =
sdbusplus::server::object_t<PowerSystemInputsInterface>;
// Validation timeout. Allow 10s to detect if new EM interfaces show up in D-Bus
// before performing the validation.
constexpr auto validationTimeout = std::chrono::seconds(10);
/**
* @class PowerSystemInputs
* @brief A concrete implementation for the PowerSystemInputs interface.
*/
class PowerSystemInputs : public PowerSystemInputsObject
{
public:
PowerSystemInputs(sdbusplus::bus::bus& bus, const std::string& path) :
PowerSystemInputsObject(bus, path.c_str())
{}
};
/**
* @class PSUManager
*
* This class will create an object used to manage and monitor a list of power
* supply devices.
*/
class PSUManager
{
public:
PSUManager() = delete;
~PSUManager() = default;
PSUManager(const PSUManager&) = delete;
PSUManager& operator=(const PSUManager&) = delete;
PSUManager(PSUManager&&) = delete;
PSUManager& operator=(PSUManager&&) = delete;
/**
* Constructor to read configuration from D-Bus.
*
* @param[in] bus - D-Bus bus object
* @param[in] e - event object
*/
PSUManager(sdbusplus::bus::bus& bus, const sdeventplus::Event& e);
/**
* Get PSU properties from D-Bus, use that to build a power supply
* object.
*
* @param[in] properties - A map of property names and values
*
*/
void getPSUProperties(util::DbusPropertyMap& properties);
/**
* Get PSU configuration from D-Bus
*/
void getPSUConfiguration();
/**
* @brief Initialize the system properties from the Supported Configuration
* D-Bus object provided by Entity Manager.
*/
void getSystemProperties();
/**
* Initializes the manager.
*
* Get current BMC state, ...
*/
void initialize()
{
// When state = 1, system is powered on
int32_t state = 0;
try
{
// Use getProperty utility function to get power state.
util::getProperty<int32_t>(POWER_IFACE, "state", POWER_OBJ_PATH,
powerService, bus, state);
if (state)
{
powerOn = true;
validationTimer->restartOnce(validationTimeout);
}
else
{
powerOn = false;
runValidateConfig = true;
}
}
catch (const std::exception& e)
{
log<level::INFO>("Failed to get power state. Assuming it is off.");
powerOn = false;
runValidateConfig = true;
}
onOffConfig(phosphor::pmbus::ON_OFF_CONFIG_CONTROL_PIN_ONLY);
clearFaults();
updateInventory();
setPowerConfigGPIO();
}
/**
* Starts the timer to start monitoring the list of devices.
*/
int run()
{
return timer->get_event().loop();
}
/**
* Write PMBus ON_OFF_CONFIG
*
* This function will be called to cause the PMBus device driver to send the
* ON_OFF_CONFIG command. Takes one byte of data.
*/
void onOffConfig(const uint8_t data)
{
for (auto& psu : psus)
{
psu->onOffConfig(data);
}
}
/**
* This function will be called in various situations in order to clear
* any fault status bits that may have been set, in order to start over
* with a clean state. Presence changes and power state changes will want
* to clear any faults logged.
*/
void clearFaults()
{
setPowerSupplyError("");
for (auto& psu : psus)
{
psu->clearFaults();
}
}
private:
/**
* The D-Bus object
*/
sdbusplus::bus::bus& bus;
/**
* The timer that runs to periodically check the power supplies.
*/
std::unique_ptr<
sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
timer;
/**
* The timer that performs power supply validation as the entity manager
* interfaces show up in d-bus.
*/
std::unique_ptr<
sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
validationTimer;
/**
* Let power control/sequencer application know of PSU error(s).
*
* @param[in] psuErrorString - string for power supply error
*/
void setPowerSupplyError(const std::string& psuErrorString);
/**
* Create an error
*
* @param[in] faultName - 'name' message for the BMC error log entry
* @param[in,out] additionalData - The AdditionalData property for the error
*/
void createError(const std::string& faultName,
std::map<std::string, std::string>& additionalData);
/**
* Analyze the status of each of the power supplies.
*
* Log errors for faults, when and where appropriate.
*/
void analyze();
/** @brief True if the power is on. */
bool powerOn = false;
/** @brief True if an error for a brownout has already been logged. */
bool brownoutLogged = false;
/** @brief Used as part of subscribing to power on state changes*/
std::string powerService;
/** @brief Used to subscribe to D-Bus power on state changes */
std::unique_ptr<sdbusplus::bus::match_t> powerOnMatch;
/** @brief Used to subscribe to D-Bus power supply presence changes */
std::vector<std::unique_ptr<sdbusplus::bus::match_t>> presenceMatches;
/** @brief Used to subscribe to Entity Manager interfaces added */
std::unique_ptr<sdbusplus::bus::match_t> entityManagerIfacesAddedMatch;
/**
* @brief Callback for power state property changes
*
* Process changes to the powered on state property for the system.
*
* @param[in] msg - Data associated with the power state signal
*/
void powerStateChanged(sdbusplus::message::message& msg);
/**
* @brief Callback for inventory property changes
*
* Process change of the Present property for power supply.
*
* @param[in] msg - Data associated with the Present change signal
**/
void presenceChanged(sdbusplus::message::message& msg);
/**
* @brief Callback for entity-manager interface added
*
* Process the information from the supported configuration and or IBM CFFPS
* Connector interface being added.
*
* @param[in] msg - Data associated with the interfaces added signal
*/
void entityManagerIfaceAdded(sdbusplus::message::message& msg);
/**
* @brief Adds properties to the inventory.
*
* Reads the values from the devices and writes them to the associated
* power supply D-Bus inventory objects.
*
* This needs to be done on startup, and each time the presence state
* changes.
*/
void updateInventory()
{
for (auto& psu : psus)
{
psu->updateInventory();
}
}
/**
* @brief Helper function to populate the system properties
*
* @param[in] properties - A map of property names and values
*/
void populateSysProperties(const util::DbusPropertyMap& properties);
/**
* @brief Perform power supply configuration validation.
* @details Validates if the existing power supply properties are a
* supported configuration, and acts on its findings such as logging errors.
*/
void validateConfig();
/**
* @brief Flag to indicate if the validateConfig() function should be run.
* Set to false once the configuration has been validated to avoid running
* multiple times due to interfaces added signal. Set to true during power
* off to trigger the validation on power on.
*/
bool runValidateConfig = true;
/**
* @brief Check that all PSUs have the same model name and that the system
* has the required number of PSUs present as specified in the Supported
* Configuration interface.
*
* @param[out] additionalData - Contains debug information on why the check
* might have failed. Can be used to fill in error logs.
* @return true if all the required PSUs are present, false otherwise.
*/
bool hasRequiredPSUs(std::map<std::string, std::string>& additionalData);
/**
* @brief Helper function to validate that all PSUs have the same model name
*
* @param[out] model - The model name. Empty if there is a mismatch.
* @param[out] additionalData - If there is a mismatch, it contains debug
* information such as the mismatched model name.
* @return true if all the PSUs have the same model name, false otherwise.
*/
bool validateModelName(std::string& model,
std::map<std::string, std::string>& additionalData);
/**
* @brief Set the power-config-full-load GPIO depending on the EM full load
* property value.
*/
void setPowerConfigGPIO();
/**
* @brief Indicate that the system is in a brownout condition by creating an
* error log and setting the PowerSystemInputs status property to Fault.
*
* @param[in] additionalData - Contains debug information on the number of
* PSUs in fault state or not present.
*/
void setBrownout(std::map<std::string, std::string>& additionalData);
/**
* @brief Indicate that the system is no longer in a brownout condition by
* setting the PowerSystemInputs status property to Good.
*/
void clearBrownout();
/**
* @brief Map of supported PSU configurations that include the model name
* and their properties.
*/
std::map<std::string, sys_properties> supportedConfigs;
/**
* @brief The vector for power supplies.
*/
std::vector<std::unique_ptr<PowerSupply>> psus;
/**
* @brief The libgpiod object for setting the power supply config
*/
std::unique_ptr<GPIOInterfaceBase> powerConfigGPIO = nullptr;
/**
* @brief PowerSystemInputs object
*/
PowerSystemInputs powerSystemInputs;
/**
* @brief Implement the ObjectManager for PowerSystemInputs object.
*
* Implements the org.freedesktop.DBus.ObjectManager interface used to
* communicate updates to the PowerSystemInputs object on the
* /xyz/openbmc_project/power/power_supplies root D-Bus path.
*/
sdbusplus::server::manager_t objectManager;
/**
* @brief Implement the ObjectManager for power supply input history.
*
* Implements the org.freedesktop.DBus.ObjectManager interface used to
* communicate updates to the Average and Maximum interface properties on
* the /org/open_power/sensors root D-Bus path.
*/
sdbusplus::server::manager_t historyManager;
/**
* @brief GPIO to toggle to 'sync' power supply input history.
*/
std::unique_ptr<GPIOInterfaceBase> syncHistoryGPIO = nullptr;
/**
* @brief Toggles the GPIO to sync power supply input history readings
*
* This GPIO is connected to all supplies. This will clear the
* previous readings out of the supplies and restart them both at the
* same time zero and at record ID 0. The supplies will return 0
* bytes of data for the input history command right after this until
* a new entry shows up.
*
* This will cause the code to delete all previous history data and
* start fresh.
*/
void syncHistory();
};
} // namespace phosphor::power::manager