Files

433 lines
16 KiB
Diff
Raw Permalink Normal View History

2026-04-23 17:07:55 +08:00
From 8b6def70a95ddab05ec565db1c5437ad17423d20 Mon Sep 17 00:00:00 2001
From: "Wang.Bin" <Bin-B.Wang@luxshare-ict.com>
Date: Tue, 3 Dec 2024 21:23:28 +0800
Subject: [PATCH 10/10] Fix soft-shutdown without SEL
---
src/power_control.cpp | 275 +++++++++++++++++++++++++++++++++++-------
1 file changed, 233 insertions(+), 42 deletions(-)
diff --git a/src/power_control.cpp b/src/power_control.cpp
index 2a72473..cfe6e57 100644
--- a/src/power_control.cpp
+++ b/src/power_control.cpp
@@ -94,6 +94,22 @@ static ConfigData idButtonConfig;
static ConfigData nmiButtonConfig;
static ConfigData slotPowerConfig;
+struct LogData
+{
+ bool assert;
+ uint16_t generatorID;
+ std::vector<uint8_t> selData;
+ std::string sensorPath;
+};
+
+struct LogData acpiStatusOffSensor = {true, 0x0020, {6, 255, 255}, "null"};
+struct LogData acpiStatusOnSensor = {true, 0x0020, {0, 255, 255}, "null"};
+struct LogData osBootSensor = {true, 0x0020, {6, 255, 255}, "null"};
+struct LogData sysBootPowerUpSensor = {true, 0x0020, {0, 255, 255}, "null"};
+struct LogData sysBootHardResetSensor = {true, 0x0020, {1, 255, 255}, "null"};
+struct LogData sysBootWarmResetSensor = {true, 0x0020, {2, 255, 255}, "null"};
+struct LogData powerButtonPressedSensor = {true, 0x0020, {0, 255, 255}, "null"};
+
// map for storing list of gpio parameters whose config are to be read from x86
// power control json config
boost::container::flat_map<std::string, ConfigData*> powerSignalMap = {
@@ -578,47 +594,48 @@ static void powerStateLog(const PowerState state)
constexpr const char* selPath = "/xyz/openbmc_project/Logging/IPMI";
constexpr const char* selInterface = "xyz.openbmc_project.Logging.IPMI";
constexpr const char* selMethod = "IpmiSelAdd";
- std::string sensorPath =
- "/xyz/openbmc_project/inventory/system/board/Lux_Baseboard/ACPI_State";
+ struct LogData powerStatusSensor;
auto bus = sdbusplus::bus::new_default();
- std::string stateStr = std::string(getChassisState(state));
+
auto method =
bus.new_method_call(selService, selPath, selInterface, selMethod);
- method.append("SEL Entry");
-
- if (stateStr == "xyz.openbmc_project.State.Chassis.PowerState.On")
- {
- std::cerr << "Send Power State On SEL Log\n";
- method.append(sensorPath.c_str());
- method.append(
- std::array<uint8_t, 3>({0x00, 0xFF, 0xFF})); // S0/G0: working
- }
- else if (stateStr == "xyz.openbmc_project.State.Chassis.PowerState.Off")
- {
- std::cerr << "Send Power State Off SEL Log\n";
- method.append(sensorPath.c_str());
- method.append(
- std::array<uint8_t, 3>({0x06, 0xFF, 0xFF})); // S4/S5: soft-off
- }
- else if (stateStr == "ButtonPressed")
- {
- std::cerr << "Send Power State Button Pressed SEL Log\n";
- sensorPath = "/xyz/openbmc_project/inventory/system/board/Lux_Baseboard/Power_Button";
- method.append(sensorPath.c_str());
- method.append(
- std::array<uint8_t, 3>({0x00, 0xFF, 0xFF})); // power button pressed
- }
- else
+ switch (state)
{
- std::cerr << "Send Power State SEL Log Error\n";
- return;
+ case PowerState::on:
+ std::cout << "PowerState:: on" << std::endl;
+ powerStatusSensor = acpiStatusOnSensor;
+ break;
+ // both off and cycleOff will call acpiStatusOffSensor
+ case PowerState::off:
+ case PowerState::cycleOff:
+ std::cout << "PowerState:: off" << std::endl;
+ powerStatusSensor = acpiStatusOffSensor;
+ break;
+ case PowerState::transitionToCycleOff:
+ powerStatusSensor = sysBootHardResetSensor;
+ break;
+ case PowerState::waitForPSPowerOK:
+ powerStatusSensor = sysBootPowerUpSensor;
+ break;
+ case PowerState::checkForWarmReset:
+ powerStatusSensor = sysBootWarmResetSensor;
+ break;
+ case PowerState::powerButtonPressed:
+ powerStatusSensor = powerButtonPressedSensor;
+ break;
+ default:
+ break;
}
- method.append(true); // assert is true and deassert is false
- method.append(uint16_t(0x0020)); // generator ID
+ method.append("SEL Entry");
+ method.append(powerStatusSensor.sensorPath);
+ method.append(powerStatusSensor.selData);
+ method.append(
+ powerStatusSensor.assert); // assert is true and deassert is false
+ method.append(powerStatusSensor.generatorID); // generator ID
try
{
bus.call_noreply(method);
@@ -851,6 +868,7 @@ static void powerButtonPressLog()
// sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i",
// LOG_INFO, "REDFISH_MESSAGE_ID=%s",
// "OpenBMC.0.1.PowerButtonPressed", NULL);
+ std::cout << "power button pressed" << __LINE__ << std::endl;
powerStateLog(PowerState::powerButtonPressed);
}
@@ -1829,9 +1847,10 @@ static void currentHostStateMonitor()
pohCounterTimerStart();
// Clear the restart cause set for the next restart
clearRestartCause();
- sd_journal_send("MESSAGE=Host system DC power is on", "PRIORITY=%i",
- LOG_INFO, "REDFISH_MESSAGE_ID=%s",
- "OpenBMC.0.1.DCPowerOn", NULL);
+ std::cout << "Host system DC power is on" << __LINE__ << std::endl;
+ //sd_journal_send("MESSAGE=Host system DC power is on", "PRIORITY=%i",
+ // LOG_INFO, "REDFISH_MESSAGE_ID=%s",
+ // "OpenBMC.0.1.DCPowerOn", NULL);
}
else
{
@@ -1848,9 +1867,10 @@ static void currentHostStateMonitor()
#ifdef USE_ACBOOT
resetACBootProperty();
#endif // USE_ACBOOT
- sd_journal_send("MESSAGE=Host system DC power is off",
- "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
- "OpenBMC.0.1.DCPowerOff", NULL);
+ std::cout << "Host system DC power is off" << __LINE__ << std::endl;
+ //sd_journal_send("MESSAGE=Host system DC power is off",
+ // "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
+ // "OpenBMC.0.1.DCPowerOff", NULL);
}
});
}
@@ -1966,6 +1986,7 @@ static void powerStateWaitForPSPowerOK(const Event event)
else
{
setPowerState(PowerState::on);
+ std::cout << "powerStateWaitForPSPowerOK" << __LINE__ << std::endl;
powerStateLog(PowerState::on);
}
break;
@@ -2018,7 +2039,6 @@ static void powerStateOff(const Event event)
else
{
setPowerState(PowerState::on);
- powerStateLog(PowerState::on);
}
break;
}
@@ -2053,6 +2073,7 @@ static void powerStateTransitionToOff(const Event event)
// Cancel any GPIO assertions held during the transition
gpioAssertTimer.cancel();
setPowerState(PowerState::off);
+ std::cout << "powerStateTransitionToOff" << __LINE__ << std::endl;
powerStateLog(PowerState::off);
break;
default:
@@ -2069,6 +2090,8 @@ static void powerStateGracefulTransitionToOff(const Event event)
case Event::psPowerOKDeAssert:
gracefulPowerOffTimer.cancel();
setPowerState(PowerState::off);
+ std::cout << "powerStateGracefulTransitionToOff power off" << __LINE__ << std::endl;
+ powerStateLog(PowerState::off);
break;
case Event::gracefulPowerOffTimerExpired:
setPowerState(PowerState::on);
@@ -2110,6 +2133,7 @@ static void powerStateCycleOff(const Event event)
else
{
setPowerState(PowerState::on);
+ std::cout << "powerStateCycleOff:power on" << __LINE__ << std::endl;
}
break;
}
@@ -2143,6 +2167,7 @@ static void powerStateTransitionToCycleOff(const Event event)
// Cancel any GPIO assertions held during the transition
gpioAssertTimer.cancel();
setPowerState(PowerState::cycleOff);
+ std::cout << "powerStateTransitionToCycleOff power off" << __LINE__ << std::endl;
powerStateLog(PowerState::cycleOff);
powerCycleTimerStart();
break;
@@ -2160,6 +2185,8 @@ static void powerStateGracefulTransitionToCycleOff(const Event event)
case Event::psPowerOKDeAssert:
gracefulPowerOffTimer.cancel();
setPowerState(PowerState::cycleOff);
+ std::cout << "powerStateGracefulTransitionToCycleOff power off" << __LINE__ << std::endl;
+ powerStateLog(PowerState::cycleOff);
powerCycleTimerStart();
break;
case Event::gracefulPowerOffTimerExpired:
@@ -2201,6 +2228,8 @@ static void powerStateCheckForWarmReset(const Event event)
case Event::psPowerOKDeAssert:
warmResetCheckTimer.cancel();
setPowerState(PowerState::off);
+ std::cout << "powerStateCheckForWarmReset power off" << __LINE__ << std::endl;
+ powerStateLog(PowerState::cycleOff);
// DC power is unexpectedly lost, beep
beep(beepPowerFail);
break;
@@ -2496,12 +2525,43 @@ static void pltRstHandler(bool pltRst)
}
}
+static void postCompleteLog()
+{
+ constexpr const char* selService = "xyz.openbmc_project.Logging.IPMI";
+ constexpr const char* selPath = "/xyz/openbmc_project/Logging/IPMI";
+ constexpr const char* selInterface = "xyz.openbmc_project.Logging.IPMI";
+ constexpr const char* selMethod = "IpmiSelAdd";
+
+ auto bus = sdbusplus::bus::new_default();
+
+ auto method =
+ bus.new_method_call(selService, selPath, selInterface, selMethod);
+
+ method.append("SEL Entry");
+ method.append(osBootSensor.sensorPath);
+ method.append(osBootSensor.selData);
+ method.append(osBootSensor.assert); // assert is true and deassert is false
+ method.append(osBootSensor.generatorID); // generator ID
+ try
+ {
+ bus.call_noreply(method);
+ }
+ catch (const sdbusplus::exception::SdBusError& ex)
+ {
+ lg2::error(
+ "Failed to call sel log {SELPATH}, {SELINTERFACE}, {SELMRTHOD}",
+ "SELPATH", selPath, "SELINTERFACE", selInterface, "SELMRTHOD",
+ selMethod);
+ }
+}
+
static void postCompleteHandler(bool state)
{
if (!state)
{
sendPowerControlEvent(Event::postCompleteAssert);
setOperatingSystemState(OperatingSystemStateStage::Inactive);
+ //postCompleteLog();
}
else
{
@@ -2510,6 +2570,107 @@ static void postCompleteHandler(bool state)
}
}
+std::optional<std::string> getDiscretePrefixFromFile()
+{
+ constexpr auto boardNameFile = "/usr/share/boardname/boardname.conf";
+ constexpr auto boardPrefix = "/xyz/openbmc_project/inventory/system/board/";
+
+ std::ifstream file(boardNameFile);
+ if (!file.is_open())
+ {
+ lg2::error("Fail to open {FILE}", "FILE", boardNameFile);
+ return std::nullopt;
+ }
+
+ std::string boardName{};
+ std::getline(file, boardName);
+ if (boardName.empty())
+ {
+ lg2::error("Fail to read {FILE}", "FILE", boardNameFile);
+ return std::nullopt;
+ }
+ lg2::info("Board name is {BOARD}", "BOARD", boardName);
+ return boardPrefix + boardName;
+}
+
+std::optional<std::vector<std::string>>
+ getSubTreePaths(sdbusplus::bus::bus& bus, const std::string& objectPath,
+ const std::string& interface)
+{
+ constexpr auto mapperBusname = "xyz.openbmc_project.ObjectMapper";
+ constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
+ constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
+ std::vector<std::string> paths;
+
+ auto method = bus.new_method_call(mapperBusname, mapperObjPath, mapperIface,
+ "GetSubTreePaths");
+ method.append(objectPath.c_str());
+ method.append(0); // Depth 0 to search all
+ method.append(std::vector<std::string>({interface.c_str()}));
+
+ try
+ {
+ auto reply = bus.call(method);
+ reply.read(paths);
+ return paths;
+ }
+ catch (const sdbusplus::exception::SdBusError& e)
+ {
+ lg2::error("Fail to get chassis path");
+ return std::nullopt;
+ }
+
+ return std::nullopt;
+}
+
+std::optional<std::string> getDiscreteSensorPath(const std::string& sensorName)
+{
+ static std::string discreteSensorPathPrefix{};
+ if (discreteSensorPathPrefix.empty())
+ {
+ // First try to get the path from the file
+ auto prefix = getDiscretePrefixFromFile();
+ if (prefix)
+ {
+ discreteSensorPathPrefix = *prefix;
+ }
+ else
+ {
+ // If the file doesn't exist, get the path from the dbus
+ constexpr auto discreteSensorUpperPath =
+ "/xyz/openbmc_project/inventory";
+ constexpr auto discreteSensorInterface =
+ "xyz.openbmc_project.Configuration.Status";
+ auto bus = sdbusplus::bus::new_default();
+ auto sensorPaths = getSubTreePaths(bus, discreteSensorUpperPath,
+ discreteSensorInterface);
+ // if call fail or empty, return nullopt
+ if (!sensorPaths || sensorPaths.value().size() == 0)
+ {
+ return std::nullopt;
+ }
+ // if any sensor path is find, get the prefix of the path
+ // because all discrete sensor path in the inventory has the same
+ // prefix
+ for (const auto& sensorPath : sensorPaths.value())
+ {
+ discreteSensorPathPrefix =
+ sensorPath.substr(0, sensorPath.find_last_of('/'));
+ break;
+ }
+ if (discreteSensorPathPrefix.empty())
+ {
+ return std::nullopt;
+ }
+ }
+ }
+
+ std::string path = discreteSensorPathPrefix;
+ path.append("/");
+ path.append(sensorName);
+ return path;
+}
+
static int loadConfigValues()
{
const std::string configFilePath =
@@ -2661,6 +2822,33 @@ static int loadConfigValues()
nmiWhenPoweredOff = events.value("NMIWhenPoweredOff", true);
}
+ auto acpiSensorPath = getDiscreteSensorPath("ACPI_State");
+ if (acpiSensorPath != std::nullopt)
+ {
+ acpiStatusOnSensor.sensorPath = acpiSensorPath.value();
+ acpiStatusOffSensor.sensorPath = acpiSensorPath.value();
+ }
+
+ auto sysbootSensorPath = getDiscreteSensorPath("SYS_Boot");
+ if (sysbootSensorPath != std::nullopt)
+ {
+ sysBootPowerUpSensor.sensorPath = sysbootSensorPath.value();
+ sysBootHardResetSensor.sensorPath = sysbootSensorPath.value();
+ sysBootWarmResetSensor.sensorPath = sysbootSensorPath.value();
+ }
+
+ auto osbootSensorPath = getDiscreteSensorPath("OS_Boot");
+ if (osbootSensorPath != std::nullopt)
+ {
+ osBootSensor.sensorPath = osbootSensorPath.value();
+ }
+
+ auto powerbuttonSensorPath = getDiscreteSensorPath("Power_Button");
+ if (powerbuttonSensorPath != std::nullopt)
+ {
+ powerButtonPressedSensor.sensorPath = powerbuttonSensorPath.value();
+ }
+
return 0;
}
@@ -2840,7 +3028,7 @@ void reschedulePropertyRead(const ConfigData& configData)
}
});
}
-
+bool bmcReset = true;
static void ACPIStateSel(void)
{
const static constexpr int TimeMs = 20000;
@@ -2856,8 +3044,11 @@ static void ACPIStateSel(void)
ec.message());
}
}
- lg2::info("ACPI State sel");
- powerStateLog(powerState);
+ std::cout << "BMC reboot:power state" << __LINE__ << std::endl;
+ if (bmcReset == true){
+ powerStateLog(powerState);
+ }
+ bmcReset = false;
});
}
--
2.25.1