Suspend/resume call path for ACPI_STATE_S1: 2006/11/17 Jun Sun Note: * Kernel is 2.6.15 patched for original FC5. Run-time system is vmplayer. Customized configuration. * The callgraph is based on echo "standby" to /sysfs/power/state * An alternative way to start suspend path is through /proc/???/acpi in drivers/acpi/sleep/proc.c through calling pm_suspend() in kernel/power/main.c TODO: * Did not track what devices are on some of the lists. Help? [USER] echo -n "standby" > /sysfs/power/state + state_store() - enter_state(ACPI_STATE_S1) - suspend_prepare() - pm_prepare_console() - set_console(SUSPEND_CONSOLE); vt_waitactive(SUSPEND_CONSOLE); orig_kmsg = kmsg_redirect; kmsg_redirect = SUSPEND_CONSOLE; freeze_processes() - for (each thread p) freeze(p) p->flags |= PF_FREEZE if (pm_ops->prepare) pm_ops->prepare() =>acpi_pm_prepare() - acpi_sleep_prepare() - if (acpi_state == ACPI_STATE_S3) { acpi_set_firmware_waking_vector(acpi_wakeup_address); } ACPI_FLUSH_CPU_CACHE(); acpi_enable_wakeup_device_prep(acpi_state); - for each dev in acpi_wakeup_device_list { acpi_enable_wakeup_device_power(dev); - For each resource handle of dev acpi_power_on(dev->wakeup.resources.handles[i]); } acpi_gpe_sleep_prepare(acpi_state); /* Disable all wakeup GPEs before poweroff */ acpi_enter_sleep_state_prep(acpi_state); /* eval acpi objects */ device_suspend() - for each dev in dpm_active { suspend_device(dev, state); - dev->bus->suspend(dev, state); } suspend_enter() - device_power_down(PMSG_SUSPEND) /* shutdown special devices */ - foreach (dev on dpm_off_irq) { suspend_device(dev, state); - dev->bus->suspend(dev, state); } sysdev_suspend(state); - /* Suspend all system devices */ /* pseudo-bus for system 'devices' (cpus, PICs, timers, etc) */ pm_ops->enter(state); =>acpi_pm_enter() - if (pm_state > PM_SUSPEND_STANDBY) { acpi_save_state_mem(); } acpi_enable_wakeup_device(acpi_state); switch (pm_state) { case PM_SUSPEND_STANDBY: acpi_enter_sleep_state(ACPI_STATE_S1); case PM_SUSPEND_MEM : do_suspend_lowlevel(); case PM_SUSPEND_DISK : acpi_enter_sleep_state(ACPI_STATE_S4); case PM_SUSPEND_MAX: acpi_power_off(); } device_power_up(); - sysdev_resume(); /* Bring system devices back to life */ dpm_power_up(); /* power on devices on dpm_off_irq list */ - foeach (dev on dpm_off_irq list) { resume_device(dev); } suspend_finish() - device_resume(); - dpm_resume(); - foeach (dev on dpm_off list) { resume_device(dev); } thaw_processes(); - foreach (thread p) { thaw_process(p); - p->flags &= ~PF_FROZEN; wake_up_process(p); } schedule(); enable_nonboot_cpus(); if (pm_ops->finish) pm_ops->finish(state); =>acpi_pm_finish() - acpi_leave_sleep_state(acpi_state); acpi_disable_wakeup_device(acpi_state); acpi_set_firmware_waking_vector((acpi_physical_address) 0); pm_restore_console(); - set_console(orig_fgconsole); kmsg_redirect = orig_kmsg;