From baa0c019b4c6eb1759cf55e7858badca4758c143 Mon Sep 17 00:00:00 2001 From: "Prakash, Prashanth" Date: Thu, 23 Jun 2016 12:24:26 -0600 Subject: ACPI / bus: Support for platform initiated graceful shutdown This patch adds support for platform initited graceful shutdown as described in sections 5.6.6(Table-143) and 6.3.5.1 of ACPI 6.1 spec The OSPM will get a graceful shutdown request via a Notify operator on \_SB device with a value of 0x81 per section 5.6.6. Following the shutdown request from platform the OSPM needs to follow the processing sequence as described in section 6.2.5.1. v3 * Switched to regular work with delays from delayed work * Dropped changes to actypes.h * Small style changes v2 * Switched from standalone driver to a simple notify handler v1 * Initial Cc: "Rafael J. Wysocki" Signed-off-by: Prashanth Prakash Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'drivers/acpi/bus.c') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 9342f4b46a4e..64a3fb0bf188 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -30,6 +30,9 @@ #include #include #include +#include +#include +#include #ifdef CONFIG_X86 #include #endif @@ -470,6 +473,56 @@ static void acpi_device_remove_notify_handler(struct acpi_device *device) acpi_device_notify); } +/* Handle events targeting \_SB device (at present only graceful shutdown) */ + +#define ACPI_SB_NOTIFY_SHUTDOWN_REQUEST 0x81 +#define ACPI_SB_INDICATE_INTERVAL 10000 + +static void sb_notify_work(struct work_struct *dummy) +{ + acpi_handle sb_handle; + + orderly_poweroff(true); + + /* + * After initiating graceful shutdown, the ACPI spec requires OSPM + * to evaluate _OST method once every 10seconds to indicate that + * the shutdown is in progress + */ + acpi_get_handle(NULL, "\\_SB", &sb_handle); + while (1) { + pr_info("Graceful shutdown in progress.\n"); + acpi_evaluate_ost(sb_handle, ACPI_OST_EC_OSPM_SHUTDOWN, + ACPI_OST_SC_OS_SHUTDOWN_IN_PROGRESS, NULL); + msleep(ACPI_SB_INDICATE_INTERVAL); + } +} + +static void acpi_sb_notify(acpi_handle handle, u32 event, void *data) +{ + static DECLARE_WORK(acpi_sb_work, sb_notify_work); + + if (event == ACPI_SB_NOTIFY_SHUTDOWN_REQUEST) { + if (!work_busy(&acpi_sb_work)) + schedule_work(&acpi_sb_work); + } else + pr_warn("event %x is not supported by \\_SB device\n", event); +} + +static int __init acpi_setup_sb_notify_handler(void) +{ + acpi_handle sb_handle; + + if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &sb_handle))) + return -ENXIO; + + if (ACPI_FAILURE(acpi_install_notify_handler(sb_handle, ACPI_DEVICE_NOTIFY, + acpi_sb_notify, NULL))) + return -EINVAL; + + return 0; +} + /* -------------------------------------------------------------------------- Device Matching -------------------------------------------------------------------------- */ @@ -1118,6 +1171,7 @@ static int __init acpi_init(void) acpi_sleep_proc_init(); acpi_wakeup_device_init(); acpi_debugger_init(); + acpi_setup_sb_notify_handler(); return 0; } -- cgit v1.2.3-59-g8ed1b