/** * acpi_suspend_enter - Actually enter a sleep state. * @pm_state: ignored * * Flush caches and go to sleep. For STR we have to call arch-specific * assembly, which in turn call acpi_enter_sleep_state(). * It's unfortunate, but it works. Please fix if you're feeling frisky. */ 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; 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); acpi_enable_wakeup_device(acpi_state); switch (acpi_state) { case ACPI_STATE_S1: barrier(); status = acpi_enter_sleep_state(acpi_state); break; case ACPI_STATE_S3: do_suspend_lowlevel(); break; } /* Reprogram control registers and execute _BFS */ acpi_leave_sleep_state_prep(acpi_state); /* ACPI 3.0 specs (P62) says that it's the responsibility * of the OSPM to clear the status bit [ implying that the * POWER_BUTTON event should not reach userspace ] */ if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3)) acpi_clear_event(ACPI_EVENT_POWER_BUTTON); /* * Disable and clear GPE status before interrupt is enabled. Some GPEs * (like wakeup GPE) haven't handler, this can avoid such GPE misfire. * acpi_leave_sleep_state will reenable specific GPEs later */ acpi_hw_disable_all_gpes(); local_irq_restore(flags); printk(KERN_DEBUG "Back to C!\n"); /* restore processor state */ if (acpi_state == ACPI_STATE_S3) acpi_restore_state_mem(); return ACPI_SUCCESS(status) ? 0 : -EFAULT; }
static int acpi_pm_enter(suspend_state_t pm_state) { acpi_status status = AE_OK; unsigned long flags = 0; u32 acpi_state = acpi_suspend_states[pm_state]; ACPI_FLUSH_CPU_CACHE(); /* Do arch specific saving of state. */ if (pm_state > PM_SUSPEND_STANDBY) { int error = acpi_save_state_mem(); if (error) return error; } local_irq_save(flags); acpi_enable_wakeup_device(acpi_state); switch (pm_state) { case PM_SUSPEND_STANDBY: barrier(); status = acpi_enter_sleep_state(acpi_state); break; case PM_SUSPEND_MEM: do_suspend_lowlevel(); break; case PM_SUSPEND_DISK: if (acpi_pm_ops.pm_disk_mode == PM_DISK_PLATFORM) status = acpi_enter_sleep_state(acpi_state); else do_suspend_lowlevel_s4bios(); break; case PM_SUSPEND_MAX: acpi_power_off(); break; default: return -EINVAL; } local_irq_restore(flags); printk(KERN_DEBUG "Back to C!\n"); /* 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 (pm_state > PM_SUSPEND_STANDBY) acpi_restore_state_mem(); return ACPI_SUCCESS(status) ? 0 : -EFAULT; }
/** * acpi_system_save_state - save OS specific state and power down devices * @state: sleep 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. * If we're entering S4, we then write the memory image to disk. * * Only then it is safe for us to power down devices, since we may need * the disks and upstream buses to write to. */ 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. */ if (state > ACPI_STATE_S1) { error = pm_send_all(PM_SAVE_STATE, (void *)3); 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.. */ if (state > ACPI_STATE_S1 && state != ACPI_STATE_S5) { error = pm_send_all(PM_SUSPEND, (void *)3); if (error) { /* Tell devices to restore state if they have * it saved and to start taking I/O requests. */ pm_send_all(PM_RESUME, (void *)0); return error; } } /* flush caches */ ACPI_FLUSH_CPU_CACHE(); /* Do arch specific saving of state. */ if (state > ACPI_STATE_S1) { error = acpi_save_state_mem(); /* TBD: if no s4bios, write codes for * acpi_save_state_disk()... */ #if 0 if (!error && (state == ACPI_STATE_S4)) error = acpi_save_state_disk(); #endif if (error) { pm_send_all(PM_RESUME, (void *)0); return error; } } } /* 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(); /* Unconditionally turn off devices. * Obvious if we enter a sleep state. * If entering S5 (soft off), this should put devices in a * quiescent state. */ if (state > ACPI_STATE_S1) { error = pm_send_all(PM_SUSPEND, (void *)3); /* 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); } return error ? AE_ERROR : AE_OK; }
static int acpi_pm_enter(suspend_state_t pm_state) { acpi_status status = AE_OK; unsigned long flags = 0; u32 acpi_state = acpi_suspend_states[pm_state]; ACPI_FLUSH_CPU_CACHE(); /* Do arch specific saving of state. */ if (pm_state > PM_SUSPEND_STANDBY) { int error = acpi_save_state_mem(); if (error) return error; } local_irq_save(flags); acpi_enable_wakeup_device(acpi_state); switch (pm_state) { case PM_SUSPEND_STANDBY: barrier(); status = acpi_enter_sleep_state(acpi_state); break; case PM_SUSPEND_MEM: if (unlikely(acpi_simulate_suspend_to_ram)) { printk(KERN_INFO "ACPI: simulating suspend-to-RAM: " "not calling BIOS.\n"); } else { do_suspend_lowlevel(); } break; case PM_SUSPEND_DISK: if (acpi_pm_ops.pm_disk_mode == PM_DISK_PLATFORM) status = acpi_enter_sleep_state(acpi_state); break; case PM_SUSPEND_MAX: acpi_power_off(); break; default: return -EINVAL; } /* ACPI 3.0 specs (P62) says that it's the responsabilty * of the OSPM to clear the status bit [ implying that the * POWER_BUTTON event should not reach userspace ] */ if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3)) acpi_clear_event(ACPI_EVENT_POWER_BUTTON); local_irq_restore(flags); printk(KERN_DEBUG "Back to C!\n"); /* 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 (pm_state > PM_SUSPEND_STANDBY) acpi_restore_state_mem(); return ACPI_SUCCESS(status) ? 0 : -EFAULT; }