aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2008-12-29 14:27:37 -0500
committerBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2008-12-29 14:27:37 -0500
commite2984c628c924442132304ae662da433f41c05c9 (patch)
treec7ed2d995fbd96fc9e4cdd12c395640bd2e6fab5
parent1d35364acbd5ab7d67bb39cfc5dd3ed0fbefb4b8 (diff)
ide: move Power Management support to ide-pm.c
There should be no functional changes caused by this patch. Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
-rw-r--r--drivers/ide/Makefile2
-rw-r--r--drivers/ide/ide-io.c159
-rw-r--r--drivers/ide/ide-pm.c235
-rw-r--r--drivers/ide/ide.c74
-rw-r--r--include/linux/ide.h8
5 files changed, 244 insertions, 234 deletions
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
index 7818d402b188..bdc7b81bc044 100644
--- a/drivers/ide/Makefile
+++ b/drivers/ide/Makefile
@@ -5,7 +5,7 @@
5EXTRA_CFLAGS += -Idrivers/ide 5EXTRA_CFLAGS += -Idrivers/ide
6 6
7ide-core-y += ide.o ide-ioctls.o ide-io.o ide-iops.o ide-lib.o ide-probe.o \ 7ide-core-y += ide.o ide-ioctls.o ide-io.o ide-iops.o ide-lib.o ide-probe.o \
8 ide-taskfile.o ide-park.o ide-pio-blacklist.o 8 ide-taskfile.o ide-pm.o ide-park.o ide-pio-blacklist.o
9 9
10# core IDE code 10# core IDE code
11ide-core-$(CONFIG_IDE_TIMINGS) += ide-timings.o 11ide-core-$(CONFIG_IDE_TIMINGS) += ide-timings.o
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 26d3f3cacc8a..ecacc008fdaf 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -120,98 +120,6 @@ int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors)
120} 120}
121EXPORT_SYMBOL(ide_end_request); 121EXPORT_SYMBOL(ide_end_request);
122 122
123static void ide_complete_power_step(ide_drive_t *drive, struct request *rq)
124{
125 struct request_pm_state *pm = rq->data;
126
127#ifdef DEBUG_PM
128 printk(KERN_INFO "%s: complete_power_step(step: %d)\n",
129 drive->name, pm->pm_step);
130#endif
131 if (drive->media != ide_disk)
132 return;
133
134 switch (pm->pm_step) {
135 case IDE_PM_FLUSH_CACHE: /* Suspend step 1 (flush cache) */
136 if (pm->pm_state == PM_EVENT_FREEZE)
137 pm->pm_step = IDE_PM_COMPLETED;
138 else
139 pm->pm_step = IDE_PM_STANDBY;
140 break;
141 case IDE_PM_STANDBY: /* Suspend step 2 (standby) */
142 pm->pm_step = IDE_PM_COMPLETED;
143 break;
144 case IDE_PM_RESTORE_PIO: /* Resume step 1 (restore PIO) */
145 pm->pm_step = IDE_PM_IDLE;
146 break;
147 case IDE_PM_IDLE: /* Resume step 2 (idle)*/
148 pm->pm_step = IDE_PM_RESTORE_DMA;
149 break;
150 }
151}
152
153static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq)
154{
155 struct request_pm_state *pm = rq->data;
156 ide_task_t *args = rq->special;
157
158 memset(args, 0, sizeof(*args));
159
160 switch (pm->pm_step) {
161 case IDE_PM_FLUSH_CACHE: /* Suspend step 1 (flush cache) */
162 if (drive->media != ide_disk)
163 break;
164 /* Not supported? Switch to next step now. */
165 if (ata_id_flush_enabled(drive->id) == 0 ||
166 (drive->dev_flags & IDE_DFLAG_WCACHE) == 0) {
167 ide_complete_power_step(drive, rq);
168 return ide_stopped;
169 }
170 if (ata_id_flush_ext_enabled(drive->id))
171 args->tf.command = ATA_CMD_FLUSH_EXT;
172 else
173 args->tf.command = ATA_CMD_FLUSH;
174 goto out_do_tf;
175 case IDE_PM_STANDBY: /* Suspend step 2 (standby) */
176 args->tf.command = ATA_CMD_STANDBYNOW1;
177 goto out_do_tf;
178 case IDE_PM_RESTORE_PIO: /* Resume step 1 (restore PIO) */
179 ide_set_max_pio(drive);
180 /*
181 * skip IDE_PM_IDLE for ATAPI devices
182 */
183 if (drive->media != ide_disk)
184 pm->pm_step = IDE_PM_RESTORE_DMA;
185 else
186 ide_complete_power_step(drive, rq);
187 return ide_stopped;
188 case IDE_PM_IDLE: /* Resume step 2 (idle) */
189 args->tf.command = ATA_CMD_IDLEIMMEDIATE;
190 goto out_do_tf;
191 case IDE_PM_RESTORE_DMA: /* Resume step 3 (restore DMA) */
192 /*
193 * Right now, all we do is call ide_set_dma(drive),
194 * we could be smarter and check for current xfer_speed
195 * in struct drive etc...
196 */
197 if (drive->hwif->dma_ops == NULL)
198 break;
199 /*
200 * TODO: respect IDE_DFLAG_USING_DMA
201 */
202 ide_set_dma(drive);
203 break;
204 }
205
206 pm->pm_step = IDE_PM_COMPLETED;
207 return ide_stopped;
208
209out_do_tf:
210 args->tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
211 args->data_phase = TASKFILE_NO_DATA;
212 return do_rw_taskfile(drive, args);
213}
214
215/** 123/**
216 * ide_end_dequeued_request - complete an IDE I/O 124 * ide_end_dequeued_request - complete an IDE I/O
217 * @drive: IDE device for the I/O 125 * @drive: IDE device for the I/O
@@ -236,39 +144,6 @@ int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq,
236} 144}
237EXPORT_SYMBOL_GPL(ide_end_dequeued_request); 145EXPORT_SYMBOL_GPL(ide_end_dequeued_request);
238 146
239
240/**
241 * ide_complete_pm_request - end the current Power Management request
242 * @drive: target drive
243 * @rq: request
244 *
245 * This function cleans up the current PM request and stops the queue
246 * if necessary.
247 */
248static void ide_complete_pm_request (ide_drive_t *drive, struct request *rq)
249{
250 struct request_queue *q = drive->queue;
251 unsigned long flags;
252
253#ifdef DEBUG_PM
254 printk("%s: completing PM request, %s\n", drive->name,
255 blk_pm_suspend_request(rq) ? "suspend" : "resume");
256#endif
257 spin_lock_irqsave(q->queue_lock, flags);
258 if (blk_pm_suspend_request(rq)) {
259 blk_stop_queue(q);
260 } else {
261 drive->dev_flags &= ~IDE_DFLAG_BLOCKED;
262 blk_start_queue(q);
263 }
264 spin_unlock_irqrestore(q->queue_lock, flags);
265
266 drive->hwif->hwgroup->rq = NULL;
267
268 if (blk_end_request(rq, 0, 0))
269 BUG();
270}
271
272/** 147/**
273 * ide_end_drive_cmd - end an explicit drive command 148 * ide_end_drive_cmd - end an explicit drive command
274 * @drive: command 149 * @drive: command
@@ -697,40 +572,6 @@ static ide_startstop_t ide_special_rq(ide_drive_t *drive, struct request *rq)
697 } 572 }
698} 573}
699 574
700static void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
701{
702 struct request_pm_state *pm = rq->data;
703
704 if (blk_pm_suspend_request(rq) &&
705 pm->pm_step == IDE_PM_START_SUSPEND)
706 /* Mark drive blocked when starting the suspend sequence. */
707 drive->dev_flags |= IDE_DFLAG_BLOCKED;
708 else if (blk_pm_resume_request(rq) &&
709 pm->pm_step == IDE_PM_START_RESUME) {
710 /*
711 * The first thing we do on wakeup is to wait for BSY bit to
712 * go away (with a looong timeout) as a drive on this hwif may
713 * just be POSTing itself.
714 * We do that before even selecting as the "other" device on
715 * the bus may be broken enough to walk on our toes at this
716 * point.
717 */
718 ide_hwif_t *hwif = drive->hwif;
719 int rc;
720#ifdef DEBUG_PM
721 printk("%s: Wakeup request inited, waiting for !BSY...\n", drive->name);
722#endif
723 rc = ide_wait_not_busy(hwif, 35000);
724 if (rc)
725 printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name);
726 SELECT_DRIVE(drive);
727 hwif->tp_ops->set_irq(hwif, 1);
728 rc = ide_wait_not_busy(hwif, 100000);
729 if (rc)
730 printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name);
731 }
732}
733
734/** 575/**
735 * start_request - start of I/O and command issuing for IDE 576 * start_request - start of I/O and command issuing for IDE
736 * 577 *
diff --git a/drivers/ide/ide-pm.c b/drivers/ide/ide-pm.c
new file mode 100644
index 000000000000..8282c6086e6a
--- /dev/null
+++ b/drivers/ide/ide-pm.c
@@ -0,0 +1,235 @@
1#include <linux/kernel.h>
2#include <linux/ide.h>
3#include <linux/hdreg.h>
4
5int generic_ide_suspend(struct device *dev, pm_message_t mesg)
6{
7 ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive);
8 ide_hwif_t *hwif = HWIF(drive);
9 struct request *rq;
10 struct request_pm_state rqpm;
11 ide_task_t args;
12 int ret;
13
14 /* call ACPI _GTM only once */
15 if ((drive->dn & 1) == 0 || pair == NULL)
16 ide_acpi_get_timing(hwif);
17
18 memset(&rqpm, 0, sizeof(rqpm));
19 memset(&args, 0, sizeof(args));
20 rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
21 rq->cmd_type = REQ_TYPE_PM_SUSPEND;
22 rq->special = &args;
23 rq->data = &rqpm;
24 rqpm.pm_step = IDE_PM_START_SUSPEND;
25 if (mesg.event == PM_EVENT_PRETHAW)
26 mesg.event = PM_EVENT_FREEZE;
27 rqpm.pm_state = mesg.event;
28
29 ret = blk_execute_rq(drive->queue, NULL, rq, 0);
30 blk_put_request(rq);
31
32 /* call ACPI _PS3 only after both devices are suspended */
33 if (ret == 0 && ((drive->dn & 1) || pair == NULL))
34 ide_acpi_set_state(hwif, 0);
35
36 return ret;
37}
38
39int generic_ide_resume(struct device *dev)
40{
41 ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive);
42 ide_hwif_t *hwif = HWIF(drive);
43 struct request *rq;
44 struct request_pm_state rqpm;
45 ide_task_t args;
46 int err;
47
48 /* call ACPI _PS0 / _STM only once */
49 if ((drive->dn & 1) == 0 || pair == NULL) {
50 ide_acpi_set_state(hwif, 1);
51 ide_acpi_push_timing(hwif);
52 }
53
54 ide_acpi_exec_tfs(drive);
55
56 memset(&rqpm, 0, sizeof(rqpm));
57 memset(&args, 0, sizeof(args));
58 rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
59 rq->cmd_type = REQ_TYPE_PM_RESUME;
60 rq->cmd_flags |= REQ_PREEMPT;
61 rq->special = &args;
62 rq->data = &rqpm;
63 rqpm.pm_step = IDE_PM_START_RESUME;
64 rqpm.pm_state = PM_EVENT_ON;
65
66 err = blk_execute_rq(drive->queue, NULL, rq, 1);
67 blk_put_request(rq);
68
69 if (err == 0 && dev->driver) {
70 ide_driver_t *drv = to_ide_driver(dev->driver);
71
72 if (drv->resume)
73 drv->resume(drive);
74 }
75
76 return err;
77}
78
79void ide_complete_power_step(ide_drive_t *drive, struct request *rq)
80{
81 struct request_pm_state *pm = rq->data;
82
83#ifdef DEBUG_PM
84 printk(KERN_INFO "%s: complete_power_step(step: %d)\n",
85 drive->name, pm->pm_step);
86#endif
87 if (drive->media != ide_disk)
88 return;
89
90 switch (pm->pm_step) {
91 case IDE_PM_FLUSH_CACHE: /* Suspend step 1 (flush cache) */
92 if (pm->pm_state == PM_EVENT_FREEZE)
93 pm->pm_step = IDE_PM_COMPLETED;
94 else
95 pm->pm_step = IDE_PM_STANDBY;
96 break;
97 case IDE_PM_STANDBY: /* Suspend step 2 (standby) */
98 pm->pm_step = IDE_PM_COMPLETED;
99 break;
100 case IDE_PM_RESTORE_PIO: /* Resume step 1 (restore PIO) */
101 pm->pm_step = IDE_PM_IDLE;
102 break;
103 case IDE_PM_IDLE: /* Resume step 2 (idle)*/
104 pm->pm_step = IDE_PM_RESTORE_DMA;
105 break;
106 }
107}
108
109ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq)
110{
111 struct request_pm_state *pm = rq->data;
112 ide_task_t *args = rq->special;
113
114 memset(args, 0, sizeof(*args));
115
116 switch (pm->pm_step) {
117 case IDE_PM_FLUSH_CACHE: /* Suspend step 1 (flush cache) */
118 if (drive->media != ide_disk)
119 break;
120 /* Not supported? Switch to next step now. */
121 if (ata_id_flush_enabled(drive->id) == 0 ||
122 (drive->dev_flags & IDE_DFLAG_WCACHE) == 0) {
123 ide_complete_power_step(drive, rq);
124 return ide_stopped;
125 }
126 if (ata_id_flush_ext_enabled(drive->id))
127 args->tf.command = ATA_CMD_FLUSH_EXT;
128 else
129 args->tf.command = ATA_CMD_FLUSH;
130 goto out_do_tf;
131 case IDE_PM_STANDBY: /* Suspend step 2 (standby) */
132 args->tf.command = ATA_CMD_STANDBYNOW1;
133 goto out_do_tf;
134 case IDE_PM_RESTORE_PIO: /* Resume step 1 (restore PIO) */
135 ide_set_max_pio(drive);
136 /*
137 * skip IDE_PM_IDLE for ATAPI devices
138 */
139 if (drive->media != ide_disk)
140 pm->pm_step = IDE_PM_RESTORE_DMA;
141 else
142 ide_complete_power_step(drive, rq);
143 return ide_stopped;
144 case IDE_PM_IDLE: /* Resume step 2 (idle) */
145 args->tf.command = ATA_CMD_IDLEIMMEDIATE;
146 goto out_do_tf;
147 case IDE_PM_RESTORE_DMA: /* Resume step 3 (restore DMA) */
148 /*
149 * Right now, all we do is call ide_set_dma(drive),
150 * we could be smarter and check for current xfer_speed
151 * in struct drive etc...
152 */
153 if (drive->hwif->dma_ops == NULL)
154 break;
155 /*
156 * TODO: respect IDE_DFLAG_USING_DMA
157 */
158 ide_set_dma(drive);
159 break;
160 }
161
162 pm->pm_step = IDE_PM_COMPLETED;
163 return ide_stopped;
164
165out_do_tf:
166 args->tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
167 args->data_phase = TASKFILE_NO_DATA;
168 return do_rw_taskfile(drive, args);
169}
170
171/**
172 * ide_complete_pm_request - end the current Power Management request
173 * @drive: target drive
174 * @rq: request
175 *
176 * This function cleans up the current PM request and stops the queue
177 * if necessary.
178 */
179void ide_complete_pm_request(ide_drive_t *drive, struct request *rq)
180{
181 struct request_queue *q = drive->queue;
182 unsigned long flags;
183
184#ifdef DEBUG_PM
185 printk("%s: completing PM request, %s\n", drive->name,
186 blk_pm_suspend_request(rq) ? "suspend" : "resume");
187#endif
188 spin_lock_irqsave(q->queue_lock, flags);
189 if (blk_pm_suspend_request(rq)) {
190 blk_stop_queue(q);
191 } else {
192 drive->dev_flags &= ~IDE_DFLAG_BLOCKED;
193 blk_start_queue(q);
194 }
195 spin_unlock_irqrestore(q->queue_lock, flags);
196
197 drive->hwif->hwgroup->rq = NULL;
198
199 if (blk_end_request(rq, 0, 0))
200 BUG();
201}
202
203void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
204{
205 struct request_pm_state *pm = rq->data;
206
207 if (blk_pm_suspend_request(rq) &&
208 pm->pm_step == IDE_PM_START_SUSPEND)
209 /* Mark drive blocked when starting the suspend sequence. */
210 drive->dev_flags |= IDE_DFLAG_BLOCKED;
211 else if (blk_pm_resume_request(rq) &&
212 pm->pm_step == IDE_PM_START_RESUME) {
213 /*
214 * The first thing we do on wakeup is to wait for BSY bit to
215 * go away (with a looong timeout) as a drive on this hwif may
216 * just be POSTing itself.
217 * We do that before even selecting as the "other" device on
218 * the bus may be broken enough to walk on our toes at this
219 * point.
220 */
221 ide_hwif_t *hwif = drive->hwif;
222 int rc;
223#ifdef DEBUG_PM
224 printk("%s: Wakeup request inited, waiting for !BSY...\n", drive->name);
225#endif
226 rc = ide_wait_not_busy(hwif, 35000);
227 if (rc)
228 printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name);
229 SELECT_DRIVE(drive);
230 hwif->tp_ops->set_irq(hwif, 1);
231 rc = ide_wait_not_busy(hwif, 100000);
232 if (rc)
233 printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name);
234 }
235}
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 41d042053548..f0f09f702e9c 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -388,80 +388,6 @@ ide_ext_devset_rw_sync(unmaskirq, unmaskirq);
388ide_ext_devset_rw_sync(using_dma, using_dma); 388ide_ext_devset_rw_sync(using_dma, using_dma);
389__IDE_DEVSET(pio_mode, DS_SYNC, NULL, set_pio_mode); 389__IDE_DEVSET(pio_mode, DS_SYNC, NULL, set_pio_mode);
390 390
391static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
392{
393 ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive);
394 ide_hwif_t *hwif = HWIF(drive);
395 struct request *rq;
396 struct request_pm_state rqpm;
397 ide_task_t args;
398 int ret;
399
400 /* call ACPI _GTM only once */
401 if ((drive->dn & 1) == 0 || pair == NULL)
402 ide_acpi_get_timing(hwif);
403
404 memset(&rqpm, 0, sizeof(rqpm));
405 memset(&args, 0, sizeof(args));
406 rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
407 rq->cmd_type = REQ_TYPE_PM_SUSPEND;
408 rq->special = &args;
409 rq->data = &rqpm;
410 rqpm.pm_step = IDE_PM_START_SUSPEND;
411 if (mesg.event == PM_EVENT_PRETHAW)
412 mesg.event = PM_EVENT_FREEZE;
413 rqpm.pm_state = mesg.event;
414
415 ret = blk_execute_rq(drive->queue, NULL, rq, 0);
416 blk_put_request(rq);
417
418 /* call ACPI _PS3 only after both devices are suspended */
419 if (ret == 0 && ((drive->dn & 1) || pair == NULL))
420 ide_acpi_set_state(hwif, 0);
421
422 return ret;
423}
424
425static int generic_ide_resume(struct device *dev)
426{
427 ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive);
428 ide_hwif_t *hwif = HWIF(drive);
429 struct request *rq;
430 struct request_pm_state rqpm;
431 ide_task_t args;
432 int err;
433
434 /* call ACPI _PS0 / _STM only once */
435 if ((drive->dn & 1) == 0 || pair == NULL) {
436 ide_acpi_set_state(hwif, 1);
437 ide_acpi_push_timing(hwif);
438 }
439
440 ide_acpi_exec_tfs(drive);
441
442 memset(&rqpm, 0, sizeof(rqpm));
443 memset(&args, 0, sizeof(args));
444 rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
445 rq->cmd_type = REQ_TYPE_PM_RESUME;
446 rq->cmd_flags |= REQ_PREEMPT;
447 rq->special = &args;
448 rq->data = &rqpm;
449 rqpm.pm_step = IDE_PM_START_RESUME;
450 rqpm.pm_state = PM_EVENT_ON;
451
452 err = blk_execute_rq(drive->queue, NULL, rq, 1);
453 blk_put_request(rq);
454
455 if (err == 0 && dev->driver) {
456 ide_driver_t *drv = to_ide_driver(dev->driver);
457
458 if (drv->resume)
459 drv->resume(drive);
460 }
461
462 return err;
463}
464
465/** 391/**
466 * ide_device_get - get an additional reference to a ide_drive_t 392 * ide_device_get - get an additional reference to a ide_drive_t
467 * @drive: device to get a reference to 393 * @drive: device to get a reference to
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 9b89cab6d493..e99c56de7f56 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -1116,6 +1116,14 @@ enum {
1116 IDE_PM_COMPLETED, 1116 IDE_PM_COMPLETED,
1117}; 1117};
1118 1118
1119int generic_ide_suspend(struct device *, pm_message_t);
1120int generic_ide_resume(struct device *);
1121
1122void ide_complete_power_step(ide_drive_t *, struct request *);
1123ide_startstop_t ide_start_power_step(ide_drive_t *, struct request *);
1124void ide_complete_pm_request(ide_drive_t *, struct request *);
1125void ide_check_pm_state(ide_drive_t *, struct request *);
1126
1119/* 1127/*
1120 * Subdrivers support. 1128 * Subdrivers support.
1121 * 1129 *