From 328853327bf138bd4c9938ac14ca09e3b6224549 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 18 Aug 2003 23:08:28 -0700 Subject: [PATCH] [acpi] Convert sleep code to new PM infrastructure. - Define and fill acpi_pm_ops, and register it on startup with the PM core. - Fill methods with only ACPI-specific code, leaving device power down, etc up to the PM core. --- drivers/acpi/sleep/main.c | 281 +++++++++----------------------------- 1 file changed, 66 insertions(+), 215 deletions(-) diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index ba72942753548..712413a7dc5a9 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c @@ -16,274 +16,124 @@ #include #include "sleep.h" -#define _COMPONENT ACPI_SYSTEM_COMPONENT -ACPI_MODULE_NAME ("sleep") - u8 sleep_states[ACPI_S_STATE_COUNT]; extern void do_suspend_lowlevel_s4bios(int); extern void do_suspend_lowlevel(int); -/** - * acpi_system_restore_state - OS-specific restoration of state - * @state: sleep state we're exiting - * - * Note that if we're coming back from S4, the memory image should have already - * been loaded from the disk and is already in place. (Otherwise how else would we - * be here?). - */ -acpi_status -acpi_system_restore_state ( - u32 state) -{ - /* restore processor state - * We should only be here if we're coming back from STR or STD. - * And, in the case of the latter, the memory image should have already - * been loaded from disk. - */ - if (state > ACPI_STATE_S1) - acpi_restore_state_mem(); - - /* wait for power to come back */ - mdelay(10); - - /* turn all the devices back on */ - device_resume(RESUME_POWER_ON); - - /* enable interrupts once again */ - ACPI_ENABLE_IRQS(); - - /* restore device context */ - device_resume(RESUME_RESTORE_STATE); - - if (dmi_broken & BROKEN_INIT_AFTER_S1) { - printk("Broken toshiba laptop -> kicking interrupts\n"); - init_8259A(0); - } - - return AE_OK; -} +static u32 acpi_suspend_states[] = { + [PM_SUSPEND_ON] = ACPI_STATE_S0, + [PM_SUSPEND_STANDBY] = ACPI_STATE_S1, + [PM_SUSPEND_MEM] = ACPI_STATE_S3, + [PM_SUSPEND_DISK] = ACPI_STATE_S4, +}; /** - * acpi_system_save_state - save OS specific state and power down devices - * @state: sleep state we're entering. + * acpi_pm_prepare - Do preliminary suspend work. + * @state: suspend state we're entering. * - * This handles saving all context to memory, and possibly disk. - * First, we call to the device driver layer to save device state. - * Once we have that, we save whatevery processor and kernel state we - * need to memory. */ -acpi_status -acpi_system_save_state( - u32 state) -{ - int error = 0; - - /* Send notification to devices that they will be suspended. - * If any device or driver cannot make the transition, either up - * or down, we'll get an error back. - */ - error = device_suspend(state, SUSPEND_NOTIFY); - if (error) - return AE_ERROR; - - if (state < ACPI_STATE_S5) { - /* Tell devices to stop I/O and actually save their state. - * It is theoretically possible that something could fail, - * so handle that gracefully.. - */ - error = device_suspend(state, SUSPEND_SAVE_STATE); - if (error) { - /* tell devices to restore state if they have - * it saved and to start taking I/O requests. - */ - device_resume(RESUME_RESTORE_STATE); - return error; - } - - /* flush caches */ - ACPI_FLUSH_CPU_CACHE(); - - /* Do arch specific saving of state. */ - if (state > ACPI_STATE_S1) { - error = acpi_save_state_mem(); +static int acpi_pm_prepare(u32 state) +{ + int error = 0; + u32 acpi_state = acpi_suspend_states[state]; - if (!error && (state == ACPI_STATE_S4)) - error = acpi_save_state_disk(); + if (!sleep_states[acpi_state]) + return -EPERM; - if (error) { - device_resume(RESUME_RESTORE_STATE); - return error; - } - } + /* do we have a wakeup address for S2 and S3? */ + /* Here, we support only S4BIOS, those we set the wakeup address */ + /* S4OS is only supported for now via swsusp.. */ + if (state == PM_SUSPEND_MEM || state == PM_SUSPEND_DISK) { + if (!acpi_wakeup_address) + return -EFAULT; + acpi_set_firmware_waking_vector( + (acpi_physical_address) acpi_wakeup_address); } - /* disable interrupts - * Note that acpi_suspend -- our caller -- will do this once we return. - * But, we want it done early, so we don't get any suprises during - * the device suspend sequence. - */ - ACPI_DISABLE_IRQS(); + ACPI_FLUSH_CPU_CACHE(); - /* Unconditionally turn off devices. - * Obvious if we enter a sleep state. - * If entering S5 (soft off), this should put devices in a - * quiescent state. - */ - error = device_suspend(state, SUSPEND_POWER_DOWN); + /* Do arch specific saving of state. */ + if (state > PM_SUSPEND_STANDBY) { + if ((error = acpi_save_state_mem())) + goto Err; + } - /* We're pretty screwed if we got an error from this. - * We try to recover by simply calling our own restore_state - * function; see above for definition. - * - * If it's S5 though, go through with it anyway.. - */ - if (error && state != ACPI_STATE_S5) - acpi_system_restore_state(state); + acpi_enter_sleep_state_prep(acpi_state); - return error ? AE_ERROR : AE_OK; + return 0; + Err: + acpi_set_firmware_waking_vector(0); + return error; } -/**************************************************************************** - * - * FUNCTION: acpi_system_suspend - * - * PARAMETERS: %state: Sleep state to enter. - * - * RETURN: acpi_status, whether or not we successfully entered and - * exited sleep. - * - * DESCRIPTION: Perform OS-specific action to enter sleep state. - * This is the final step in going to sleep, per spec. If we - * know we're coming back (i.e. not entering S5), we save the - * processor flags. [ We'll have to save and restore them anyway, - * so we use the arch-agnostic save_flags and restore_flags - * here.] We then set the place to return to in arch-specific - * globals using arch_set_return_point. Finally, we call the - * ACPI function to write the proper values to I/O ports. - * - ****************************************************************************/ - -acpi_status -acpi_system_suspend( - u32 state) +static int acpi_pm_enter(u32 state) { - acpi_status status = AE_ERROR; - unsigned long flags = 0; + acpi_status status = AE_OK; + unsigned long flags = 0; + ACPI_FLUSH_CPU_CACHE(); local_irq_save(flags); - switch (state) { - case ACPI_STATE_S1: + case PM_SUSPEND_STANDBY: barrier(); - status = acpi_enter_sleep_state(state); + status = acpi_enter_sleep_state(acpi_suspend_states[state]); break; - case ACPI_STATE_S2: - case ACPI_STATE_S3: + case PM_SUSPEND_MEM: do_suspend_lowlevel(0); break; - case ACPI_STATE_S4: + case PM_SUSPEND_DISK: do_suspend_lowlevel_s4bios(0); break; default: - printk(KERN_WARNING PREFIX "don't know how to handle %d state.\n", state); - break; + return -EINVAL; } local_irq_restore(flags); printk(KERN_DEBUG "Back to C!\n"); - return status; + return ACPI_SUCCESS(status) ? 0 : -EFAULT; } - -/** - * acpi_suspend - OS-agnostic system suspend/resume support (S? states) - * @state: state we're entering - * - */ -acpi_status -acpi_suspend ( - u32 state) +static int acpi_pm_finish(u32 state) { - acpi_status status; - - /* Suspend is hard to get right on SMP. */ - if (num_online_cpus() != 1) - return AE_ERROR; - - /* get out if state is invalid */ - if (state < ACPI_STATE_S1 || state > ACPI_STATE_S5) - return AE_ERROR; - - /* Since we handle S4OS via a different path (swsusp), give up if no s4bios. */ - if (state == ACPI_STATE_S4 && !acpi_gbl_FACS->S4bios_f) - return AE_ERROR; - - pm_prepare_console(); - - /* - * TBD: S1 can be done without device_suspend. Make a CONFIG_XX - * to handle however when S1 failed without device_suspend. - */ - if (freeze_processes()) { - status = AE_ERROR; - goto Done; - } - - /* do we have a wakeup address for S2 and S3? */ - /* Here, we support only S4BIOS, those we set the wakeup address */ - /* S4OS is only supported for now via swsusp.. */ - if (state == ACPI_STATE_S2 || state == ACPI_STATE_S3 || state == ACPI_STATE_S4) { - if (!acpi_wakeup_address) - return AE_ERROR; - acpi_set_firmware_waking_vector((acpi_physical_address) acpi_wakeup_address); - } - - status = acpi_system_save_state(state); - if (!ACPI_SUCCESS(status)) - return status; - - acpi_enter_sleep_state_prep(state); - - /* disable interrupts and flush caches */ - ACPI_DISABLE_IRQS(); - ACPI_FLUSH_CPU_CACHE(); - - /* perform OS-specific sleep actions */ - status = acpi_system_suspend(state); - - /* Even if we failed to go to sleep, all of the devices are in an suspended - * mode. So, we run these unconditionaly to make sure we have a usable system - * no matter what. - */ acpi_leave_sleep_state(state); - acpi_system_restore_state(state); - /* make sure interrupts are enabled */ - ACPI_ENABLE_IRQS(); + /* restore processor state + * We should only be here if we're coming back from STR or STD. + * And, in the case of the latter, the memory image should have already + * been loaded from disk. + */ + if (state > ACPI_STATE_S1) + acpi_restore_state_mem(); /* reset firmware waking vector */ acpi_set_firmware_waking_vector((acpi_physical_address) 0); - Done: - thaw_processes(); - pm_restore_console(); - return status; + if (dmi_broken & BROKEN_INIT_AFTER_S1) { + printk("Broken toshiba laptop -> kicking interrupts\n"); + init_8259A(0); + } + return 0; } + +static struct pm_ops acpi_pm_ops = { + .prepare = acpi_pm_prepare, + .enter = acpi_pm_enter, + .finish = acpi_pm_finish, +}; + static int __init acpi_sleep_init(void) { int i = 0; - ACPI_FUNCTION_TRACE("acpi_system_add_fs"); - if (acpi_disabled) - return_VALUE(0); + return 0; printk(KERN_INFO PREFIX "(supports"); for (i=0; i