Blame view

drivers/ide/ide-pm.c 6.53 KB
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
1
  #include <linux/kernel.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
2
  #include <linux/gfp.h>
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
3
  #include <linux/ide.h>
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
4
5
6
  
  int generic_ide_suspend(struct device *dev, pm_message_t mesg)
  {
fcb520772   Greg Kroah-Hartman   ide: remove drive...
7
8
  	ide_drive_t *drive = dev_get_drvdata(dev);
  	ide_drive_t *pair = ide_get_pair_dev(drive);
898ec223f   Bartlomiej Zolnierkiewicz   ide: remove HWIF(...
9
  	ide_hwif_t *hwif = drive->hwif;
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
10
11
  	struct request *rq;
  	struct request_pm_state rqpm;
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
12
  	int ret;
2bf427b25   Bartlomiej Zolnierkiewicz   ide: fix resume f...
13
14
15
16
17
  	if (ide_port_acpi(hwif)) {
  		/* call ACPI _GTM only once */
  		if ((drive->dn & 1) == 0 || pair == NULL)
  			ide_acpi_get_timing(hwif);
  	}
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
18
19
  
  	memset(&rqpm, 0, sizeof(rqpm));
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
20
21
  	rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
  	rq->cmd_type = REQ_TYPE_PM_SUSPEND;
fc38b521d   Tejun Heo   ide-pm: don't abu...
22
  	rq->special = &rqpm;
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
23
24
25
26
27
28
29
  	rqpm.pm_step = IDE_PM_START_SUSPEND;
  	if (mesg.event == PM_EVENT_PRETHAW)
  		mesg.event = PM_EVENT_FREEZE;
  	rqpm.pm_state = mesg.event;
  
  	ret = blk_execute_rq(drive->queue, NULL, rq, 0);
  	blk_put_request(rq);
2bf427b25   Bartlomiej Zolnierkiewicz   ide: fix resume f...
30
31
32
33
34
  	if (ret == 0 && ide_port_acpi(hwif)) {
  		/* call ACPI _PS3 only after both devices are suspended */
  		if ((drive->dn & 1) || pair == NULL)
  			ide_acpi_set_state(hwif, 0);
  	}
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
35
36
37
38
39
40
  
  	return ret;
  }
  
  int generic_ide_resume(struct device *dev)
  {
fcb520772   Greg Kroah-Hartman   ide: remove drive...
41
42
  	ide_drive_t *drive = dev_get_drvdata(dev);
  	ide_drive_t *pair = ide_get_pair_dev(drive);
898ec223f   Bartlomiej Zolnierkiewicz   ide: remove HWIF(...
43
  	ide_hwif_t *hwif = drive->hwif;
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
44
45
  	struct request *rq;
  	struct request_pm_state rqpm;
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
46
  	int err;
2bf427b25   Bartlomiej Zolnierkiewicz   ide: fix resume f...
47
48
49
50
51
52
  	if (ide_port_acpi(hwif)) {
  		/* call ACPI _PS0 / _STM only once */
  		if ((drive->dn & 1) == 0 || pair == NULL) {
  			ide_acpi_set_state(hwif, 1);
  			ide_acpi_push_timing(hwif);
  		}
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
53

2bf427b25   Bartlomiej Zolnierkiewicz   ide: fix resume f...
54
55
  		ide_acpi_exec_tfs(drive);
  	}
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
56
57
  
  	memset(&rqpm, 0, sizeof(rqpm));
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
58
59
60
  	rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
  	rq->cmd_type = REQ_TYPE_PM_RESUME;
  	rq->cmd_flags |= REQ_PREEMPT;
fc38b521d   Tejun Heo   ide-pm: don't abu...
61
  	rq->special = &rqpm;
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
62
63
64
65
66
67
68
  	rqpm.pm_step = IDE_PM_START_RESUME;
  	rqpm.pm_state = PM_EVENT_ON;
  
  	err = blk_execute_rq(drive->queue, NULL, rq, 1);
  	blk_put_request(rq);
  
  	if (err == 0 && dev->driver) {
7f3c868ba   Bartlomiej Zolnierkiewicz   ide: remove ide_d...
69
  		struct ide_driver *drv = to_ide_driver(dev->driver);
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
70
71
72
73
74
75
76
77
78
79
  
  		if (drv->resume)
  			drv->resume(drive);
  	}
  
  	return err;
  }
  
  void ide_complete_power_step(ide_drive_t *drive, struct request *rq)
  {
fc38b521d   Tejun Heo   ide-pm: don't abu...
80
  	struct request_pm_state *pm = rq->special;
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
  
  #ifdef DEBUG_PM
  	printk(KERN_INFO "%s: complete_power_step(step: %d)
  ",
  		drive->name, pm->pm_step);
  #endif
  	if (drive->media != ide_disk)
  		return;
  
  	switch (pm->pm_step) {
  	case IDE_PM_FLUSH_CACHE:	/* Suspend step 1 (flush cache) */
  		if (pm->pm_state == PM_EVENT_FREEZE)
  			pm->pm_step = IDE_PM_COMPLETED;
  		else
  			pm->pm_step = IDE_PM_STANDBY;
  		break;
  	case IDE_PM_STANDBY:		/* Suspend step 2 (standby) */
  		pm->pm_step = IDE_PM_COMPLETED;
  		break;
  	case IDE_PM_RESTORE_PIO:	/* Resume step 1 (restore PIO) */
  		pm->pm_step = IDE_PM_IDLE;
  		break;
  	case IDE_PM_IDLE:		/* Resume step 2 (idle)*/
  		pm->pm_step = IDE_PM_RESTORE_DMA;
  		break;
  	}
  }
  
  ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq)
  {
fc38b521d   Tejun Heo   ide-pm: don't abu...
111
112
  	struct request_pm_state *pm = rq->special;
  	struct ide_cmd cmd = { };
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
113
114
115
116
117
118
119
120
121
122
123
124
  
  	switch (pm->pm_step) {
  	case IDE_PM_FLUSH_CACHE:	/* Suspend step 1 (flush cache) */
  		if (drive->media != ide_disk)
  			break;
  		/* Not supported? Switch to next step now. */
  		if (ata_id_flush_enabled(drive->id) == 0 ||
  		    (drive->dev_flags & IDE_DFLAG_WCACHE) == 0) {
  			ide_complete_power_step(drive, rq);
  			return ide_stopped;
  		}
  		if (ata_id_flush_ext_enabled(drive->id))
fc38b521d   Tejun Heo   ide-pm: don't abu...
125
  			cmd.tf.command = ATA_CMD_FLUSH_EXT;
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
126
  		else
fc38b521d   Tejun Heo   ide-pm: don't abu...
127
  			cmd.tf.command = ATA_CMD_FLUSH;
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
128
129
  		goto out_do_tf;
  	case IDE_PM_STANDBY:		/* Suspend step 2 (standby) */
fc38b521d   Tejun Heo   ide-pm: don't abu...
130
  		cmd.tf.command = ATA_CMD_STANDBYNOW1;
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
131
132
133
134
135
136
137
138
139
140
141
142
  		goto out_do_tf;
  	case IDE_PM_RESTORE_PIO:	/* Resume step 1 (restore PIO) */
  		ide_set_max_pio(drive);
  		/*
  		 * skip IDE_PM_IDLE for ATAPI devices
  		 */
  		if (drive->media != ide_disk)
  			pm->pm_step = IDE_PM_RESTORE_DMA;
  		else
  			ide_complete_power_step(drive, rq);
  		return ide_stopped;
  	case IDE_PM_IDLE:		/* Resume step 2 (idle) */
fc38b521d   Tejun Heo   ide-pm: don't abu...
143
  		cmd.tf.command = ATA_CMD_IDLEIMMEDIATE;
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
  		goto out_do_tf;
  	case IDE_PM_RESTORE_DMA:	/* Resume step 3 (restore DMA) */
  		/*
  		 * Right now, all we do is call ide_set_dma(drive),
  		 * we could be smarter and check for current xfer_speed
  		 * in struct drive etc...
  		 */
  		if (drive->hwif->dma_ops == NULL)
  			break;
  		/*
  		 * TODO: respect IDE_DFLAG_USING_DMA
  		 */
  		ide_set_dma(drive);
  		break;
  	}
  
  	pm->pm_step = IDE_PM_COMPLETED;
22aa4b32a   Bartlomiej Zolnierkiewicz   ide: remove ide_t...
161

e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
162
163
164
  	return ide_stopped;
  
  out_do_tf:
fc38b521d   Tejun Heo   ide-pm: don't abu...
165
166
167
  	cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
  	cmd.valid.in.tf  = IDE_VALID_IN_TF  | IDE_VALID_DEVICE;
  	cmd.protocol = ATA_PROT_NODATA;
22aa4b32a   Bartlomiej Zolnierkiewicz   ide: remove ide_t...
168

fc38b521d   Tejun Heo   ide-pm: don't abu...
169
  	return do_rw_taskfile(drive, &cmd);
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
170
171
172
  }
  
  /**
3616b6536   Bartlomiej Zolnierkiewicz   ide: complete pow...
173
   *	ide_complete_pm_rq - end the current Power Management request
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
174
175
176
177
178
179
   *	@drive: target drive
   *	@rq: request
   *
   *	This function cleans up the current PM request and stops the queue
   *	if necessary.
   */
3616b6536   Bartlomiej Zolnierkiewicz   ide: complete pow...
180
  void ide_complete_pm_rq(ide_drive_t *drive, struct request *rq)
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
181
182
  {
  	struct request_queue *q = drive->queue;
fc38b521d   Tejun Heo   ide-pm: don't abu...
183
  	struct request_pm_state *pm = rq->special;
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
184
  	unsigned long flags;
3616b6536   Bartlomiej Zolnierkiewicz   ide: complete pow...
185
186
187
  	ide_complete_power_step(drive, rq);
  	if (pm->pm_step != IDE_PM_COMPLETED)
  		return;
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
188
189
190
  #ifdef DEBUG_PM
  	printk("%s: completing PM request, %s
  ", drive->name,
33659ebba   Christoph Hellwig   block: remove wra...
191
  	       (rq->cmd_type == REQ_TYPE_PM_SUSPEND) ? "suspend" : "resume");
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
192
193
  #endif
  	spin_lock_irqsave(q->queue_lock, flags);
33659ebba   Christoph Hellwig   block: remove wra...
194
  	if (rq->cmd_type == REQ_TYPE_PM_SUSPEND)
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
195
  		blk_stop_queue(q);
2ea552102   Bartlomiej Zolnierkiewicz   ide: fix suspend ...
196
  	else
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
197
  		drive->dev_flags &= ~IDE_DFLAG_BLOCKED;
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
198
  	spin_unlock_irqrestore(q->queue_lock, flags);
b65fac32c   Bartlomiej Zolnierkiewicz   ide: merge ide_hw...
199
  	drive->hwif->rq = NULL;
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
200
201
202
203
204
205
206
  
  	if (blk_end_request(rq, 0, 0))
  		BUG();
  }
  
  void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
  {
fc38b521d   Tejun Heo   ide-pm: don't abu...
207
  	struct request_pm_state *pm = rq->special;
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
208

33659ebba   Christoph Hellwig   block: remove wra...
209
  	if (rq->cmd_type == REQ_TYPE_PM_SUSPEND &&
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
210
211
212
  	    pm->pm_step == IDE_PM_START_SUSPEND)
  		/* Mark drive blocked when starting the suspend sequence. */
  		drive->dev_flags |= IDE_DFLAG_BLOCKED;
33659ebba   Christoph Hellwig   block: remove wra...
213
  	else if (rq->cmd_type == REQ_TYPE_PM_RESUME &&
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
214
215
216
217
218
219
220
221
222
223
  		 pm->pm_step == IDE_PM_START_RESUME) {
  		/*
  		 * The first thing we do on wakeup is to wait for BSY bit to
  		 * go away (with a looong timeout) as a drive on this hwif may
  		 * just be POSTing itself.
  		 * We do that before even selecting as the "other" device on
  		 * the bus may be broken enough to walk on our toes at this
  		 * point.
  		 */
  		ide_hwif_t *hwif = drive->hwif;
fdd88f0af   Sergei Shtylyov   ide: inline SELEC...
224
  		const struct ide_tp_ops *tp_ops = hwif->tp_ops;
2ea552102   Bartlomiej Zolnierkiewicz   ide: fix suspend ...
225
226
  		struct request_queue *q = drive->queue;
  		unsigned long flags;
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
227
228
229
230
231
232
233
234
235
  		int rc;
  #ifdef DEBUG_PM
  		printk("%s: Wakeup request inited, waiting for !BSY...
  ", drive->name);
  #endif
  		rc = ide_wait_not_busy(hwif, 35000);
  		if (rc)
  			printk(KERN_WARNING "%s: bus not ready on wakeup
  ", drive->name);
fdd88f0af   Sergei Shtylyov   ide: inline SELEC...
236
237
  		tp_ops->dev_select(drive);
  		tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
238
239
240
241
  		rc = ide_wait_not_busy(hwif, 100000);
  		if (rc)
  			printk(KERN_WARNING "%s: drive not ready on wakeup
  ", drive->name);
2ea552102   Bartlomiej Zolnierkiewicz   ide: fix suspend ...
242
243
244
245
  
  		spin_lock_irqsave(q->queue_lock, flags);
  		blk_start_queue(q);
  		spin_unlock_irqrestore(q->queue_lock, flags);
e2984c628   Bartlomiej Zolnierkiewicz   ide: move Power M...
246
247
  	}
  }