]> git.pld-linux.org Git - packages/kernel.git/blame - linux-2.6.17-ide-acpi-support.patch
- revert
[packages/kernel.git] / linux-2.6.17-ide-acpi-support.patch
CommitLineData
0bdc70b7 1From: Hannes Reinecke <hare@suse.de>
2Subject: ACPI support for IDE devices
3References: 145591 - FATE #151275
4
5This patch implements ACPI integration for generic IDE devices.
6The ACPI spec mandates that some methods are called during suspend and
7resume. And consequently there most modern Laptops cannot resume
8properly without it.
9
10According to the spec, we should call '_GTM' (Get Timing) upon suspend
11to store the current IDE adapter settings.
12Upon resume we should call '_STM' (Set Timing) to initialize the
13adapter with the stored settings; afterwards '_GTF' (Get Taskfile)
14should be called which returns a buffer with some IDE initialisation
15commands. Those commands should be passed to the drive.
16
17There are two module params which control the behaviour of this patch:
18
19'ide=noacpi'
20 Do not call any ACPI methods (Disables any ACPI method calls)
21'ide=acpigtf'
22 Enable execution of _GTF methods upon resume.
23 Has no effect if 'ide=noacpi' is set.
24'ide=acpionboot'
25 Enable execution of ACPI methods during boot.
26 This might be required on some machines if 'ide=acpigtf' is
27 selected as some machines modify the _GTF information
28 depending on the drive identification passed down with _STM.
29
30Signed-off-by: Hannes Reinecke <hare@suse.de>
31
32---
33 drivers/ide/Kconfig | 7
34 drivers/ide/Makefile | 1
35 drivers/ide/ide-acpi.c | 696 ++++++++++++++++++++++++++++++++++++++++++++++++
36 drivers/ide/ide-probe.c | 3
37 drivers/ide/ide.c | 36 ++
38 include/linux/ide.h | 27 +
39 6 files changed, 770 insertions(+)
40
41--- linux-2.6.17.orig/drivers/ide/Kconfig
42+++ linux-2.6.17/drivers/ide/Kconfig
43@@ -262,6 +262,13 @@ config BLK_DEV_IDESCSI
44 If both this SCSI emulation and native ATAPI support are compiled
45 into the kernel, the native support will be used.
46
47+config BLK_DEV_IDEACPI
48+ bool "IDE ACPI support"
49+ depends on ACPI
50+ ---help---
51+ Implement ACPI support for generic IDE devices. On modern
52+ machines ACPI support is required to properly handle ACPI S3 states.
53+
54 config IDE_TASK_IOCTL
55 bool "IDE Taskfile Access"
56 help
57--- linux-2.6.17.orig/drivers/ide/Makefile
58+++ linux-2.6.17/drivers/ide/Makefile
59@@ -22,6 +22,7 @@ ide-core-$(CONFIG_BLK_DEV_IDEPCI) += set
60 ide-core-$(CONFIG_BLK_DEV_IDEDMA) += ide-dma.o
61 ide-core-$(CONFIG_PROC_FS) += ide-proc.o
62 ide-core-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o
63+ide-core-$(CONFIG_BLK_DEV_IDEACPI) += ide-acpi.o
64
65 # built-in only drivers from arm/
66 ide-core-$(CONFIG_IDE_ARM) += arm/ide_arm.o
67--- /dev/null
68+++ linux-2.6.17/drivers/ide/ide-acpi.c
69@@ -0,0 +1,696 @@
70+/*
71+ * ide-acpi.c
72+ * Provides ACPI support for IDE drives.
73+ *
74+ * Copyright (C) 2005 Intel Corp.
75+ * Copyright (C) 2005 Randy Dunlap
76+ * Copyright (C) 2006 SUSE Linux Products GmbH
77+ * Copyright (C) 2006 Hannes Reinecke
78+ */
79+
80+#include <linux/ata.h>
81+#include <linux/delay.h>
82+#include <linux/device.h>
83+#include <linux/errno.h>
84+#include <linux/kernel.h>
85+#include <acpi/acpi.h>
86+#include <linux/ide.h>
87+#include <linux/pci.h>
88+
89+#include <acpi/acpi_bus.h>
90+#include <acpi/acnames.h>
91+#include <acpi/acnamesp.h>
92+#include <acpi/acparser.h>
93+#include <acpi/acexcep.h>
94+#include <acpi/acmacros.h>
95+#include <acpi/actypes.h>
96+
97+#define REGS_PER_GTF 7
98+struct taskfile_array {
99+ u8 tfa[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */
100+};
101+
102+struct GTM_buffer {
103+ u32 PIO_speed0;
104+ u32 DMA_speed0;
105+ u32 PIO_speed1;
106+ u32 DMA_speed1;
107+ u32 GTM_flags;
108+};
109+
110+struct ide_acpi_drive_link {
111+ ide_drive_t *drive;
112+ acpi_handle obj_handle;
113+ u8 idbuff[512];
114+};
115+
116+struct ide_acpi_hwif_link {
117+ ide_hwif_t *hwif;
118+ acpi_handle obj_handle;
119+ struct GTM_buffer gtm;
120+ struct ide_acpi_drive_link master;
121+ struct ide_acpi_drive_link slave;
122+};
123+
124+#undef DEBUGGING
125+/* note: adds function name and KERN_DEBUG */
126+#ifdef DEBUGGING
127+#define DEBPRINT(fmt, args...) \
128+ printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ## args)
129+#else
130+#define DEBPRINT(fmt, args...) do {} while (0)
131+#endif /* DEBUGGING */
132+
133+extern int ide_noacpi;
134+extern int ide_noacpitfs;
135+extern int ide_noacpionboot;
136+
137+/**
138+ * ide_get_dev_handle - finds acpi_handle and PCI device.function
139+ * @dev: device to locate
140+ * @handle: returned acpi_handle for @dev
141+ * @pcidevfn: return PCI device.func for @dev
142+ *
143+ * Returns the ACPI object handle to the corresponding PCI device.
144+ *
145+ * Returns 0 on success, <0 on error.
146+ */
147+static int ide_get_dev_handle(struct device *dev, acpi_handle *handle,
148+ acpi_integer *pcidevfn)
149+{
150+ struct pci_dev *pdev = to_pci_dev(dev);
151+ unsigned int bus, devnum, func;
152+ acpi_integer addr;
153+ acpi_handle dev_handle;
154+ struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER,
155+ .pointer = NULL};
156+ acpi_status status;
157+ struct acpi_device_info *dinfo = NULL;
158+ int ret = -ENODEV;
159+
160+ bus = pdev->bus->number;
161+ devnum = PCI_SLOT(pdev->devfn);
162+ func = PCI_FUNC(pdev->devfn);
163+ /* ACPI _ADR encoding for PCI bus: */
164+ addr = (acpi_integer)(devnum << 16 | func);
165+
166+ DEBPRINT("ENTER: pci %02x:%02x.%01x\n", bus, devnum, func);
167+
168+ dev_handle = DEVICE_ACPI_HANDLE(dev);
169+ if (!dev_handle) {
170+ DEBPRINT("no acpi handle for device\n");
171+ goto err;
172+ }
173+
174+ status = acpi_get_object_info(dev_handle, &buffer);
175+ if (ACPI_FAILURE(status)) {
176+ DEBPRINT("get_object_info for device failed\n");
177+ goto err;
178+ }
179+ dinfo = buffer.pointer;
180+ if (dinfo && (dinfo->valid & ACPI_VALID_ADR) &&
181+ dinfo->address == addr) {
182+ *pcidevfn = addr;
183+ *handle = dev_handle;
184+ } else {
185+ DEBPRINT("get_object_info for device has wrong "
186+ " address: %llu, should be %u\n",
187+ dinfo ? (unsigned long long)dinfo->address : -1ULL,
188+ (unsigned int)addr);
189+ goto err;
190+ }
191+
192+ DEBPRINT("for dev=0x%x.%x, addr=0x%llx, *handle=0x%p\n",
193+ devnum, func, (unsigned long long)addr, *handle);
194+ ret = 0;
195+err:
196+ kfree(dinfo);
197+ return ret;
198+}
199+
200+/**
201+ * ide_acpi_hwif_get_handle - Get ACPI object handle for a given hwif
202+ * @hwif: device to locate
203+ *
204+ * Retrieves the object handle for a given hwif.
205+ *
206+ * Returns handle on success, 0 on error.
207+ */
208+static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif)
209+{
210+ struct device *dev = hwif->gendev.parent;
211+ acpi_handle dev_handle;
212+ acpi_integer pcidevfn;
213+ acpi_handle chan_handle;
214+ int err;
215+
216+ DEBPRINT("ENTER: device %s\n", hwif->name);
217+
218+ if (!dev) {
219+ DEBPRINT("no PCI device for %s\n", hwif->name);
220+ return NULL;
221+ }
222+
223+ err = ide_get_dev_handle(dev, &dev_handle, &pcidevfn);
224+ if (err < 0) {
225+ DEBPRINT("ide_get_dev_handle failed (%d)\n", err);
226+ return NULL;
227+ }
228+
229+ /* get child objects of dev_handle == channel objects,
230+ * + _their_ children == drive objects */
231+ /* channel is hwif->channel */
232+ chan_handle = acpi_get_child(dev_handle, hwif->channel);
233+ DEBPRINT("chan adr=%d: handle=0x%p\n",
234+ hwif->channel, chan_handle);
235+
236+ return chan_handle;
237+}
238+
239+/**
240+ * ide_acpi_drive_get_handle - Get ACPI object handle for a given drive
241+ * @drive: device to locate
242+ *
243+ * Retrieves the object handle of a given drive. According to the ACPI
244+ * spec the drive is a child of the hwif.
245+ *
246+ * Returns handle on success, 0 on error.
247+ */
248+static acpi_handle ide_acpi_drive_get_handle(ide_drive_t *drive)
249+{
250+ ide_hwif_t *hwif = HWIF(drive);
251+ int port;
252+ acpi_handle drive_handle;
253+
254+ if (!hwif->acpidata)
255+ return NULL;
256+
257+ if (!hwif->acpidata->obj_handle)
258+ return NULL;
259+
260+ port = hwif->channel ? drive->dn - 2: drive->dn;
261+
262+ DEBPRINT("ENTER: %s at channel#: %d port#: %d\n",
263+ drive->name, hwif->channel, port);
264+
265+
266+ /* TBD: could also check ACPI object VALID bits */
267+ drive_handle = acpi_get_child(hwif->acpidata->obj_handle, port);
268+ DEBPRINT("drive %s handle 0x%p\n", drive->name, drive_handle);
269+
270+ return drive_handle;
271+}
272+
273+/**
274+ * do_drive_get_GTF - get the drive bootup default taskfile settings
275+ * @drive: the drive for which the taskfile settings should be retrieved
276+ * @gtf_length: number of bytes of _GTF data returned at @gtf_address
277+ * @gtf_address: buffer containing _GTF taskfile arrays
278+ *
279+ * The _GTF method has no input parameters.
280+ * It returns a variable number of register set values (registers
281+ * hex 1F1..1F7, taskfiles).
282+ * The <variable number> is not known in advance, so have ACPI-CA
283+ * allocate the buffer as needed and return it, then free it later.
284+ *
285+ * The returned @gtf_length and @gtf_address are only valid if the
286+ * function return value is 0.
287+ */
288+static int do_drive_get_GTF(ide_drive_t *drive,
289+ unsigned int *gtf_length, unsigned long *gtf_address,
290+ unsigned long *obj_loc)
291+{
292+ acpi_status status;
293+ struct acpi_buffer output;
294+ union acpi_object *out_obj;
295+ ide_hwif_t *hwif = HWIF(drive);
296+ struct device *dev = hwif->gendev.parent;
297+ int err = -ENODEV;
298+ int port;
299+
300+ *gtf_length = 0;
301+ *gtf_address = 0UL;
302+ *obj_loc = 0UL;
303+
304+ if (ide_noacpi)
305+ return 0;
306+
307+ if (!dev) {
308+ DEBPRINT("no PCI device for %s\n", hwif->name);
309+ goto out;
310+ }
311+
312+ if (!hwif->acpidata) {
313+ DEBPRINT("no ACPI data for %s\n", hwif->name);
314+ goto out;
315+ }
316+
317+ port = hwif->channel ? drive->dn - 2: drive->dn;
318+
319+ if (!drive->acpidata) {
320+ if (port == 0) {
321+ drive->acpidata = &hwif->acpidata->master;
322+ hwif->acpidata->master.drive = drive;
323+ } else {
324+ drive->acpidata = &hwif->acpidata->slave;
325+ hwif->acpidata->slave.drive = drive;
326+ }
327+ }
328+
329+ DEBPRINT("ENTER: %s at %s, port#: %d, hard_port#: %d\n",
330+ hwif->name, dev->bus_id, port, hwif->channel);
331+
332+ if (!drive->present) {
333+ DEBPRINT("%s drive %d:%d not present\n",
334+ hwif->name, hwif->channel, port);
335+ goto out;
336+ }
337+
338+ /* Get this drive's _ADR info. if not already known. */
339+ if (!drive->acpidata->obj_handle) {
340+ drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive);
341+ if (!drive->acpidata->obj_handle) {
342+ DEBPRINT("No ACPI object found for %s\n",
343+ drive->name);
344+ goto out;
345+ }
346+ }
347+
348+ /* Setting up output buffer */
349+ output.length = ACPI_ALLOCATE_BUFFER;
350+ output.pointer = NULL; /* ACPI-CA sets this; save/free it later */
351+
352+ /* _GTF has no input parameters */
353+ err = -EIO;
354+ status = acpi_evaluate_object(drive->acpidata->obj_handle, "_GTF",
355+ NULL, &output);
356+ if (ACPI_FAILURE(status)) {
357+ printk(KERN_DEBUG
358+ "%s: Run _GTF error: status = 0x%x\n",
359+ __FUNCTION__, status);
360+ goto out;
361+ }
362+
363+ if (!output.length || !output.pointer) {
364+ DEBPRINT("Run _GTF: "
365+ "length or ptr is NULL (0x%llx, 0x%p)\n",
366+ (unsigned long long)output.length,
367+ output.pointer);
368+ goto out;
369+ }
370+
371+ out_obj = output.pointer;
372+ if (out_obj->type != ACPI_TYPE_BUFFER) {
373+ DEBPRINT("Run _GTF: error: "
374+ "expected object type of ACPI_TYPE_BUFFER, "
375+ "got 0x%x\n", out_obj->type);
376+ err = -ENOENT;
377+ kfree(output.pointer);
378+ goto out;
379+ }
380+
381+ if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
382+ out_obj->buffer.length % REGS_PER_GTF) {
383+ printk(KERN_ERR
384+ "%s: unexpected GTF length (%d) or addr (0x%p)\n",
385+ __FUNCTION__, out_obj->buffer.length,
386+ out_obj->buffer.pointer);
387+ err = -ENOENT;
388+ kfree(output.pointer);
389+ goto out;
390+ }
391+
392+ *gtf_length = out_obj->buffer.length;
393+ *gtf_address = (unsigned long)out_obj->buffer.pointer;
394+ *obj_loc = (unsigned long)out_obj;
395+ DEBPRINT("returning gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n",
396+ *gtf_length, *gtf_address, *obj_loc);
397+ err = 0;
398+out:
399+ return err;
400+}
401+
402+/**
403+ * taskfile_load_raw - send taskfile registers to drive
404+ * @drive: drive to which output is sent
405+ * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7)
406+ *
407+ * Outputs IDE taskfile to the drive.
408+ */
409+static int taskfile_load_raw(ide_drive_t *drive,
410+ const struct taskfile_array *gtf)
411+{
412+ ide_task_t args;
413+ int err = 0;
414+
415+ DEBPRINT("(0x1f1-1f7): hex: "
416+ "%02x %02x %02x %02x %02x %02x %02x\n",
417+ gtf->tfa[0], gtf->tfa[1], gtf->tfa[2],
418+ gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]);
419+
420+ memset(&args, 0, sizeof(ide_task_t));
421+ args.command_type = IDE_DRIVE_TASK_NO_DATA;
422+ args.data_phase = TASKFILE_IN;
423+ args.handler = &task_no_data_intr;
424+
425+ /* convert gtf to IDE Taskfile */
426+ args.tfRegister[1] = gtf->tfa[0]; /* 0x1f1 */
427+ args.tfRegister[2] = gtf->tfa[1]; /* 0x1f2 */
428+ args.tfRegister[3] = gtf->tfa[2]; /* 0x1f3 */
429+ args.tfRegister[4] = gtf->tfa[3]; /* 0x1f4 */
430+ args.tfRegister[5] = gtf->tfa[4]; /* 0x1f5 */
431+ args.tfRegister[6] = gtf->tfa[5]; /* 0x1f6 */
432+ args.tfRegister[7] = gtf->tfa[6]; /* 0x1f7 */
433+
434+ if (ide_noacpitfs) {
435+ DEBPRINT("_GTF execution disabled\n");
436+ return err;
437+ }
438+
439+ err = ide_raw_taskfile(drive, &args, NULL);
440+ if (err)
441+ printk(KERN_ERR "%s: ide_raw_taskfile failed: %u\n",
442+ __FUNCTION__, err);
443+
444+ return err;
445+}
446+
447+/**
448+ * do_drive_set_taskfiles - write the drive taskfile settings from _GTF
449+ * @drive: the drive to which the taskfile command should be sent
450+ * @gtf_length: total number of bytes of _GTF taskfiles
451+ * @gtf_address: location of _GTF taskfile arrays
452+ *
453+ * Write {gtf_address, length gtf_length} in groups of
454+ * REGS_PER_GTF bytes.
455+ */
456+static int do_drive_set_taskfiles(ide_drive_t *drive,
457+ unsigned int gtf_length,
458+ unsigned long gtf_address)
459+{
460+ int rc = -ENODEV, err;
461+ int gtf_count = gtf_length / REGS_PER_GTF;
462+ int ix;
463+ struct taskfile_array *gtf;
464+
465+ if (ide_noacpi)
466+ return 0;
467+
468+ DEBPRINT("ENTER: %s, hard_port#: %d\n", drive->name, drive->dn);
469+
470+ if (!drive->present)
471+ goto out;
472+ if (!gtf_count) /* shouldn't be here */
473+ goto out;
474+
475+ DEBPRINT("total GTF bytes=%u (0x%x), gtf_count=%d, addr=0x%lx\n",
476+ gtf_length, gtf_length, gtf_count, gtf_address);
477+
478+ if (gtf_length % REGS_PER_GTF) {
479+ printk(KERN_ERR "%s: unexpected GTF length (%d)\n",
480+ __FUNCTION__, gtf_length);
481+ goto out;
482+ }
483+
484+ rc = 0;
485+ for (ix = 0; ix < gtf_count; ix++) {
486+ gtf = (struct taskfile_array *)
487+ (gtf_address + ix * REGS_PER_GTF);
488+
489+ /* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */
490+ err = taskfile_load_raw(drive, gtf);
491+ if (err)
492+ rc = err;
493+ }
494+
495+out:
496+ return rc;
497+}
498+
499+/**
500+ * ide_acpi_exec_tfs - get then write drive taskfile settings
501+ * @drive: the drive for which the taskfile settings should be
502+ * written.
503+ *
504+ * According to the ACPI spec this should be called after _STM
505+ * has been evaluated for the interface. Some ACPI vendors interpret
506+ * that as a hard requirement and modify the taskfile according
507+ * to the Identify Drive information passed down with _STM.
508+ * So one should really make sure to call this only after _STM has
509+ * been executed.
510+ */
511+int ide_acpi_exec_tfs(ide_drive_t *drive)
512+{
513+ int ret;
514+ unsigned int gtf_length;
515+ unsigned long gtf_address;
516+ unsigned long obj_loc;
517+
518+ if (ide_noacpi)
519+ return 0;
520+
521+ DEBPRINT("call get_GTF, drive=%s port=%d\n", drive->name, drive->dn);
522+
523+ ret = do_drive_get_GTF(drive, &gtf_length, &gtf_address, &obj_loc);
524+ if (ret < 0) {
525+ DEBPRINT("get_GTF error (%d)\n", ret);
526+ return ret;
527+ }
528+
529+ DEBPRINT("call set_taskfiles, drive=%s\n", drive->name);
530+
531+ ret = do_drive_set_taskfiles(drive, gtf_length, gtf_address);
532+ kfree((void *)obj_loc);
533+ if (ret < 0) {
534+ DEBPRINT("set_taskfiles error (%d)\n", ret);
535+ }
536+
537+ DEBPRINT("ret=%d\n", ret);
538+
539+ return ret;
540+}
541+EXPORT_SYMBOL_GPL(ide_acpi_exec_tfs);
542+
543+/**
544+ * ide_acpi_get_timing - get the channel (controller) timings
545+ * @hwif: target IDE interface (channel)
546+ *
547+ * This function executes the _GTM ACPI method for the target channel.
548+ *
549+ */
550+void ide_acpi_get_timing(ide_hwif_t *hwif)
551+{
552+ acpi_status status;
553+ struct acpi_buffer output;
554+ union acpi_object *out_obj;
555+
556+ if (ide_noacpi)
557+ return;
558+
559+ DEBPRINT("ENTER:\n");
560+
561+ if (!hwif->acpidata) {
562+ DEBPRINT("no ACPI data for %s\n", hwif->name);
563+ return;
564+ }
565+
566+ /* Setting up output buffer for _GTM */
567+ output.length = ACPI_ALLOCATE_BUFFER;
568+ output.pointer = NULL; /* ACPI-CA sets this; save/free it later */
569+
570+ /* _GTM has no input parameters */
571+ status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_GTM",
572+ NULL, &output);
573+
574+ DEBPRINT("_GTM status: %d, outptr: 0x%p, outlen: 0x%llx\n",
575+ status, output.pointer,
576+ (unsigned long long)output.length);
577+
578+ if (ACPI_FAILURE(status)) {
579+ DEBPRINT("Run _GTM error: status = 0x%x\n", status);
580+ return;
581+ }
582+
583+ if (!output.length || !output.pointer) {
584+ DEBPRINT("Run _GTM: length or ptr is NULL (0x%llx, 0x%p)\n",
585+ (unsigned long long)output.length,
586+ output.pointer);
587+ kfree(output.pointer);
588+ return;
589+ }
590+
591+ out_obj = output.pointer;
592+ if (out_obj->type != ACPI_TYPE_BUFFER) {
593+ kfree(output.pointer);
594+ DEBPRINT("Run _GTM: error: "
595+ "expected object type of ACPI_TYPE_BUFFER, "
596+ "got 0x%x\n", out_obj->type);
597+ return;
598+ }
599+
600+ if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
601+ out_obj->buffer.length != sizeof(struct GTM_buffer)) {
602+ kfree(output.pointer);
603+ printk(KERN_ERR
604+ "%s: unexpected _GTM length (0x%x)[should be 0x%x] or addr (0x%p)\n",
605+ __FUNCTION__, out_obj->buffer.length,
606+ sizeof(struct GTM_buffer), out_obj->buffer.pointer);
607+ return;
608+ }
609+
610+ memcpy(&hwif->acpidata->gtm, out_obj->buffer.pointer,
611+ sizeof(struct GTM_buffer));
612+
613+ DEBPRINT("_GTM info: ptr: 0x%p, len: 0x%x, exp.len: 0x%Zx\n",
614+ out_obj->buffer.pointer, out_obj->buffer.length,
615+ sizeof(struct GTM_buffer));
616+
617+ DEBPRINT("_GTM fields: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
618+ hwif->acpidata->gtm.PIO_speed0,
619+ hwif->acpidata->gtm.DMA_speed0,
620+ hwif->acpidata->gtm.PIO_speed1,
621+ hwif->acpidata->gtm.DMA_speed1,
622+ hwif->acpidata->gtm.GTM_flags);
623+
624+ kfree(output.pointer);
625+}
626+EXPORT_SYMBOL_GPL(ide_acpi_get_timing);
627+
628+/**
629+ * ide_acpi_push_timing - set the channel (controller) timings
630+ * @hwif: target IDE interface (channel)
631+ *
632+ * This function executes the _STM ACPI method for the target channel.
633+ *
634+ * _STM requires Identify Drive data, which has to passed as an argument.
635+ * Unfortunately hd_driveid is a mangled version which we can't readily
636+ * use; hence we'll get the information afresh.
637+ */
638+void ide_acpi_push_timing(ide_hwif_t *hwif)
639+{
640+ acpi_status status;
641+ struct acpi_object_list input;
642+ union acpi_object in_params[3];
643+ struct ide_acpi_drive_link *master = &hwif->acpidata->master;
644+ struct ide_acpi_drive_link *slave = &hwif->acpidata->slave;
645+
646+ if (ide_noacpi)
647+ return;
648+
649+ DEBPRINT("ENTER:\n");
650+
651+ if (!hwif->acpidata) {
652+ DEBPRINT("no ACPI data for %s\n", hwif->name);
653+ return;
654+ }
655+
656+ /* Give the GTM buffer + drive Identify data to the channel via the
657+ * _STM method: */
658+ /* setup input parameters buffer for _STM */
659+ input.count = 3;
660+ input.pointer = in_params;
661+ in_params[0].type = ACPI_TYPE_BUFFER;
662+ in_params[0].buffer.length = sizeof(struct GTM_buffer);
663+ in_params[0].buffer.pointer = (u8 *)&hwif->acpidata->gtm;
664+ in_params[1].type = ACPI_TYPE_BUFFER;
665+ in_params[1].buffer.length = sizeof(struct hd_driveid);
666+ in_params[1].buffer.pointer = (u8 *)&master->idbuff;
667+ in_params[2].type = ACPI_TYPE_BUFFER;
668+ in_params[2].buffer.length = sizeof(struct hd_driveid);
669+ in_params[2].buffer.pointer = (u8 *)&slave->idbuff;
670+ /* Output buffer: _STM has no output */
671+
672+ status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_STM",
673+ &input, NULL);
674+
675+ if (ACPI_FAILURE(status)) {
676+ DEBPRINT("Run _STM error: status = 0x%x\n", status);
677+ }
678+ DEBPRINT("_STM status: %d\n", status);
679+}
680+EXPORT_SYMBOL_GPL(ide_acpi_push_timing);
681+
682+/**
683+ * ide_acpi_init - initialize the ACPI link for an IDE interface
684+ * @hwif: target IDE interface (channel)
685+ *
686+ * The ACPI spec is not quite clear when the drive identify buffer
687+ * should be obtained. Calling IDENTIFY DEVICE during shutdown
688+ * is not the best of ideas as the drive might already being put to
689+ * sleep. And obviously we can't call it during resume.
690+ * So we get the information during startup; but this means that
691+ * any changes during run-time will be lost after resume.
692+ */
693+void ide_acpi_init(ide_hwif_t *hwif)
694+{
695+ int unit;
696+ int err;
697+ struct ide_acpi_drive_link *master;
698+ struct ide_acpi_drive_link *slave;
699+
700+ hwif->acpidata = kzalloc(sizeof(struct ide_acpi_hwif_link), GFP_KERNEL);
701+ if (!hwif->acpidata)
702+ return;
703+
704+ hwif->acpidata->obj_handle = ide_acpi_hwif_get_handle(hwif);
705+ if (!hwif->acpidata->obj_handle) {
706+ DEBPRINT("no ACPI object for %s found\n", hwif->name);
707+ kfree(hwif->acpidata);
708+ hwif->acpidata = NULL;
709+ return;
710+ }
711+
712+ /*
713+ * The ACPI spec mandates that we send information
714+ * for both drives, regardless whether they are connected
715+ * or not.
716+ */
717+ hwif->acpidata->master.drive = &hwif->drives[0];
718+ hwif->drives[0].acpidata = &hwif->acpidata->master;
719+ master = &hwif->acpidata->master;
720+
721+ hwif->acpidata->slave.drive = &hwif->drives[1];
722+ hwif->drives[1].acpidata = &hwif->acpidata->slave;
723+ slave = &hwif->acpidata->slave;
724+
725+
726+ /*
727+ * Send IDENTIFY for each drive
728+ */
729+ if (master->drive->present) {
730+ err = taskfile_lib_get_identify(master->drive, master->idbuff);
731+ if (err) {
732+ DEBPRINT("identify device %s failed (%d)\n",
733+ master->drive->name, err);
734+ }
735+ }
736+
737+ if (slave->drive->present) {
738+ err = taskfile_lib_get_identify(slave->drive, slave->idbuff);
739+ if (err) {
740+ DEBPRINT("identify device %s failed (%d)\n",
741+ slave->drive->name, err);
742+ }
743+ }
744+
745+ if (ide_noacpionboot) {
746+ DEBPRINT("ACPI methods disabled on boot\n");
747+ return;
748+ }
749+
750+ /*
751+ * ACPI requires us to call _STM on startup
752+ */
753+ ide_acpi_get_timing(hwif);
754+ ide_acpi_push_timing(hwif);
755+
756+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
757+ ide_drive_t *drive = &hwif->drives[unit];
758+
759+ if (drive->present) {
760+ /* Execute ACPI startup code */
761+ ide_acpi_exec_tfs(drive);
762+ }
763+ }
764+}
765+EXPORT_SYMBOL_GPL(ide_acpi_init);
766--- linux-2.6.17.orig/drivers/ide/ide-probe.c
767+++ linux-2.6.17/drivers/ide/ide-probe.c
768@@ -1377,6 +1377,9 @@ static int hwif_init(ide_hwif_t *hwif)
769
770 done:
771 init_gendisk(hwif);
772+
773+ ide_acpi_init(hwif);
774+
775 hwif->present = 1; /* success */
776 return 1;
777
778--- linux-2.6.17.orig/drivers/ide/ide.c
779+++ linux-2.6.17/drivers/ide/ide.c
780@@ -187,6 +187,12 @@ int noautodma = 1;
781
782 EXPORT_SYMBOL(noautodma);
783
784+#ifdef CONFIG_BLK_DEV_IDEACPI
785+int ide_noacpi = 0;
786+int ide_noacpitfs = 1;
787+int ide_noacpionboot = 1;
788+#endif
789+
790 /*
791 * This is declared extern in ide.h, for access by other IDE modules:
792 */
793@@ -1210,10 +1216,15 @@ EXPORT_SYMBOL(system_bus_clock);
794 static int generic_ide_suspend(struct device *dev, pm_message_t state)
795 {
796 ide_drive_t *drive = dev->driver_data;
797+ ide_hwif_t *hwif = HWIF(drive);
798 struct request rq;
799 struct request_pm_state rqpm;
800 ide_task_t args;
801
802+ /* Call ACPI _GTM only once */
803+ if (!(drive->dn % 2))
804+ ide_acpi_get_timing(hwif);
805+
806 memset(&rq, 0, sizeof(rq));
807 memset(&rqpm, 0, sizeof(rqpm));
808 memset(&args, 0, sizeof(args));
809@@ -1229,10 +1240,17 @@ static int generic_ide_suspend(struct de
810 static int generic_ide_resume(struct device *dev)
811 {
812 ide_drive_t *drive = dev->driver_data;
813+ ide_hwif_t *hwif = HWIF(drive);
814 struct request rq;
815 struct request_pm_state rqpm;
816 ide_task_t args;
817
818+ /* Call ACPI _STM only once */
819+ if (!(drive->dn % 2))
820+ ide_acpi_push_timing(hwif);
821+
822+ ide_acpi_exec_tfs(drive);
823+
824 memset(&rq, 0, sizeof(rq));
825 memset(&rqpm, 0, sizeof(rqpm));
826 memset(&args, 0, sizeof(args));
827@@ -1532,6 +1550,24 @@ static int __init ide_setup(char *s)
828 }
829 #endif /* CONFIG_BLK_DEV_IDEPCI */
830
831+#ifdef CONFIG_BLK_DEV_IDEACPI
832+ if (!strcmp(s, "ide=noacpi")) {
833+ //printk(" : Disable IDE ACPI support.\n");
834+ ide_noacpi = 1;
835+ return 1;
836+ }
837+ if (!strcmp(s, "ide=acpigtf")) {
838+ //printk(" : Enable IDE ACPI _GTF support.\n");
839+ ide_noacpitfs = 0;
840+ return 1;
841+ }
842+ if (!strcmp(s, "ide=acpionboot")) {
843+ //printk(" : Call IDE ACPI methods on boot.\n");
844+ ide_noacpionboot = 0;
845+ return 1;
846+ }
847+#endif /* CONFIG_BLK_DEV_IDEACPI */
848+
849 /*
850 * Look for drive options: "hdx="
851 */
852--- linux-2.6.17.orig/include/linux/ide.h
853+++ linux-2.6.17/include/linux/ide.h
854@@ -18,6 +18,9 @@
855 #include <linux/device.h>
856 #include <linux/pci.h>
857 #include <linux/completion.h>
858+#ifdef CONFIG_BLK_DEV_IDEACPI
859+#include <acpi/acpi.h>
860+#endif
861 #include <asm/byteorder.h>
862 #include <asm/system.h>
863 #include <asm/io.h>
864@@ -540,6 +543,11 @@ typedef enum {
865 struct ide_driver_s;
866 struct ide_settings_s;
867
868+#ifdef CONFIG_BLK_DEV_IDEACPI
869+struct ide_acpi_drive_link;
870+struct ide_acpi_hwif_link;
871+#endif
872+
873 typedef struct ide_drive_s {
874 char name[4]; /* drive name, such as "hda" */
875 char driver_req[10]; /* requests specific driver */
876@@ -636,6 +644,9 @@ typedef struct ide_drive_s {
877
878 int lun; /* logical unit */
879 int crc_count; /* crc counter to reduce drive speed */
880+#ifdef CONFIG_BLK_DEV_IDEACPI
881+ struct ide_acpi_drive_link *acpidata;
882+#endif
883 struct list_head list;
884 struct device gendev;
885 struct completion gendev_rel_comp; /* to deal with device release() */
886@@ -803,6 +814,10 @@ typedef struct hwif_s {
887 unsigned dma;
888
889 void (*led_act)(void *data, int rw);
890+
891+#ifdef CONFIG_BLK_DEV_IDEACPI
892+ struct ide_acpi_hwif_link *acpidata;
893+#endif
894 } ____cacheline_internodealigned_in_smp ide_hwif_t;
895
896 /*
897@@ -1295,6 +1310,18 @@ static inline void ide_dma_verbose(ide_d
898 static inline void ide_release_dma(ide_hwif_t *drive) {;}
899 #endif
900
901+#ifdef CONFIG_BLK_DEV_IDEACPI
902+extern int ide_acpi_exec_tfs(ide_drive_t *drive);
903+extern void ide_acpi_get_timing(ide_hwif_t *hwif);
904+extern void ide_acpi_push_timing(ide_hwif_t *hwif);
905+extern void ide_acpi_init(ide_hwif_t *hwif);
906+#else
907+static inline int ide_acpi_exec_tfs(ide_drive_t *drive) { return 0; }
908+static inline void ide_acpi_get_timing(ide_hwif_t *hwif) { ; }
909+static inline void ide_acpi_push_timing(ide_hwif_t *hwif) { ; }
910+static inline void ide_acpi_init(ide_hwif_t *hwif) { ; }
911+#endif
912+
913 extern int ide_hwif_request_regions(ide_hwif_t *hwif);
914 extern void ide_hwif_release_regions(ide_hwif_t* hwif);
915 extern void ide_unregister (unsigned int index);
This page took 0.151877 seconds and 4 git commands to generate.