diff --git a/[refs] b/[refs] index 5e905150bebe..8e63df20daf2 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: aad83b143008e1d406248803550bfbfc600b6398 +refs/heads/master: 23fe36306ea489eef7dd88506bdcefdc8da39c91 diff --git a/trunk/arch/ia64/include/asm/acpi.h b/trunk/arch/ia64/include/asm/acpi.h index a06dfb13d518..837dc82a013e 100644 --- a/trunk/arch/ia64/include/asm/acpi.h +++ b/trunk/arch/ia64/include/asm/acpi.h @@ -128,9 +128,9 @@ static inline const char *acpi_get_sysname (void) int acpi_request_vector (u32 int_type); int acpi_gsi_to_irq (u32 gsi, unsigned int *irq); -/* Low-level suspend routine. */ -extern int acpi_suspend_lowlevel(void); - +/* routines for saving/restoring kernel state */ +extern int acpi_save_state_mem(void); +extern void acpi_restore_state_mem(void); extern unsigned long acpi_wakeup_address; /* diff --git a/trunk/arch/ia64/kernel/acpi.c b/trunk/arch/ia64/kernel/acpi.c index a54d054ed4b0..90ebceb899a0 100644 --- a/trunk/arch/ia64/kernel/acpi.c +++ b/trunk/arch/ia64/kernel/acpi.c @@ -1034,8 +1034,18 @@ int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base) EXPORT_SYMBOL(acpi_unregister_ioapic); /* - * acpi_suspend_lowlevel() - save kernel state and suspend. + * acpi_save_state_mem() - save kernel state * * TBD when when IA64 starts to support suspend... */ -int acpi_suspend_lowlevel(void) { return 0; } +int acpi_save_state_mem(void) { return 0; } + +/* + * acpi_restore_state() + */ +void acpi_restore_state_mem(void) {} + +/* + * do_suspend_lowlevel() + */ +void do_suspend_lowlevel(void) {} diff --git a/trunk/arch/x86/include/asm/acpi.h b/trunk/arch/x86/include/asm/acpi.h index aa92684aa674..211ca3f7fd16 100644 --- a/trunk/arch/x86/include/asm/acpi.h +++ b/trunk/arch/x86/include/asm/acpi.h @@ -112,8 +112,9 @@ static inline void acpi_disable_pci(void) acpi_noirq_set(); } -/* Low-level suspend routine. */ -extern int acpi_suspend_lowlevel(void); +/* routines for saving/restoring kernel state */ +extern int acpi_save_state_mem(void); +extern void acpi_restore_state_mem(void); extern unsigned long acpi_wakeup_address; diff --git a/trunk/arch/x86/kernel/acpi/sleep.c b/trunk/arch/x86/kernel/acpi/sleep.c index 5f1b747f6ef1..68d1537b8c81 100644 --- a/trunk/arch/x86/kernel/acpi/sleep.c +++ b/trunk/arch/x86/kernel/acpi/sleep.c @@ -29,14 +29,14 @@ static char temp_stack[4096]; #endif /** - * acpi_suspend_lowlevel - save kernel state + * acpi_save_state_mem - save kernel state * * Create an identity mapped page table and copy the wakeup routine to * low memory. * * Note that this is too late to change acpi_wakeup_address. */ -int acpi_suspend_lowlevel(void) +int acpi_save_state_mem(void) { struct wakeup_header *header; @@ -107,10 +107,17 @@ int acpi_suspend_lowlevel(void) saved_magic = 0x123456789abcdef0L; #endif /* CONFIG_64BIT */ - do_suspend_lowlevel(); return 0; } +/* + * acpi_restore_state - undo effects of acpi_save_state_mem + */ +void acpi_restore_state_mem(void) +{ +} + + /** * acpi_reserve_wakeup_memory - do _very_ early ACPI initialisation * diff --git a/trunk/arch/x86/kernel/acpi/sleep.h b/trunk/arch/x86/kernel/acpi/sleep.h index 31ce13f20297..adbcbaa6f1df 100644 --- a/trunk/arch/x86/kernel/acpi/sleep.h +++ b/trunk/arch/x86/kernel/acpi/sleep.h @@ -14,5 +14,3 @@ extern char swsusp_pg_dir[PAGE_SIZE]; extern unsigned long acpi_copy_wakeup_routine(unsigned long); extern void wakeup_long64(void); - -extern void do_suspend_lowlevel(void); diff --git a/trunk/drivers/acpi/button.c b/trunk/drivers/acpi/button.c index 12c28f4adb67..76bbb78a5ad9 100644 --- a/trunk/drivers/acpi/button.c +++ b/trunk/drivers/acpi/button.c @@ -98,7 +98,6 @@ struct acpi_button { struct input_dev *input; char phys[32]; /* for input device */ unsigned long pushed; - bool wakeup_enabled; }; static const struct file_operations acpi_button_info_fops = { @@ -431,10 +430,8 @@ static int acpi_button_add(struct acpi_device *device) /* Button's GPE is run-wake GPE */ acpi_enable_gpe(device->wakeup.gpe_device, device->wakeup.gpe_number); - if (!device_may_wakeup(&device->dev)) { - device_set_wakeup_enable(&device->dev, true); - button->wakeup_enabled = true; - } + device->wakeup.run_wake_count++; + device_set_wakeup_enable(&device->dev, true); } printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device)); @@ -456,8 +453,8 @@ static int acpi_button_remove(struct acpi_device *device, int type) if (device->wakeup.flags.valid) { acpi_disable_gpe(device->wakeup.gpe_device, device->wakeup.gpe_number); - if (button->wakeup_enabled) - device_set_wakeup_enable(&device->dev, false); + device->wakeup.run_wake_count--; + device_set_wakeup_enable(&device->dev, false); } acpi_button_remove_fs(device); diff --git a/trunk/drivers/acpi/osl.c b/trunk/drivers/acpi/osl.c index c90c76aa7f8b..187dff96356b 100644 --- a/trunk/drivers/acpi/osl.c +++ b/trunk/drivers/acpi/osl.c @@ -76,7 +76,6 @@ EXPORT_SYMBOL(acpi_in_debugger); extern char line_buf[80]; #endif /*ENABLE_DEBUGGER */ -static unsigned int acpi_irq_irq; static acpi_osd_handler acpi_irq_handler; static void *acpi_irq_context; static struct workqueue_struct *kacpid_wq; @@ -516,11 +515,15 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, acpi_irq_stats_init(); /* - * Ignore the GSI from the core, and use the value in our copy of the - * FADT. It may not be the same if an interrupt source override exists - * for the SCI. + * ACPI interrupts different from the SCI in our copy of the FADT are + * not supported. */ - gsi = acpi_gbl_FADT.sci_interrupt; + if (gsi != acpi_gbl_FADT.sci_interrupt) + return AE_BAD_PARAMETER; + + if (acpi_irq_handler) + return AE_ALREADY_ACQUIRED; + if (acpi_gsi_to_irq(gsi, &irq) < 0) { printk(KERN_ERR PREFIX "SCI (ACPI GSI %d) not registered\n", gsi); @@ -531,20 +534,20 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, acpi_irq_context = context; if (request_irq(irq, acpi_irq, IRQF_SHARED, "acpi", acpi_irq)) { printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq); + acpi_irq_handler = NULL; return AE_NOT_ACQUIRED; } - acpi_irq_irq = irq; return AE_OK; } acpi_status acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler) { - if (irq) { - free_irq(irq, acpi_irq); - acpi_irq_handler = NULL; - acpi_irq_irq = 0; - } + if (irq != acpi_gbl_FADT.sci_interrupt) + return AE_BAD_PARAMETER; + + free_irq(irq, acpi_irq); + acpi_irq_handler = NULL; return AE_OK; } @@ -1603,7 +1606,7 @@ acpi_status __init acpi_os_initialize1(void) acpi_status acpi_os_terminate(void) { if (acpi_irq_handler) { - acpi_os_remove_interrupt_handler(acpi_irq_irq, + acpi_os_remove_interrupt_handler(acpi_gbl_FADT.sci_interrupt, acpi_irq_handler); } diff --git a/trunk/drivers/acpi/scan.c b/trunk/drivers/acpi/scan.c index b136c9c1e531..b99e62494607 100644 --- a/trunk/drivers/acpi/scan.c +++ b/trunk/drivers/acpi/scan.c @@ -797,6 +797,7 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device) acpi_status status; acpi_event_status event_status; + device->wakeup.run_wake_count = 0; device->wakeup.flags.notifier_present = 0; /* Power button, Lid switch always enable wakeup */ diff --git a/trunk/drivers/acpi/sleep.c b/trunk/drivers/acpi/sleep.c index 84f57143ad7c..d6a8cd14de2e 100644 --- a/trunk/drivers/acpi/sleep.c +++ b/trunk/drivers/acpi/sleep.c @@ -199,6 +199,8 @@ static void acpi_pm_end(void) #endif /* CONFIG_ACPI_SLEEP */ #ifdef CONFIG_SUSPEND +extern void do_suspend_lowlevel(void); + static u32 acpi_suspend_states[] = { [PM_SUSPEND_ON] = ACPI_STATE_S0, [PM_SUSPEND_STANDBY] = ACPI_STATE_S1, @@ -241,11 +243,20 @@ static int acpi_suspend_begin(suspend_state_t pm_state) static int acpi_suspend_enter(suspend_state_t pm_state) { acpi_status status = AE_OK; + unsigned long flags = 0; u32 acpi_state = acpi_target_sleep_state; - int error; ACPI_FLUSH_CPU_CACHE(); + /* Do arch specific saving of state. */ + if (acpi_state == ACPI_STATE_S3) { + int error = acpi_save_state_mem(); + + if (error) + return error; + } + + local_irq_save(flags); switch (acpi_state) { case ACPI_STATE_S1: barrier(); @@ -253,10 +264,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state) break; case ACPI_STATE_S3: - error = acpi_suspend_lowlevel(); - if (error) - return error; - pr_info(PREFIX "Low-level resume complete\n"); + do_suspend_lowlevel(); break; } @@ -282,6 +290,13 @@ static int acpi_suspend_enter(suspend_state_t pm_state) /* Allow EC transactions to happen. */ acpi_ec_unblock_transactions_early(); + local_irq_restore(flags); + printk(KERN_DEBUG "Back to C!\n"); + + /* restore processor state */ + if (acpi_state == ACPI_STATE_S3) + acpi_restore_state_mem(); + suspend_nvs_restore(); return ACPI_SUCCESS(status) ? 0 : -EFAULT; @@ -457,13 +472,16 @@ static int acpi_hibernation_begin(void) static int acpi_hibernation_enter(void) { acpi_status status = AE_OK; + unsigned long flags = 0; ACPI_FLUSH_CPU_CACHE(); + local_irq_save(flags); /* This shouldn't return. If it returns, we have a problem */ status = acpi_enter_sleep_state(ACPI_STATE_S4); /* Reprogram control registers and execute _BFS */ acpi_leave_sleep_state_prep(ACPI_STATE_S4); + local_irq_restore(flags); return ACPI_SUCCESS(status) ? 0 : -EFAULT; } diff --git a/trunk/drivers/pci/pci-acpi.c b/trunk/drivers/pci/pci-acpi.c index 7c3b18e78cee..6fe0772e0e7d 100644 --- a/trunk/drivers/pci/pci-acpi.c +++ b/trunk/drivers/pci/pci-acpi.c @@ -293,11 +293,19 @@ static int acpi_dev_run_wake(struct device *phys_dev, bool enable) } if (enable) { - acpi_enable_wakeup_device_power(dev, ACPI_STATE_S0); - acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number); + if (!dev->wakeup.run_wake_count++) { + acpi_enable_wakeup_device_power(dev, ACPI_STATE_S0); + acpi_enable_gpe(dev->wakeup.gpe_device, + dev->wakeup.gpe_number); + } + } else if (dev->wakeup.run_wake_count > 0) { + if (!--dev->wakeup.run_wake_count) { + acpi_disable_gpe(dev->wakeup.gpe_device, + dev->wakeup.gpe_number); + acpi_disable_wakeup_device_power(dev); + } } else { - acpi_disable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number); - acpi_disable_wakeup_device_power(dev); + error = -EALREADY; } return error; diff --git a/trunk/include/acpi/acpi_bus.h b/trunk/include/acpi/acpi_bus.h index f50ebb9bc53b..78ca429929f7 100644 --- a/trunk/include/acpi/acpi_bus.h +++ b/trunk/include/acpi/acpi_bus.h @@ -250,6 +250,7 @@ struct acpi_device_wakeup { struct acpi_handle_list resources; struct acpi_device_wakeup_flags flags; int prepare_count; + int run_wake_count; }; /* Device */