From: Neil Horman <nhorman@redhat.com> Date: Fri, 12 Sep 2008 16:35:36 -0400 Subject: [acpi] correctly allow WoL from S4 state Message-id: 20080912203536.GO29710@hmsendeavour.rdu.redhat.com O-Subject: Re: [RHEL5.3 PATCH] acpi: correctly allow WoL from S4 state Bugzilla: 445890 This patch is a combination of these two upstream patches: commit 9b039330808b83acac3597535da26f47ad1862ce Author: Alexey Starikovskiy <astarikovskiy@suse.de> Date: Wed Sep 26 19:47:30 2007 +0400 ACPI: Hibernate erroneously disabled Suspend wakeup devices and commit 9c1c6a1ba786d58bd03e27ee49f89a5685e8e07b Author: Alexey Starikovskiy <astarikovskiy@suse.de> Date: Mon Oct 22 14:18:06 2007 +0400 ACPI: sleep: Fix GPE suspend cleanup It was tested and now allows WoL to work from the S4 state on e1000e (this was previously not possible). Most of the leg work was done by Anders Karlsson on this one, so he deserves the credit. This will resolve bug 445890. This is the new patch. I've not tested it extensively, but I've booted it and excercized it on ia64 in rhts for most of the day, and it seems to work reasonably well. Its exactly the same as the old patch, but the call to acpi_enable_wakeup_device is only made if CONFIG_ACPI_SLEEP is configured. Neil diff --git a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c index 47fb4b3..3e00e40 100644 --- a/drivers/acpi/sleep/poweroff.c +++ b/drivers/acpi/sleep/poweroff.c @@ -33,7 +33,6 @@ int acpi_sleep_prepare(u32 acpi_state) ACPI_FLUSH_CPU_CACHE(); acpi_enable_wakeup_device_prep(acpi_state); #endif - acpi_gpe_sleep_prepare(acpi_state); acpi_enter_sleep_state_prep(acpi_state); return 0; } @@ -46,6 +45,9 @@ void acpi_power_off(void) printk("%s called\n", __FUNCTION__); local_irq_disable(); /* Some SMP machines only can poweroff in boot CPU */ +#ifdef CONFIG_ACPI_SLEEP + acpi_enable_wakeup_device(ACPI_STATE_S5); +#endif acpi_enter_sleep_state(ACPI_STATE_S5); } diff --git a/drivers/acpi/sleep/sleep.h b/drivers/acpi/sleep/sleep.h index f3e7039..cfaf8f5 100644 --- a/drivers/acpi/sleep/sleep.h +++ b/drivers/acpi/sleep/sleep.h @@ -5,4 +5,3 @@ extern int acpi_suspend (u32 state); extern void acpi_enable_wakeup_device_prep(u8 sleep_state); extern void acpi_enable_wakeup_device(u8 sleep_state); extern void acpi_disable_wakeup_device(u8 sleep_state); -extern void acpi_gpe_sleep_prepare(u32 sleep_state); diff --git a/drivers/acpi/sleep/wakeup.c b/drivers/acpi/sleep/wakeup.c index af1dbab..d9741b8 100644 --- a/drivers/acpi/sleep/wakeup.c +++ b/drivers/acpi/sleep/wakeup.c @@ -65,36 +65,29 @@ void acpi_enable_wakeup_device(u8 sleep_state) ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device"); spin_lock(&acpi_device_lock); list_for_each_safe(node, next, &acpi_wakeup_device_list) { - struct acpi_device *dev = container_of(node, - struct acpi_device, - wakeup_list); - + struct acpi_device *dev = + container_of(node, struct acpi_device, wakeup_list); + if (!dev->wakeup.flags.valid) + continue; /* If users want to disable run-wake GPE, * we only disable it for wake and leave it for runtime */ - if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) { - spin_unlock(&acpi_device_lock); - acpi_set_gpe_type(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, - ACPI_GPE_TYPE_RUNTIME); - /* Re-enable it, since set_gpe_type will disable it */ - acpi_enable_gpe(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, ACPI_ISR); - spin_lock(&acpi_device_lock); + if (!dev->wakeup.state.enabled || + sleep_state > (u32) dev->wakeup.sleep_state) { + if (dev->wakeup.flags.run_wake) { + spin_unlock(&acpi_device_lock); + /* set_gpe_type will disable GPE, leave it like that */ + acpi_set_gpe_type(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, + ACPI_GPE_TYPE_RUNTIME); + spin_lock(&acpi_device_lock); + } continue; } - - if (!dev->wakeup.flags.valid || - !dev->wakeup.state.enabled || - (sleep_state > (u32) dev->wakeup.sleep_state)) - continue; - spin_unlock(&acpi_device_lock); - /* run-wake GPE has been enabled */ if (!dev->wakeup.flags.run_wake) acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number, ACPI_ISR); - dev->wakeup.state.active = 1; spin_lock(&acpi_device_lock); } spin_unlock(&acpi_device_lock); @@ -113,26 +106,25 @@ void acpi_disable_wakeup_device(u8 sleep_state) spin_lock(&acpi_device_lock); list_for_each_safe(node, next, &acpi_wakeup_device_list) { - struct acpi_device *dev = container_of(node, - struct acpi_device, - wakeup_list); + struct acpi_device *dev = + container_of(node, struct acpi_device, wakeup_list); - if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) { - spin_unlock(&acpi_device_lock); - acpi_set_gpe_type(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, - ACPI_GPE_TYPE_WAKE_RUN); - /* Re-enable it, since set_gpe_type will disable it */ - acpi_enable_gpe(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, ACPI_NOT_ISR); - spin_lock(&acpi_device_lock); + if (!dev->wakeup.flags.valid) continue; - } - - if (!dev->wakeup.flags.valid || - !dev->wakeup.state.active || - (sleep_state > (u32) dev->wakeup.sleep_state)) + if (!dev->wakeup.state.enabled || + sleep_state > (u32) dev->wakeup.sleep_state) { + if (dev->wakeup.flags.run_wake) { + spin_unlock(&acpi_device_lock); + acpi_set_gpe_type(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, + ACPI_GPE_TYPE_WAKE_RUN); + /* Re-enable it, since set_gpe_type will disable it */ + acpi_enable_gpe(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_NOT_ISR); + spin_lock(&acpi_device_lock); + } continue; + } spin_unlock(&acpi_device_lock); acpi_disable_wakeup_device_power(dev); @@ -143,7 +135,6 @@ void acpi_disable_wakeup_device(u8 sleep_state) acpi_clear_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number, ACPI_NOT_ISR); } - dev->wakeup.state.active = 0; spin_lock(&acpi_device_lock); } spin_unlock(&acpi_device_lock); @@ -161,49 +152,21 @@ static int __init acpi_wakeup_device_init(void) struct acpi_device *dev = container_of(node, struct acpi_device, wakeup_list); - /* In case user doesn't load button driver */ - if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) { - spin_unlock(&acpi_device_lock); - acpi_set_gpe_type(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, - ACPI_GPE_TYPE_WAKE_RUN); - acpi_enable_gpe(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, ACPI_NOT_ISR); - dev->wakeup.state.enabled = 1; - spin_lock(&acpi_device_lock); - } + if (!dev->wakeup.flags.run_wake || dev->wakeup.state.enabled) + continue; + spin_unlock(&acpi_device_lock); + acpi_set_gpe_type(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, + ACPI_GPE_TYPE_WAKE_RUN); + acpi_enable_gpe(dev->wakeup.gpe_device, + dev->wakeup.gpe_number, ACPI_NOT_ISR); + dev->wakeup.state.enabled = 1; + spin_lock(&acpi_device_lock); } spin_unlock(&acpi_device_lock); - return 0; } late_initcall(acpi_wakeup_device_init); #endif - -/* - * Disable all wakeup GPEs before power off. - * - * Since acpi_enter_sleep_state() will disable all - * RUNTIME GPEs, we simply mark all GPES that - * are not enabled for wakeup from S5 as RUNTIME. - */ -void acpi_gpe_sleep_prepare(u32 sleep_state) -{ - struct list_head *node, *next; - - list_for_each_safe(node, next, &acpi_wakeup_device_list) { - struct acpi_device *dev = container_of(node, - struct acpi_device, - wakeup_list); - - /* The GPE can wakeup system from this state, don't touch it */ - if ((u32) dev->wakeup.sleep_state >= sleep_state) - continue; - /* acpi_set_gpe_type will automatically disable GPE */ - acpi_set_gpe_type(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, - ACPI_GPE_TYPE_RUNTIME); - } -} diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index f338e40..385d8a0 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -265,7 +265,6 @@ struct acpi_device_wakeup_flags { struct acpi_device_wakeup_state { u8 enabled:1; - u8 active:1; }; struct acpi_device_wakeup {