Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] ide: reprogram disk pio timings on resume

Add a step to the IDE PM state machine that reprograms disk PIO timings
as the first step on resume. This prevents ide deadlock on
resume-from-ram on my nforce3-based laptop.

An earlier implementation was written entirely within the amd74xx ide
driver, but Alan helpfully pointed out that this is the correct thing to
do globally. Still, I'm only calling hwif->tuneproc() for disks, based
on two things:

- The existing state machine is already passed over for non-disk drives
- Previous testing on my laptop shows that the hangs are related only
to the disk - suspend/resume from a livecd showed that there's no
need for this on the cdrom.

Signed-off-by: Jason Lunz <lunz@falooley.org>
Cc: Bartlomiej Zolnierkiewicz <B.Zolnierkiewicz@elka.pw.edu.pl>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
Cc: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Cc: Pavel Machek <pavel@ucw.cz>
Cc: Brad Campbell <brad@wasp.net.au>
Cc: David Brownell <david-b@pacbell.net>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Jason Lunz and committed by
Linus Torvalds
8c2c0118 3f63c5e8

+19 -6
+19 -6
drivers/ide/ide-io.c
··· 134 134 ide_pm_flush_cache = ide_pm_state_start_suspend, 135 135 idedisk_pm_standby, 136 136 137 - idedisk_pm_idle = ide_pm_state_start_resume, 137 + idedisk_pm_restore_pio = ide_pm_state_start_resume, 138 + idedisk_pm_idle, 138 139 ide_pm_restore_dma, 139 140 }; 140 141 ··· 156 155 case idedisk_pm_standby: /* Suspend step 2 (standby) complete */ 157 156 pm->pm_step = ide_pm_state_completed; 158 157 break; 159 - case idedisk_pm_idle: /* Resume step 1 (idle) complete */ 158 + case idedisk_pm_restore_pio: /* Resume step 1 complete */ 159 + pm->pm_step = idedisk_pm_idle; 160 + break; 161 + case idedisk_pm_idle: /* Resume step 2 (idle) complete */ 160 162 pm->pm_step = ide_pm_restore_dma; 161 163 break; 162 164 } ··· 173 169 memset(args, 0, sizeof(*args)); 174 170 175 171 if (drive->media != ide_disk) { 176 - /* skip idedisk_pm_idle for ATAPI devices */ 177 - if (pm->pm_step == idedisk_pm_idle) 172 + /* 173 + * skip idedisk_pm_restore_pio and idedisk_pm_idle for ATAPI 174 + * devices 175 + */ 176 + if (pm->pm_step == idedisk_pm_restore_pio) 178 177 pm->pm_step = ide_pm_restore_dma; 179 178 } 180 179 ··· 204 197 args->handler = &task_no_data_intr; 205 198 return do_rw_taskfile(drive, args); 206 199 207 - case idedisk_pm_idle: /* Resume step 1 (idle) */ 200 + case idedisk_pm_restore_pio: /* Resume step 1 (restore PIO) */ 201 + if (drive->hwif->tuneproc != NULL) 202 + drive->hwif->tuneproc(drive, 255); 203 + ide_complete_power_step(drive, rq, 0, 0); 204 + return ide_stopped; 205 + 206 + case idedisk_pm_idle: /* Resume step 2 (idle) */ 208 207 args->tfRegister[IDE_COMMAND_OFFSET] = WIN_IDLEIMMEDIATE; 209 208 args->command_type = IDE_DRIVE_TASK_NO_DATA; 210 209 args->handler = task_no_data_intr; 211 210 return do_rw_taskfile(drive, args); 212 211 213 - case ide_pm_restore_dma: /* Resume step 2 (restore DMA) */ 212 + case ide_pm_restore_dma: /* Resume step 3 (restore DMA) */ 214 213 /* 215 214 * Right now, all we do is call hwif->ide_dma_check(drive), 216 215 * we could be smarter and check for current xfer_speed