diff options
-rw-r--r-- | drivers/ide/Kconfig | 7 | ||||
-rw-r--r-- | drivers/ide/Makefile | 1 | ||||
-rw-r--r-- | drivers/ide/ide-acpi.c | 696 | ||||
-rw-r--r-- | drivers/ide/ide-probe.c | 3 | ||||
-rw-r--r-- | drivers/ide/ide.c | 36 | ||||
-rw-r--r-- | include/linux/ide.h | 27 |
6 files changed, 770 insertions, 0 deletions
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 0e511ca50b84..ec03341d2bd8 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig | |||
@@ -271,6 +271,13 @@ config BLK_DEV_IDESCSI | |||
271 | If both this SCSI emulation and native ATAPI support are compiled | 271 | If both this SCSI emulation and native ATAPI support are compiled |
272 | into the kernel, the native support will be used. | 272 | into the kernel, the native support will be used. |
273 | 273 | ||
274 | config BLK_DEV_IDEACPI | ||
275 | bool "IDE ACPI support" | ||
276 | depends on ACPI | ||
277 | ---help--- | ||
278 | Implement ACPI support for generic IDE devices. On modern | ||
279 | machines ACPI support is required to properly handle ACPI S3 states. | ||
280 | |||
274 | config IDE_TASK_IOCTL | 281 | config IDE_TASK_IOCTL |
275 | bool "IDE Taskfile Access" | 282 | bool "IDE Taskfile Access" |
276 | help | 283 | help |
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile index 569fae717503..d9f029e8ff74 100644 --- a/drivers/ide/Makefile +++ b/drivers/ide/Makefile | |||
@@ -22,6 +22,7 @@ ide-core-$(CONFIG_BLK_DEV_IDEPCI) += setup-pci.o | |||
22 | ide-core-$(CONFIG_BLK_DEV_IDEDMA) += ide-dma.o | 22 | ide-core-$(CONFIG_BLK_DEV_IDEDMA) += ide-dma.o |
23 | ide-core-$(CONFIG_PROC_FS) += ide-proc.o | 23 | ide-core-$(CONFIG_PROC_FS) += ide-proc.o |
24 | ide-core-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o | 24 | ide-core-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o |
25 | ide-core-$(CONFIG_BLK_DEV_IDEACPI) += ide-acpi.o | ||
25 | 26 | ||
26 | # built-in only drivers from arm/ | 27 | # built-in only drivers from arm/ |
27 | ide-core-$(CONFIG_IDE_ARM) += arm/ide_arm.o | 28 | ide-core-$(CONFIG_IDE_ARM) += arm/ide_arm.o |
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c new file mode 100644 index 000000000000..1eb734951dc9 --- /dev/null +++ b/drivers/ide/ide-acpi.c | |||
@@ -0,0 +1,696 @@ | |||
1 | /* | ||
2 | * ide-acpi.c | ||
3 | * Provides ACPI support for IDE drives. | ||
4 | * | ||
5 | * Copyright (C) 2005 Intel Corp. | ||
6 | * Copyright (C) 2005 Randy Dunlap | ||
7 | * Copyright (C) 2006 SUSE Linux Products GmbH | ||
8 | * Copyright (C) 2006 Hannes Reinecke | ||
9 | */ | ||
10 | |||
11 | #include <linux/ata.h> | ||
12 | #include <linux/delay.h> | ||
13 | #include <linux/device.h> | ||
14 | #include <linux/errno.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <acpi/acpi.h> | ||
17 | #include <linux/ide.h> | ||
18 | #include <linux/pci.h> | ||
19 | |||
20 | #include <acpi/acpi_bus.h> | ||
21 | #include <acpi/acnames.h> | ||
22 | #include <acpi/acnamesp.h> | ||
23 | #include <acpi/acparser.h> | ||
24 | #include <acpi/acexcep.h> | ||
25 | #include <acpi/acmacros.h> | ||
26 | #include <acpi/actypes.h> | ||
27 | |||
28 | #define REGS_PER_GTF 7 | ||
29 | struct taskfile_array { | ||
30 | u8 tfa[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */ | ||
31 | }; | ||
32 | |||
33 | struct GTM_buffer { | ||
34 | u32 PIO_speed0; | ||
35 | u32 DMA_speed0; | ||
36 | u32 PIO_speed1; | ||
37 | u32 DMA_speed1; | ||
38 | u32 GTM_flags; | ||
39 | }; | ||
40 | |||
41 | struct ide_acpi_drive_link { | ||
42 | ide_drive_t *drive; | ||
43 | acpi_handle obj_handle; | ||
44 | u8 idbuff[512]; | ||
45 | }; | ||
46 | |||
47 | struct ide_acpi_hwif_link { | ||
48 | ide_hwif_t *hwif; | ||
49 | acpi_handle obj_handle; | ||
50 | struct GTM_buffer gtm; | ||
51 | struct ide_acpi_drive_link master; | ||
52 | struct ide_acpi_drive_link slave; | ||
53 | }; | ||
54 | |||
55 | #undef DEBUGGING | ||
56 | /* note: adds function name and KERN_DEBUG */ | ||
57 | #ifdef DEBUGGING | ||
58 | #define DEBPRINT(fmt, args...) \ | ||
59 | printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ## args) | ||
60 | #else | ||
61 | #define DEBPRINT(fmt, args...) do {} while (0) | ||
62 | #endif /* DEBUGGING */ | ||
63 | |||
64 | extern int ide_noacpi; | ||
65 | extern int ide_noacpitfs; | ||
66 | extern int ide_noacpionboot; | ||
67 | |||
68 | /** | ||
69 | * ide_get_dev_handle - finds acpi_handle and PCI device.function | ||
70 | * @dev: device to locate | ||
71 | * @handle: returned acpi_handle for @dev | ||
72 | * @pcidevfn: return PCI device.func for @dev | ||
73 | * | ||
74 | * Returns the ACPI object handle to the corresponding PCI device. | ||
75 | * | ||
76 | * Returns 0 on success, <0 on error. | ||
77 | */ | ||
78 | static int ide_get_dev_handle(struct device *dev, acpi_handle *handle, | ||
79 | acpi_integer *pcidevfn) | ||
80 | { | ||
81 | struct pci_dev *pdev = to_pci_dev(dev); | ||
82 | unsigned int bus, devnum, func; | ||
83 | acpi_integer addr; | ||
84 | acpi_handle dev_handle; | ||
85 | struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER, | ||
86 | .pointer = NULL}; | ||
87 | acpi_status status; | ||
88 | struct acpi_device_info *dinfo = NULL; | ||
89 | int ret = -ENODEV; | ||
90 | |||
91 | bus = pdev->bus->number; | ||
92 | devnum = PCI_SLOT(pdev->devfn); | ||
93 | func = PCI_FUNC(pdev->devfn); | ||
94 | /* ACPI _ADR encoding for PCI bus: */ | ||
95 | addr = (acpi_integer)(devnum << 16 | func); | ||
96 | |||
97 | DEBPRINT("ENTER: pci %02x:%02x.%01x\n", bus, devnum, func); | ||
98 | |||
99 | dev_handle = DEVICE_ACPI_HANDLE(dev); | ||
100 | if (!dev_handle) { | ||
101 | DEBPRINT("no acpi handle for device\n"); | ||
102 | goto err; | ||
103 | } | ||
104 | |||
105 | status = acpi_get_object_info(dev_handle, &buffer); | ||
106 | if (ACPI_FAILURE(status)) { | ||
107 | DEBPRINT("get_object_info for device failed\n"); | ||
108 | goto err; | ||
109 | } | ||
110 | dinfo = buffer.pointer; | ||
111 | if (dinfo && (dinfo->valid & ACPI_VALID_ADR) && | ||
112 | dinfo->address == addr) { | ||
113 | *pcidevfn = addr; | ||
114 | *handle = dev_handle; | ||
115 | } else { | ||
116 | DEBPRINT("get_object_info for device has wrong " | ||
117 | " address: %llu, should be %u\n", | ||
118 | dinfo ? (unsigned long long)dinfo->address : -1ULL, | ||
119 | (unsigned int)addr); | ||
120 | goto err; | ||
121 | } | ||
122 | |||
123 | DEBPRINT("for dev=0x%x.%x, addr=0x%llx, *handle=0x%p\n", | ||
124 | devnum, func, (unsigned long long)addr, *handle); | ||
125 | ret = 0; | ||
126 | err: | ||
127 | kfree(dinfo); | ||
128 | return ret; | ||
129 | } | ||
130 | |||
131 | /** | ||
132 | * ide_acpi_hwif_get_handle - Get ACPI object handle for a given hwif | ||
133 | * @hwif: device to locate | ||
134 | * | ||
135 | * Retrieves the object handle for a given hwif. | ||
136 | * | ||
137 | * Returns handle on success, 0 on error. | ||
138 | */ | ||
139 | static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif) | ||
140 | { | ||
141 | struct device *dev = hwif->gendev.parent; | ||
142 | acpi_handle dev_handle; | ||
143 | acpi_integer pcidevfn; | ||
144 | acpi_handle chan_handle; | ||
145 | int err; | ||
146 | |||
147 | DEBPRINT("ENTER: device %s\n", hwif->name); | ||
148 | |||
149 | if (!dev) { | ||
150 | DEBPRINT("no PCI device for %s\n", hwif->name); | ||
151 | return NULL; | ||
152 | } | ||
153 | |||
154 | err = ide_get_dev_handle(dev, &dev_handle, &pcidevfn); | ||
155 | if (err < 0) { | ||
156 | DEBPRINT("ide_get_dev_handle failed (%d)\n", err); | ||
157 | return NULL; | ||
158 | } | ||
159 | |||
160 | /* get child objects of dev_handle == channel objects, | ||
161 | * + _their_ children == drive objects */ | ||
162 | /* channel is hwif->channel */ | ||
163 | chan_handle = acpi_get_child(dev_handle, hwif->channel); | ||
164 | DEBPRINT("chan adr=%d: handle=0x%p\n", | ||
165 | hwif->channel, chan_handle); | ||
166 | |||
167 | return chan_handle; | ||
168 | } | ||
169 | |||
170 | /** | ||
171 | * ide_acpi_drive_get_handle - Get ACPI object handle for a given drive | ||
172 | * @drive: device to locate | ||
173 | * | ||
174 | * Retrieves the object handle of a given drive. According to the ACPI | ||
175 | * spec the drive is a child of the hwif. | ||
176 | * | ||
177 | * Returns handle on success, 0 on error. | ||
178 | */ | ||
179 | static acpi_handle ide_acpi_drive_get_handle(ide_drive_t *drive) | ||
180 | { | ||
181 | ide_hwif_t *hwif = HWIF(drive); | ||
182 | int port; | ||
183 | acpi_handle drive_handle; | ||
184 | |||
185 | if (!hwif->acpidata) | ||
186 | return NULL; | ||
187 | |||
188 | if (!hwif->acpidata->obj_handle) | ||
189 | return NULL; | ||
190 | |||
191 | port = hwif->channel ? drive->dn - 2: drive->dn; | ||
192 | |||
193 | DEBPRINT("ENTER: %s at channel#: %d port#: %d\n", | ||
194 | drive->name, hwif->channel, port); | ||
195 | |||
196 | |||
197 | /* TBD: could also check ACPI object VALID bits */ | ||
198 | drive_handle = acpi_get_child(hwif->acpidata->obj_handle, port); | ||
199 | DEBPRINT("drive %s handle 0x%p\n", drive->name, drive_handle); | ||
200 | |||
201 | return drive_handle; | ||
202 | } | ||
203 | |||
204 | /** | ||
205 | * do_drive_get_GTF - get the drive bootup default taskfile settings | ||
206 | * @drive: the drive for which the taskfile settings should be retrieved | ||
207 | * @gtf_length: number of bytes of _GTF data returned at @gtf_address | ||
208 | * @gtf_address: buffer containing _GTF taskfile arrays | ||
209 | * | ||
210 | * The _GTF method has no input parameters. | ||
211 | * It returns a variable number of register set values (registers | ||
212 | * hex 1F1..1F7, taskfiles). | ||
213 | * The <variable number> is not known in advance, so have ACPI-CA | ||
214 | * allocate the buffer as needed and return it, then free it later. | ||
215 | * | ||
216 | * The returned @gtf_length and @gtf_address are only valid if the | ||
217 | * function return value is 0. | ||
218 | */ | ||
219 | static int do_drive_get_GTF(ide_drive_t *drive, | ||
220 | unsigned int *gtf_length, unsigned long *gtf_address, | ||
221 | unsigned long *obj_loc) | ||
222 | { | ||
223 | acpi_status status; | ||
224 | struct acpi_buffer output; | ||
225 | union acpi_object *out_obj; | ||
226 | ide_hwif_t *hwif = HWIF(drive); | ||
227 | struct device *dev = hwif->gendev.parent; | ||
228 | int err = -ENODEV; | ||
229 | int port; | ||
230 | |||
231 | *gtf_length = 0; | ||
232 | *gtf_address = 0UL; | ||
233 | *obj_loc = 0UL; | ||
234 | |||
235 | if (ide_noacpi) | ||
236 | return 0; | ||
237 | |||
238 | if (!dev) { | ||
239 | DEBPRINT("no PCI device for %s\n", hwif->name); | ||
240 | goto out; | ||
241 | } | ||
242 | |||
243 | if (!hwif->acpidata) { | ||
244 | DEBPRINT("no ACPI data for %s\n", hwif->name); | ||
245 | goto out; | ||
246 | } | ||
247 | |||
248 | port = hwif->channel ? drive->dn - 2: drive->dn; | ||
249 | |||
250 | if (!drive->acpidata) { | ||
251 | if (port == 0) { | ||
252 | drive->acpidata = &hwif->acpidata->master; | ||
253 | hwif->acpidata->master.drive = drive; | ||
254 | } else { | ||
255 | drive->acpidata = &hwif->acpidata->slave; | ||
256 | hwif->acpidata->slave.drive = drive; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | DEBPRINT("ENTER: %s at %s, port#: %d, hard_port#: %d\n", | ||
261 | hwif->name, dev->bus_id, port, hwif->channel); | ||
262 | |||
263 | if (!drive->present) { | ||
264 | DEBPRINT("%s drive %d:%d not present\n", | ||
265 | hwif->name, hwif->channel, port); | ||
266 | goto out; | ||
267 | } | ||
268 | |||
269 | /* Get this drive's _ADR info. if not already known. */ | ||
270 | if (!drive->acpidata->obj_handle) { | ||
271 | drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive); | ||
272 | if (!drive->acpidata->obj_handle) { | ||
273 | DEBPRINT("No ACPI object found for %s\n", | ||
274 | drive->name); | ||
275 | goto out; | ||
276 | } | ||
277 | } | ||
278 | |||
279 | /* Setting up output buffer */ | ||
280 | output.length = ACPI_ALLOCATE_BUFFER; | ||
281 | output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ | ||
282 | |||
283 | /* _GTF has no input parameters */ | ||
284 | err = -EIO; | ||
285 | status = acpi_evaluate_object(drive->acpidata->obj_handle, "_GTF", | ||
286 | NULL, &output); | ||
287 | if (ACPI_FAILURE(status)) { | ||
288 | printk(KERN_DEBUG | ||
289 | "%s: Run _GTF error: status = 0x%x\n", | ||
290 | __FUNCTION__, status); | ||
291 | goto out; | ||
292 | } | ||
293 | |||
294 | if (!output.length || !output.pointer) { | ||
295 | DEBPRINT("Run _GTF: " | ||
296 | "length or ptr is NULL (0x%llx, 0x%p)\n", | ||
297 | (unsigned long long)output.length, | ||
298 | output.pointer); | ||
299 | goto out; | ||
300 | } | ||
301 | |||
302 | out_obj = output.pointer; | ||
303 | if (out_obj->type != ACPI_TYPE_BUFFER) { | ||
304 | DEBPRINT("Run _GTF: error: " | ||
305 | "expected object type of ACPI_TYPE_BUFFER, " | ||
306 | "got 0x%x\n", out_obj->type); | ||
307 | err = -ENOENT; | ||
308 | kfree(output.pointer); | ||
309 | goto out; | ||
310 | } | ||
311 | |||
312 | if (!out_obj->buffer.length || !out_obj->buffer.pointer || | ||
313 | out_obj->buffer.length % REGS_PER_GTF) { | ||
314 | printk(KERN_ERR | ||
315 | "%s: unexpected GTF length (%d) or addr (0x%p)\n", | ||
316 | __FUNCTION__, out_obj->buffer.length, | ||
317 | out_obj->buffer.pointer); | ||
318 | err = -ENOENT; | ||
319 | kfree(output.pointer); | ||
320 | goto out; | ||
321 | } | ||
322 | |||
323 | *gtf_length = out_obj->buffer.length; | ||
324 | *gtf_address = (unsigned long)out_obj->buffer.pointer; | ||
325 | *obj_loc = (unsigned long)out_obj; | ||
326 | DEBPRINT("returning gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n", | ||
327 | *gtf_length, *gtf_address, *obj_loc); | ||
328 | err = 0; | ||
329 | out: | ||
330 | return err; | ||
331 | } | ||
332 | |||
333 | /** | ||
334 | * taskfile_load_raw - send taskfile registers to drive | ||
335 | * @drive: drive to which output is sent | ||
336 | * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7) | ||
337 | * | ||
338 | * Outputs IDE taskfile to the drive. | ||
339 | */ | ||
340 | static int taskfile_load_raw(ide_drive_t *drive, | ||
341 | const struct taskfile_array *gtf) | ||
342 | { | ||
343 | ide_task_t args; | ||
344 | int err = 0; | ||
345 | |||
346 | DEBPRINT("(0x1f1-1f7): hex: " | ||
347 | "%02x %02x %02x %02x %02x %02x %02x\n", | ||
348 | gtf->tfa[0], gtf->tfa[1], gtf->tfa[2], | ||
349 | gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]); | ||
350 | |||
351 | memset(&args, 0, sizeof(ide_task_t)); | ||
352 | args.command_type = IDE_DRIVE_TASK_NO_DATA; | ||
353 | args.data_phase = TASKFILE_IN; | ||
354 | args.handler = &task_no_data_intr; | ||
355 | |||
356 | /* convert gtf to IDE Taskfile */ | ||
357 | args.tfRegister[1] = gtf->tfa[0]; /* 0x1f1 */ | ||
358 | args.tfRegister[2] = gtf->tfa[1]; /* 0x1f2 */ | ||
359 | args.tfRegister[3] = gtf->tfa[2]; /* 0x1f3 */ | ||
360 | args.tfRegister[4] = gtf->tfa[3]; /* 0x1f4 */ | ||
361 | args.tfRegister[5] = gtf->tfa[4]; /* 0x1f5 */ | ||
362 | args.tfRegister[6] = gtf->tfa[5]; /* 0x1f6 */ | ||
363 | args.tfRegister[7] = gtf->tfa[6]; /* 0x1f7 */ | ||
364 | |||
365 | if (ide_noacpitfs) { | ||
366 | DEBPRINT("_GTF execution disabled\n"); | ||
367 | return err; | ||
368 | } | ||
369 | |||
370 | err = ide_raw_taskfile(drive, &args, NULL); | ||
371 | if (err) | ||
372 | printk(KERN_ERR "%s: ide_raw_taskfile failed: %u\n", | ||
373 | __FUNCTION__, err); | ||
374 | |||
375 | return err; | ||
376 | } | ||
377 | |||
378 | /** | ||
379 | * do_drive_set_taskfiles - write the drive taskfile settings from _GTF | ||
380 | * @drive: the drive to which the taskfile command should be sent | ||
381 | * @gtf_length: total number of bytes of _GTF taskfiles | ||
382 | * @gtf_address: location of _GTF taskfile arrays | ||
383 | * | ||
384 | * Write {gtf_address, length gtf_length} in groups of | ||
385 | * REGS_PER_GTF bytes. | ||
386 | */ | ||
387 | static int do_drive_set_taskfiles(ide_drive_t *drive, | ||
388 | unsigned int gtf_length, | ||
389 | unsigned long gtf_address) | ||
390 | { | ||
391 | int rc = -ENODEV, err; | ||
392 | int gtf_count = gtf_length / REGS_PER_GTF; | ||
393 | int ix; | ||
394 | struct taskfile_array *gtf; | ||
395 | |||
396 | if (ide_noacpi) | ||
397 | return 0; | ||
398 | |||
399 | DEBPRINT("ENTER: %s, hard_port#: %d\n", drive->name, drive->dn); | ||
400 | |||
401 | if (!drive->present) | ||
402 | goto out; | ||
403 | if (!gtf_count) /* shouldn't be here */ | ||
404 | goto out; | ||
405 | |||
406 | DEBPRINT("total GTF bytes=%u (0x%x), gtf_count=%d, addr=0x%lx\n", | ||
407 | gtf_length, gtf_length, gtf_count, gtf_address); | ||
408 | |||
409 | if (gtf_length % REGS_PER_GTF) { | ||
410 | printk(KERN_ERR "%s: unexpected GTF length (%d)\n", | ||
411 | __FUNCTION__, gtf_length); | ||
412 | goto out; | ||
413 | } | ||
414 | |||
415 | rc = 0; | ||
416 | for (ix = 0; ix < gtf_count; ix++) { | ||
417 | gtf = (struct taskfile_array *) | ||
418 | (gtf_address + ix * REGS_PER_GTF); | ||
419 | |||
420 | /* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */ | ||
421 | err = taskfile_load_raw(drive, gtf); | ||
422 | if (err) | ||
423 | rc = err; | ||
424 | } | ||
425 | |||
426 | out: | ||
427 | return rc; | ||
428 | } | ||
429 | |||
430 | /** | ||
431 | * ide_acpi_exec_tfs - get then write drive taskfile settings | ||
432 | * @drive: the drive for which the taskfile settings should be | ||
433 | * written. | ||
434 | * | ||
435 | * According to the ACPI spec this should be called after _STM | ||
436 | * has been evaluated for the interface. Some ACPI vendors interpret | ||
437 | * that as a hard requirement and modify the taskfile according | ||
438 | * to the Identify Drive information passed down with _STM. | ||
439 | * So one should really make sure to call this only after _STM has | ||
440 | * been executed. | ||
441 | */ | ||
442 | int ide_acpi_exec_tfs(ide_drive_t *drive) | ||
443 | { | ||
444 | int ret; | ||
445 | unsigned int gtf_length; | ||
446 | unsigned long gtf_address; | ||
447 | unsigned long obj_loc; | ||
448 | |||
449 | if (ide_noacpi) | ||
450 | return 0; | ||
451 | |||
452 | DEBPRINT("call get_GTF, drive=%s port=%d\n", drive->name, drive->dn); | ||
453 | |||
454 | ret = do_drive_get_GTF(drive, >f_length, >f_address, &obj_loc); | ||
455 | if (ret < 0) { | ||
456 | DEBPRINT("get_GTF error (%d)\n", ret); | ||
457 | return ret; | ||
458 | } | ||
459 | |||
460 | DEBPRINT("call set_taskfiles, drive=%s\n", drive->name); | ||
461 | |||
462 | ret = do_drive_set_taskfiles(drive, gtf_length, gtf_address); | ||
463 | kfree((void *)obj_loc); | ||
464 | if (ret < 0) { | ||
465 | DEBPRINT("set_taskfiles error (%d)\n", ret); | ||
466 | } | ||
467 | |||
468 | DEBPRINT("ret=%d\n", ret); | ||
469 | |||
470 | return ret; | ||
471 | } | ||
472 | EXPORT_SYMBOL_GPL(ide_acpi_exec_tfs); | ||
473 | |||
474 | /** | ||
475 | * ide_acpi_get_timing - get the channel (controller) timings | ||
476 | * @hwif: target IDE interface (channel) | ||
477 | * | ||
478 | * This function executes the _GTM ACPI method for the target channel. | ||
479 | * | ||
480 | */ | ||
481 | void ide_acpi_get_timing(ide_hwif_t *hwif) | ||
482 | { | ||
483 | acpi_status status; | ||
484 | struct acpi_buffer output; | ||
485 | union acpi_object *out_obj; | ||
486 | |||
487 | if (ide_noacpi) | ||
488 | return; | ||
489 | |||
490 | DEBPRINT("ENTER:\n"); | ||
491 | |||
492 | if (!hwif->acpidata) { | ||
493 | DEBPRINT("no ACPI data for %s\n", hwif->name); | ||
494 | return; | ||
495 | } | ||
496 | |||
497 | /* Setting up output buffer for _GTM */ | ||
498 | output.length = ACPI_ALLOCATE_BUFFER; | ||
499 | output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ | ||
500 | |||
501 | /* _GTM has no input parameters */ | ||
502 | status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_GTM", | ||
503 | NULL, &output); | ||
504 | |||
505 | DEBPRINT("_GTM status: %d, outptr: 0x%p, outlen: 0x%llx\n", | ||
506 | status, output.pointer, | ||
507 | (unsigned long long)output.length); | ||
508 | |||
509 | if (ACPI_FAILURE(status)) { | ||
510 | DEBPRINT("Run _GTM error: status = 0x%x\n", status); | ||
511 | return; | ||
512 | } | ||
513 | |||
514 | if (!output.length || !output.pointer) { | ||
515 | DEBPRINT("Run _GTM: length or ptr is NULL (0x%llx, 0x%p)\n", | ||
516 | (unsigned long long)output.length, | ||
517 | output.pointer); | ||
518 | kfree(output.pointer); | ||
519 | return; | ||
520 | } | ||
521 | |||
522 | out_obj = output.pointer; | ||
523 | if (out_obj->type != ACPI_TYPE_BUFFER) { | ||
524 | kfree(output.pointer); | ||
525 | DEBPRINT("Run _GTM: error: " | ||
526 | "expected object type of ACPI_TYPE_BUFFER, " | ||
527 | "got 0x%x\n", out_obj->type); | ||
528 | return; | ||
529 | } | ||
530 | |||
531 | if (!out_obj->buffer.length || !out_obj->buffer.pointer || | ||
532 | out_obj->buffer.length != sizeof(struct GTM_buffer)) { | ||
533 | kfree(output.pointer); | ||
534 | printk(KERN_ERR | ||
535 | "%s: unexpected _GTM length (0x%x)[should be 0x%x] or addr (0x%p)\n", | ||
536 | __FUNCTION__, out_obj->buffer.length, | ||
537 | sizeof(struct GTM_buffer), out_obj->buffer.pointer); | ||
538 | return; | ||
539 | } | ||
540 | |||
541 | memcpy(&hwif->acpidata->gtm, out_obj->buffer.pointer, | ||
542 | sizeof(struct GTM_buffer)); | ||
543 | |||
544 | DEBPRINT("_GTM info: ptr: 0x%p, len: 0x%x, exp.len: 0x%Zx\n", | ||
545 | out_obj->buffer.pointer, out_obj->buffer.length, | ||
546 | sizeof(struct GTM_buffer)); | ||
547 | |||
548 | DEBPRINT("_GTM fields: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", | ||
549 | hwif->acpidata->gtm.PIO_speed0, | ||
550 | hwif->acpidata->gtm.DMA_speed0, | ||
551 | hwif->acpidata->gtm.PIO_speed1, | ||
552 | hwif->acpidata->gtm.DMA_speed1, | ||
553 | hwif->acpidata->gtm.GTM_flags); | ||
554 | |||
555 | kfree(output.pointer); | ||
556 | } | ||
557 | EXPORT_SYMBOL_GPL(ide_acpi_get_timing); | ||
558 | |||
559 | /** | ||
560 | * ide_acpi_push_timing - set the channel (controller) timings | ||
561 | * @hwif: target IDE interface (channel) | ||
562 | * | ||
563 | * This function executes the _STM ACPI method for the target channel. | ||
564 | * | ||
565 | * _STM requires Identify Drive data, which has to passed as an argument. | ||
566 | * Unfortunately hd_driveid is a mangled version which we can't readily | ||
567 | * use; hence we'll get the information afresh. | ||
568 | */ | ||
569 | void ide_acpi_push_timing(ide_hwif_t *hwif) | ||
570 | { | ||
571 | acpi_status status; | ||
572 | struct acpi_object_list input; | ||
573 | union acpi_object in_params[3]; | ||
574 | struct ide_acpi_drive_link *master = &hwif->acpidata->master; | ||
575 | struct ide_acpi_drive_link *slave = &hwif->acpidata->slave; | ||
576 | |||
577 | if (ide_noacpi) | ||
578 | return; | ||
579 | |||
580 | DEBPRINT("ENTER:\n"); | ||
581 | |||
582 | if (!hwif->acpidata) { | ||
583 | DEBPRINT("no ACPI data for %s\n", hwif->name); | ||
584 | return; | ||
585 | } | ||
586 | |||
587 | /* Give the GTM buffer + drive Identify data to the channel via the | ||
588 | * _STM method: */ | ||
589 | /* setup input parameters buffer for _STM */ | ||
590 | input.count = 3; | ||
591 | input.pointer = in_params; | ||
592 | in_params[0].type = ACPI_TYPE_BUFFER; | ||
593 | in_params[0].buffer.length = sizeof(struct GTM_buffer); | ||
594 | in_params[0].buffer.pointer = (u8 *)&hwif->acpidata->gtm; | ||
595 | in_params[1].type = ACPI_TYPE_BUFFER; | ||
596 | in_params[1].buffer.length = sizeof(struct hd_driveid); | ||
597 | in_params[1].buffer.pointer = (u8 *)&master->idbuff; | ||
598 | in_params[2].type = ACPI_TYPE_BUFFER; | ||
599 | in_params[2].buffer.length = sizeof(struct hd_driveid); | ||
600 | in_params[2].buffer.pointer = (u8 *)&slave->idbuff; | ||
601 | /* Output buffer: _STM has no output */ | ||
602 | |||
603 | status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_STM", | ||
604 | &input, NULL); | ||
605 | |||
606 | if (ACPI_FAILURE(status)) { | ||
607 | DEBPRINT("Run _STM error: status = 0x%x\n", status); | ||
608 | } | ||
609 | DEBPRINT("_STM status: %d\n", status); | ||
610 | } | ||
611 | EXPORT_SYMBOL_GPL(ide_acpi_push_timing); | ||
612 | |||
613 | /** | ||
614 | * ide_acpi_init - initialize the ACPI link for an IDE interface | ||
615 | * @hwif: target IDE interface (channel) | ||
616 | * | ||
617 | * The ACPI spec is not quite clear when the drive identify buffer | ||
618 | * should be obtained. Calling IDENTIFY DEVICE during shutdown | ||
619 | * is not the best of ideas as the drive might already being put to | ||
620 | * sleep. And obviously we can't call it during resume. | ||
621 | * So we get the information during startup; but this means that | ||
622 | * any changes during run-time will be lost after resume. | ||
623 | */ | ||
624 | void ide_acpi_init(ide_hwif_t *hwif) | ||
625 | { | ||
626 | int unit; | ||
627 | int err; | ||
628 | struct ide_acpi_drive_link *master; | ||
629 | struct ide_acpi_drive_link *slave; | ||
630 | |||
631 | hwif->acpidata = kzalloc(sizeof(struct ide_acpi_hwif_link), GFP_KERNEL); | ||
632 | if (!hwif->acpidata) | ||
633 | return; | ||
634 | |||
635 | hwif->acpidata->obj_handle = ide_acpi_hwif_get_handle(hwif); | ||
636 | if (!hwif->acpidata->obj_handle) { | ||
637 | DEBPRINT("no ACPI object for %s found\n", hwif->name); | ||
638 | kfree(hwif->acpidata); | ||
639 | hwif->acpidata = NULL; | ||
640 | return; | ||
641 | } | ||
642 | |||
643 | /* | ||
644 | * The ACPI spec mandates that we send information | ||
645 | * for both drives, regardless whether they are connected | ||
646 | * or not. | ||
647 | */ | ||
648 | hwif->acpidata->master.drive = &hwif->drives[0]; | ||
649 | hwif->drives[0].acpidata = &hwif->acpidata->master; | ||
650 | master = &hwif->acpidata->master; | ||
651 | |||
652 | hwif->acpidata->slave.drive = &hwif->drives[1]; | ||
653 | hwif->drives[1].acpidata = &hwif->acpidata->slave; | ||
654 | slave = &hwif->acpidata->slave; | ||
655 | |||
656 | |||
657 | /* | ||
658 | * Send IDENTIFY for each drive | ||
659 | */ | ||
660 | if (master->drive->present) { | ||
661 | err = taskfile_lib_get_identify(master->drive, master->idbuff); | ||
662 | if (err) { | ||
663 | DEBPRINT("identify device %s failed (%d)\n", | ||
664 | master->drive->name, err); | ||
665 | } | ||
666 | } | ||
667 | |||
668 | if (slave->drive->present) { | ||
669 | err = taskfile_lib_get_identify(slave->drive, slave->idbuff); | ||
670 | if (err) { | ||
671 | DEBPRINT("identify device %s failed (%d)\n", | ||
672 | slave->drive->name, err); | ||
673 | } | ||
674 | } | ||
675 | |||
676 | if (ide_noacpionboot) { | ||
677 | DEBPRINT("ACPI methods disabled on boot\n"); | ||
678 | return; | ||
679 | } | ||
680 | |||
681 | /* | ||
682 | * ACPI requires us to call _STM on startup | ||
683 | */ | ||
684 | ide_acpi_get_timing(hwif); | ||
685 | ide_acpi_push_timing(hwif); | ||
686 | |||
687 | for (unit = 0; unit < MAX_DRIVES; ++unit) { | ||
688 | ide_drive_t *drive = &hwif->drives[unit]; | ||
689 | |||
690 | if (drive->present) { | ||
691 | /* Execute ACPI startup code */ | ||
692 | ide_acpi_exec_tfs(drive); | ||
693 | } | ||
694 | } | ||
695 | } | ||
696 | EXPORT_SYMBOL_GPL(ide_acpi_init); | ||
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 5a5c565a32a8..176bbc850d6b 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c | |||
@@ -1384,6 +1384,9 @@ static int hwif_init(ide_hwif_t *hwif) | |||
1384 | 1384 | ||
1385 | done: | 1385 | done: |
1386 | init_gendisk(hwif); | 1386 | init_gendisk(hwif); |
1387 | |||
1388 | ide_acpi_init(hwif); | ||
1389 | |||
1387 | hwif->present = 1; /* success */ | 1390 | hwif->present = 1; /* success */ |
1388 | return 1; | 1391 | return 1; |
1389 | 1392 | ||
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 6c9bd5165bdb..c750f6ce770a 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c | |||
@@ -187,6 +187,12 @@ int noautodma = 1; | |||
187 | 187 | ||
188 | EXPORT_SYMBOL(noautodma); | 188 | EXPORT_SYMBOL(noautodma); |
189 | 189 | ||
190 | #ifdef CONFIG_BLK_DEV_IDEACPI | ||
191 | int ide_noacpi = 0; | ||
192 | int ide_noacpitfs = 1; | ||
193 | int ide_noacpionboot = 1; | ||
194 | #endif | ||
195 | |||
190 | /* | 196 | /* |
191 | * This is declared extern in ide.h, for access by other IDE modules: | 197 | * This is declared extern in ide.h, for access by other IDE modules: |
192 | */ | 198 | */ |
@@ -1214,10 +1220,15 @@ EXPORT_SYMBOL(system_bus_clock); | |||
1214 | static int generic_ide_suspend(struct device *dev, pm_message_t mesg) | 1220 | static int generic_ide_suspend(struct device *dev, pm_message_t mesg) |
1215 | { | 1221 | { |
1216 | ide_drive_t *drive = dev->driver_data; | 1222 | ide_drive_t *drive = dev->driver_data; |
1223 | ide_hwif_t *hwif = HWIF(drive); | ||
1217 | struct request rq; | 1224 | struct request rq; |
1218 | struct request_pm_state rqpm; | 1225 | struct request_pm_state rqpm; |
1219 | ide_task_t args; | 1226 | ide_task_t args; |
1220 | 1227 | ||
1228 | /* Call ACPI _GTM only once */ | ||
1229 | if (!(drive->dn % 2)) | ||
1230 | ide_acpi_get_timing(hwif); | ||
1231 | |||
1221 | memset(&rq, 0, sizeof(rq)); | 1232 | memset(&rq, 0, sizeof(rq)); |
1222 | memset(&rqpm, 0, sizeof(rqpm)); | 1233 | memset(&rqpm, 0, sizeof(rqpm)); |
1223 | memset(&args, 0, sizeof(args)); | 1234 | memset(&args, 0, sizeof(args)); |
@@ -1235,10 +1246,17 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg) | |||
1235 | static int generic_ide_resume(struct device *dev) | 1246 | static int generic_ide_resume(struct device *dev) |
1236 | { | 1247 | { |
1237 | ide_drive_t *drive = dev->driver_data; | 1248 | ide_drive_t *drive = dev->driver_data; |
1249 | ide_hwif_t *hwif = HWIF(drive); | ||
1238 | struct request rq; | 1250 | struct request rq; |
1239 | struct request_pm_state rqpm; | 1251 | struct request_pm_state rqpm; |
1240 | ide_task_t args; | 1252 | ide_task_t args; |
1241 | 1253 | ||
1254 | /* Call ACPI _STM only once */ | ||
1255 | if (!(drive->dn % 2)) | ||
1256 | ide_acpi_push_timing(hwif); | ||
1257 | |||
1258 | ide_acpi_exec_tfs(drive); | ||
1259 | |||
1242 | memset(&rq, 0, sizeof(rq)); | 1260 | memset(&rq, 0, sizeof(rq)); |
1243 | memset(&rqpm, 0, sizeof(rqpm)); | 1261 | memset(&rqpm, 0, sizeof(rqpm)); |
1244 | memset(&args, 0, sizeof(args)); | 1262 | memset(&args, 0, sizeof(args)); |
@@ -1543,6 +1561,24 @@ static int __init ide_setup(char *s) | |||
1543 | } | 1561 | } |
1544 | #endif /* CONFIG_BLK_DEV_IDEPCI */ | 1562 | #endif /* CONFIG_BLK_DEV_IDEPCI */ |
1545 | 1563 | ||
1564 | #ifdef CONFIG_BLK_DEV_IDEACPI | ||
1565 | if (!strcmp(s, "ide=noacpi")) { | ||
1566 | //printk(" : Disable IDE ACPI support.\n"); | ||
1567 | ide_noacpi = 1; | ||
1568 | return 1; | ||
1569 | } | ||
1570 | if (!strcmp(s, "ide=acpigtf")) { | ||
1571 | //printk(" : Enable IDE ACPI _GTF support.\n"); | ||
1572 | ide_noacpitfs = 0; | ||
1573 | return 1; | ||
1574 | } | ||
1575 | if (!strcmp(s, "ide=acpionboot")) { | ||
1576 | //printk(" : Call IDE ACPI methods on boot.\n"); | ||
1577 | ide_noacpionboot = 0; | ||
1578 | return 1; | ||
1579 | } | ||
1580 | #endif /* CONFIG_BLK_DEV_IDEACPI */ | ||
1581 | |||
1546 | /* | 1582 | /* |
1547 | * Look for drive options: "hdx=" | 1583 | * Look for drive options: "hdx=" |
1548 | */ | 1584 | */ |
diff --git a/include/linux/ide.h b/include/linux/ide.h index e26a03981a94..ba1c92999f6e 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h | |||
@@ -18,6 +18,9 @@ | |||
18 | #include <linux/device.h> | 18 | #include <linux/device.h> |
19 | #include <linux/pci.h> | 19 | #include <linux/pci.h> |
20 | #include <linux/completion.h> | 20 | #include <linux/completion.h> |
21 | #ifdef CONFIG_BLK_DEV_IDEACPI | ||
22 | #include <acpi/acpi.h> | ||
23 | #endif | ||
21 | #include <asm/byteorder.h> | 24 | #include <asm/byteorder.h> |
22 | #include <asm/system.h> | 25 | #include <asm/system.h> |
23 | #include <asm/io.h> | 26 | #include <asm/io.h> |
@@ -541,6 +544,11 @@ typedef enum { | |||
541 | struct ide_driver_s; | 544 | struct ide_driver_s; |
542 | struct ide_settings_s; | 545 | struct ide_settings_s; |
543 | 546 | ||
547 | #ifdef CONFIG_BLK_DEV_IDEACPI | ||
548 | struct ide_acpi_drive_link; | ||
549 | struct ide_acpi_hwif_link; | ||
550 | #endif | ||
551 | |||
544 | typedef struct ide_drive_s { | 552 | typedef struct ide_drive_s { |
545 | char name[4]; /* drive name, such as "hda" */ | 553 | char name[4]; /* drive name, such as "hda" */ |
546 | char driver_req[10]; /* requests specific driver */ | 554 | char driver_req[10]; /* requests specific driver */ |
@@ -637,6 +645,9 @@ typedef struct ide_drive_s { | |||
637 | 645 | ||
638 | int lun; /* logical unit */ | 646 | int lun; /* logical unit */ |
639 | int crc_count; /* crc counter to reduce drive speed */ | 647 | int crc_count; /* crc counter to reduce drive speed */ |
648 | #ifdef CONFIG_BLK_DEV_IDEACPI | ||
649 | struct ide_acpi_drive_link *acpidata; | ||
650 | #endif | ||
640 | struct list_head list; | 651 | struct list_head list; |
641 | struct device gendev; | 652 | struct device gendev; |
642 | struct completion gendev_rel_comp; /* to deal with device release() */ | 653 | struct completion gendev_rel_comp; /* to deal with device release() */ |
@@ -804,6 +815,10 @@ typedef struct hwif_s { | |||
804 | void *hwif_data; /* extra hwif data */ | 815 | void *hwif_data; /* extra hwif data */ |
805 | 816 | ||
806 | unsigned dma; | 817 | unsigned dma; |
818 | |||
819 | #ifdef CONFIG_BLK_DEV_IDEACPI | ||
820 | struct ide_acpi_hwif_link *acpidata; | ||
821 | #endif | ||
807 | } ____cacheline_internodealigned_in_smp ide_hwif_t; | 822 | } ____cacheline_internodealigned_in_smp ide_hwif_t; |
808 | 823 | ||
809 | /* | 824 | /* |
@@ -1298,6 +1313,18 @@ static inline void ide_dma_verbose(ide_drive_t *drive) { ; } | |||
1298 | static inline void ide_release_dma(ide_hwif_t *drive) {;} | 1313 | static inline void ide_release_dma(ide_hwif_t *drive) {;} |
1299 | #endif | 1314 | #endif |
1300 | 1315 | ||
1316 | #ifdef CONFIG_BLK_DEV_IDEACPI | ||
1317 | extern int ide_acpi_exec_tfs(ide_drive_t *drive); | ||
1318 | extern void ide_acpi_get_timing(ide_hwif_t *hwif); | ||
1319 | extern void ide_acpi_push_timing(ide_hwif_t *hwif); | ||
1320 | extern void ide_acpi_init(ide_hwif_t *hwif); | ||
1321 | #else | ||
1322 | static inline int ide_acpi_exec_tfs(ide_drive_t *drive) { return 0; } | ||
1323 | static inline void ide_acpi_get_timing(ide_hwif_t *hwif) { ; } | ||
1324 | static inline void ide_acpi_push_timing(ide_hwif_t *hwif) { ; } | ||
1325 | static inline void ide_acpi_init(ide_hwif_t *hwif) { ; } | ||
1326 | #endif | ||
1327 | |||
1301 | extern int ide_hwif_request_regions(ide_hwif_t *hwif); | 1328 | extern int ide_hwif_request_regions(ide_hwif_t *hwif); |
1302 | extern void ide_hwif_release_regions(ide_hwif_t* hwif); | 1329 | extern void ide_hwif_release_regions(ide_hwif_t* hwif); |
1303 | extern void ide_unregister (unsigned int index); | 1330 | extern void ide_unregister (unsigned int index); |