From: Pavel Machek This almost changes no code (constant is still "3"), but at least it uses right constants for device_suspend() and fixes types at few points. Also puts explanation of constants to the Documentation. Signed-off-by: Andrew Morton --- 25-akpm/Documentation/power/devices.txt | 88 ++++++++++++++++++++++++++++++++ 25-akpm/arch/i386/kernel/apm.c | 6 +- 25-akpm/drivers/acpi/sleep/main.c | 2 25-akpm/kernel/power/disk.c | 6 +- 25-akpm/kernel/power/main.c | 7 +- 25-akpm/kernel/power/swsusp.c | 4 - 6 files changed, 102 insertions(+), 11 deletions(-) diff -puN arch/i386/kernel/apm.c~swsusp-dm-use-right-levels-for-device_suspend arch/i386/kernel/apm.c --- 25/arch/i386/kernel/apm.c~swsusp-dm-use-right-levels-for-device_suspend Wed Jan 12 16:08:40 2005 +++ 25-akpm/arch/i386/kernel/apm.c Wed Jan 12 16:08:40 2005 @@ -1201,8 +1201,8 @@ static int suspend(int vetoable) printk(KERN_CRIT "apm: suspend was vetoed, but suspending anyway.\n"); } - device_suspend(3); - device_power_down(3); + device_suspend(PMSG_SUSPEND); + device_power_down(PMSG_SUSPEND); /* serialize with the timer interrupt */ write_seqlock_irq(&xtime_lock); @@ -1255,7 +1255,7 @@ static void standby(void) { int err; - device_power_down(3); + device_power_down(PMSG_SUSPEND); /* serialize with the timer interrupt */ write_seqlock_irq(&xtime_lock); /* If needed, notify drivers here */ diff -puN Documentation/power/devices.txt~swsusp-dm-use-right-levels-for-device_suspend Documentation/power/devices.txt --- 25/Documentation/power/devices.txt~swsusp-dm-use-right-levels-for-device_suspend Wed Jan 12 16:08:40 2005 +++ 25-akpm/Documentation/power/devices.txt Wed Jan 12 16:08:40 2005 @@ -229,3 +229,91 @@ module is re-inserted during it's ->prob The driver core will not call any extra functions when binding the device to the driver. +pm_message_t meaning + +pm_message_t has two fields. event ("major"), and flags. If driver +does not know event code, it aborts the request, returning error. Some +drivers may need to deal with special cases based on the actual type +of suspend operation being done at the system level. This is why +there are flags. + +Event codes are: + +ON -- no need to do anything except special cases like broken +HW. + +# NOTIFICATION -- pretty much same as ON? + +FREEZE -- stop DMA and interrupts, and be prepared to reinit HW from +scratch. That probably means stop accepting upstream requests, the +actual policy of what to do with them being specific to a given +driver. It's acceptable for a network driver to just drop packets +while a block driver is expected to block the queue so no request is +lost. (Use IDE as an example on how to do that). FREEZE requires no +power state change, and it's expected for drivers to be able to +quickly transition back to operating state. + +SUSPEND -- like FREEZE, but also put hardware into low-power state. If +there's need to distinguish several levels of sleep, additional flag +is probably best way to do that. + +Transitions are only from a resumed state to a suspended state, never +between 2 suspended states. (ON -> FREEZE or ON -> SUSPEND can happen, +FREEZE -> SUSPEND or SUSPEND -> FREEZE can not). + +All events are: + +[NOTE NOTE NOTE: If you are driver author, you should not care; you +should only look at event, and ignore flags.] + +#Prepare for suspend -- userland is still running but we are going to +#enter suspend state. This gives drivers chance to load firmware from +#disk and store it in memory, or do other activities taht require +#operating userland, ability to kmalloc GFP_KERNEL, etc... All of these +#are forbiden once the suspend dance is started.. event = ON, flags = +#PREPARE_TO_SUSPEND + +Apm standby -- prepare for APM event. Quiesce devices to make life +easier for APM BIOS. event = FREEZE, flags = APM_STANDBY + +Apm suspend -- same as APM_STANDBY, but it we should probably avoid +spinning down disks. event = FREEZE, flags = APM_SUSPEND + +System halt, reboot -- quiesce devices to make life easier for BIOS. event += FREEZE, flags = SYSTEM_HALT or SYSTEM_REBOOT + +System shutdown -- at least disks need to be spun down, or data may be +lost. Quiesce devices, just to make life easier for BIOS. event = +FREEZE, flags = SYSTEM_SHUTDOWN + +Kexec -- turn off DMAs and put hardware into some state where new +kernel can take over. event = FREEZE, flags = KEXEC + +Powerdown at end of swsusp -- very similar to SYSTEM_SHUTDOWN, except wake +may need to be enabled on some devices. This actually has at least 3 +subtypes, system can reboot, enter S4 and enter S5 at the end of +swsusp. event = FREEZE, flags = SWSUSP and one of SYSTEM_REBOOT, +SYSTEM_SHUTDOWN, SYSTEM_S4 + +Suspend to ram -- put devices into low power state. event = SUSPEND, +flags = SUSPEND_TO_RAM + +Freeze for swsusp snapshot -- stop DMA and interrupts. No need to put +devices into low power mode, but you must be able to reinitialize +device from scratch in resume method. This has two flavors, its done +once on suspending kernel, once on resuming kernel. event = FREEZE, +flags = DURING_SUSPEND or DURING_RESUME + +Device detach requested from /sys -- deinitialize device; proably same as +SYSTEM_SHUTDOWN, I do not understand this one too much. probably event += FREEZE, flags = DEV_DETACH. + +#These are not really events sent: +# +#System fully on -- device is working normally; this is probably never +#passed to suspend() method... event = ON, flags = 0 +# +#Ready after resume -- userland is now running, again. Time to free any +#memory you ate during prepare to suspend... event = ON, flags = +#READY_AFTER_RESUME +# diff -puN drivers/acpi/sleep/main.c~swsusp-dm-use-right-levels-for-device_suspend drivers/acpi/sleep/main.c --- 25/drivers/acpi/sleep/main.c~swsusp-dm-use-right-levels-for-device_suspend Wed Jan 12 16:08:40 2005 +++ 25-akpm/drivers/acpi/sleep/main.c Wed Jan 12 16:08:40 2005 @@ -159,7 +159,7 @@ static int acpi_pm_finish(suspend_state_ int acpi_suspend(u32 acpi_state) { - u32 states[] = { + suspend_state_t states[] = { [1] = PM_SUSPEND_STANDBY, [3] = PM_SUSPEND_MEM, [4] = PM_SUSPEND_DISK, diff -puN kernel/power/disk.c~swsusp-dm-use-right-levels-for-device_suspend kernel/power/disk.c --- 25/kernel/power/disk.c~swsusp-dm-use-right-levels-for-device_suspend Wed Jan 12 16:08:40 2005 +++ 25-akpm/kernel/power/disk.c Wed Jan 12 16:08:40 2005 @@ -51,7 +51,7 @@ static void power_down(suspend_disk_meth local_irq_save(flags); switch(mode) { case PM_DISK_PLATFORM: - device_power_down(PM_SUSPEND_DISK); + device_power_down(PMSG_SUSPEND); error = pm_ops->enter(PM_SUSPEND_DISK); break; case PM_DISK_SHUTDOWN: @@ -144,8 +144,10 @@ static int prepare(void) free_some_memory(); disable_nonboot_cpus(); - if ((error = device_suspend(PM_SUSPEND_DISK))) + if ((error = device_suspend(PMSG_FREEZE))) { + printk("Some devices failed to suspend\n"); goto Finish; + } return 0; Finish: diff -puN kernel/power/main.c~swsusp-dm-use-right-levels-for-device_suspend kernel/power/main.c --- 25/kernel/power/main.c~swsusp-dm-use-right-levels-for-device_suspend Wed Jan 12 16:08:40 2005 +++ 25-akpm/kernel/power/main.c Wed Jan 12 16:08:40 2005 @@ -65,7 +65,7 @@ static int suspend_prepare(suspend_state goto Thaw; } - if ((error = device_suspend(state))) + if ((error = device_suspend(PMSG_SUSPEND))) goto Finish; return 0; Finish: @@ -78,13 +78,14 @@ static int suspend_prepare(suspend_state } -static int suspend_enter(u32 state) +static int suspend_enter(suspend_state_t state) { int error = 0; unsigned long flags; local_irq_save(flags); - if ((error = device_power_down(state))) + + if ((error = device_power_down(PMSG_SUSPEND))) goto Done; error = pm_ops->enter(state); device_power_up(); diff -puN kernel/power/swsusp.c~swsusp-dm-use-right-levels-for-device_suspend kernel/power/swsusp.c --- 25/kernel/power/swsusp.c~swsusp-dm-use-right-levels-for-device_suspend Wed Jan 12 16:08:40 2005 +++ 25-akpm/kernel/power/swsusp.c Wed Jan 12 16:08:40 2005 @@ -849,7 +849,7 @@ int swsusp_suspend(void) * become desynchronized with the actual state of the hardware * at resume time, and evil weirdness ensues. */ - if ((error = device_power_down(PM_SUSPEND_DISK))) { + if ((error = device_power_down(PMSG_FREEZE))) { local_irq_enable(); return error; } @@ -878,7 +878,7 @@ int swsusp_resume(void) { int error; local_irq_disable(); - device_power_down(PM_SUSPEND_DISK); + device_power_down(PMSG_FREEZE); /* We'll ignore saved state, but this gets preempt count (etc) right */ save_processor_state(); error = swsusp_arch_resume(); _