diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-08-27 03:28:38 +0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-08-27 03:28:38 +0400 |
commit | 4b319f290d3b9c756228a66f72095d0039ec1b50 (patch) | |
tree | 2cda8d4ac3d1f2d9732a2b16feb15b14f91c83f7 | |
parent | 0ad4c9a9848fdd46dc422160efd947489a98bbc1 (diff) | |
parent | 01c6a6afd50f07dfd66b2891fd194c4b789fca48 (diff) | |
download | linux-4b319f290d3b9c756228a66f72095d0039ec1b50.tar.xz |
Merge branch 'acpi-sleep'
* acpi-sleep:
x86 / tboot / ACPI: Fail extended mode reduced hardware sleep
xen / ACPI: notify xen when reduced hardware sleep is available
ACPI / sleep: Introduce acpi_os_prepare_extended_sleep() for extended sleep path
-rw-r--r-- | arch/x86/kernel/tboot.c | 10 | ||||
-rw-r--r-- | drivers/acpi/acpica/hwesleep.c | 9 | ||||
-rw-r--r-- | drivers/acpi/osl.c | 24 | ||||
-rw-r--r-- | drivers/xen/acpi.c | 41 | ||||
-rw-r--r-- | include/linux/acpi.h | 7 | ||||
-rw-r--r-- | include/xen/acpi.h | 8 | ||||
-rw-r--r-- | include/xen/interface/platform.h | 7 |
7 files changed, 88 insertions, 18 deletions
diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c index addf7b58f4e8..91a4496db434 100644 --- a/arch/x86/kernel/tboot.c +++ b/arch/x86/kernel/tboot.c @@ -301,6 +301,15 @@ static int tboot_sleep(u8 sleep_state, u32 pm1a_control, u32 pm1b_control) return 0; } +static int tboot_extended_sleep(u8 sleep_state, u32 val_a, u32 val_b) +{ + if (!tboot_enabled()) + return 0; + + pr_warning("tboot is not able to suspend on platforms with reduced hardware sleep (ACPIv5)"); + return -ENODEV; +} + static atomic_t ap_wfs_count; static int tboot_wait_for_aps(int num_aps) @@ -422,6 +431,7 @@ static __init int tboot_late_init(void) #endif acpi_os_set_prepare_sleep(&tboot_sleep); + acpi_os_set_prepare_extended_sleep(&tboot_extended_sleep); return 0; } diff --git a/drivers/acpi/acpica/hwesleep.c b/drivers/acpi/acpica/hwesleep.c index 5e5f76230f5e..414076818d40 100644 --- a/drivers/acpi/acpica/hwesleep.c +++ b/drivers/acpi/acpica/hwesleep.c @@ -43,6 +43,7 @@ */ #include <acpi/acpi.h> +#include <linux/acpi.h> #include "accommon.h" #define _COMPONENT ACPI_HARDWARE @@ -128,6 +129,14 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state) ACPI_FLUSH_CPU_CACHE(); + status = acpi_os_prepare_extended_sleep(sleep_state, + acpi_gbl_sleep_type_a, + acpi_gbl_sleep_type_b); + if (ACPI_SKIP(status)) + return_ACPI_STATUS(AE_OK); + if (ACPI_FAILURE(status)) + return_ACPI_STATUS(status); + /* * Set the SLP_TYP and SLP_EN bits. * diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 6ab2c3505520..a934950ff7a0 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -79,6 +79,8 @@ extern char line_buf[80]; static int (*__acpi_os_prepare_sleep)(u8 sleep_state, u32 pm1a_ctrl, u32 pm1b_ctrl); +static int (*__acpi_os_prepare_extended_sleep)(u8 sleep_state, u32 val_a, + u32 val_b); static acpi_osd_handler acpi_irq_handler; static void *acpi_irq_context; @@ -1779,6 +1781,28 @@ void acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state, __acpi_os_prepare_sleep = func; } +acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a, + u32 val_b) +{ + int rc = 0; + if (__acpi_os_prepare_extended_sleep) + rc = __acpi_os_prepare_extended_sleep(sleep_state, + val_a, val_b); + if (rc < 0) + return AE_ERROR; + else if (rc > 0) + return AE_CTRL_SKIP; + + return AE_OK; +} + +void acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state, + u32 val_a, u32 val_b)) +{ + __acpi_os_prepare_extended_sleep = func; +} + + void alloc_acpi_hp_work(acpi_handle handle, u32 type, void *context, void (*func)(struct work_struct *work)) { diff --git a/drivers/xen/acpi.c b/drivers/xen/acpi.c index 119d42a2bf57..90307c0b630c 100644 --- a/drivers/xen/acpi.c +++ b/drivers/xen/acpi.c @@ -35,28 +35,43 @@ #include <asm/xen/hypercall.h> #include <asm/xen/hypervisor.h> -int xen_acpi_notify_hypervisor_state(u8 sleep_state, - u32 pm1a_cnt, u32 pm1b_cnt) +static int xen_acpi_notify_hypervisor_state(u8 sleep_state, + u32 val_a, u32 val_b, + bool extended) { + unsigned int bits = extended ? 8 : 16; + struct xen_platform_op op = { .cmd = XENPF_enter_acpi_sleep, .interface_version = XENPF_INTERFACE_VERSION, - .u = { - .enter_acpi_sleep = { - .pm1a_cnt_val = (u16)pm1a_cnt, - .pm1b_cnt_val = (u16)pm1b_cnt, - .sleep_state = sleep_state, - }, + .u.enter_acpi_sleep = { + .val_a = (u16)val_a, + .val_b = (u16)val_b, + .sleep_state = sleep_state, + .flags = extended ? XENPF_ACPI_SLEEP_EXTENDED : 0, }, }; - if ((pm1a_cnt & 0xffff0000) || (pm1b_cnt & 0xffff0000)) { - WARN(1, "Using more than 16bits of PM1A/B 0x%x/0x%x!" - "Email xen-devel@lists.xensource.com Thank you.\n", \ - pm1a_cnt, pm1b_cnt); + if (WARN((val_a & (~0 << bits)) || (val_b & (~0 << bits)), + "Using more than %u bits of sleep control values %#x/%#x!" + "Email xen-devel@lists.xen.org - Thank you.\n", \ + bits, val_a, val_b)) return -1; - } HYPERVISOR_dom0_op(&op); return 1; } + +int xen_acpi_notify_hypervisor_sleep(u8 sleep_state, + u32 pm1a_cnt, u32 pm1b_cnt) +{ + return xen_acpi_notify_hypervisor_state(sleep_state, pm1a_cnt, + pm1b_cnt, false); +} + +int xen_acpi_notify_hypervisor_extended_sleep(u8 sleep_state, + u32 val_a, u32 val_b) +{ + return xen_acpi_notify_hypervisor_state(sleep_state, val_a, + val_b, true); +} diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 353ba256f368..a5db4aeefa36 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -481,6 +481,13 @@ void acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state, acpi_status acpi_os_prepare_sleep(u8 sleep_state, u32 pm1a_control, u32 pm1b_control); + +void acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state, + u32 val_a, u32 val_b)); + +acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, + u32 val_a, u32 val_b); + #ifdef CONFIG_X86 void arch_reserve_mem_area(acpi_physical_address addr, size_t size); #else diff --git a/include/xen/acpi.h b/include/xen/acpi.h index 46aa3d1c1654..4ddd7dc4a61e 100644 --- a/include/xen/acpi.h +++ b/include/xen/acpi.h @@ -75,8 +75,10 @@ static inline int xen_acpi_get_pxm(acpi_handle h) return -ENXIO; } -int xen_acpi_notify_hypervisor_state(u8 sleep_state, +int xen_acpi_notify_hypervisor_sleep(u8 sleep_state, u32 pm1a_cnt, u32 pm1b_cnd); +int xen_acpi_notify_hypervisor_extended_sleep(u8 sleep_state, + u32 val_a, u32 val_b); static inline int xen_acpi_suspend_lowlevel(void) { @@ -93,7 +95,9 @@ static inline void xen_acpi_sleep_register(void) { if (xen_initial_domain()) { acpi_os_set_prepare_sleep( - &xen_acpi_notify_hypervisor_state); + &xen_acpi_notify_hypervisor_sleep); + acpi_os_set_prepare_extended_sleep( + &xen_acpi_notify_hypervisor_extended_sleep); acpi_suspend_lowlevel = xen_acpi_suspend_lowlevel; } diff --git a/include/xen/interface/platform.h b/include/xen/interface/platform.h index c57d5f67f702..f1331e3e7271 100644 --- a/include/xen/interface/platform.h +++ b/include/xen/interface/platform.h @@ -152,10 +152,11 @@ DEFINE_GUEST_HANDLE_STRUCT(xenpf_firmware_info_t); #define XENPF_enter_acpi_sleep 51 struct xenpf_enter_acpi_sleep { /* IN variables */ - uint16_t pm1a_cnt_val; /* PM1a control value. */ - uint16_t pm1b_cnt_val; /* PM1b control value. */ + uint16_t val_a; /* PM1a control / sleep type A. */ + uint16_t val_b; /* PM1b control / sleep type B. */ uint32_t sleep_state; /* Which state to enter (Sn). */ - uint32_t flags; /* Must be zero. */ +#define XENPF_ACPI_SLEEP_EXTENDED 0x00000001 + uint32_t flags; /* XENPF_ACPI_SLEEP_*. */ }; DEFINE_GUEST_HANDLE_STRUCT(xenpf_enter_acpi_sleep_t); |