Commit e3a59b4d authored by Hannes Reinecke's avatar Hannes Reinecke Committed by Bartlomiej Zolnierkiewicz

ACPI support for IDE devices

This patch implements ACPI integration for generic IDE devices.
The ACPI spec mandates that some methods are called during suspend and
resume. And consequently there most modern Laptops cannot resume
properly without it.

According to the spec, we should call '_GTM' (Get Timing) upon suspend
to store the current IDE adapter settings.
Upon resume we should call '_STM' (Set Timing) to initialize the
adapter with the stored settings; afterwards '_GTF' (Get Taskfile)
should be called which returns a buffer with some IDE initialisation
commands. Those commands should be passed to the drive.

There are two module params which control the behaviour of this patch:

'ide=noacpi'
	Do not call any ACPI methods (Disables any ACPI method calls)
'ide=acpigtf'
	Enable execution of _GTF methods upon resume.
	Has no effect if 'ide=noacpi' is set.
'ide=acpionboot'
	Enable execution of ACPI methods during boot.
	This might be required on some machines if 'ide=acpigtf' is
	selected as some machines modify the _GTF information
	depending on the drive identification passed down with _STM.
Signed-off-by: default avatarHannes Reinecke <hare@suse.de>
Signed-off-by: default avatarBartlomiej Zolnierkiewicz <bzolnier@gmail.com>
parent 78281c53
...@@ -271,6 +271,13 @@ config BLK_DEV_IDESCSI ...@@ -271,6 +271,13 @@ config BLK_DEV_IDESCSI
If both this SCSI emulation and native ATAPI support are compiled If both this SCSI emulation and native ATAPI support are compiled
into the kernel, the native support will be used. into the kernel, the native support will be used.
config BLK_DEV_IDEACPI
bool "IDE ACPI support"
depends on ACPI
---help---
Implement ACPI support for generic IDE devices. On modern
machines ACPI support is required to properly handle ACPI S3 states.
config IDE_TASK_IOCTL config IDE_TASK_IOCTL
bool "IDE Taskfile Access" bool "IDE Taskfile Access"
help help
......
...@@ -22,6 +22,7 @@ ide-core-$(CONFIG_BLK_DEV_IDEPCI) += setup-pci.o ...@@ -22,6 +22,7 @@ ide-core-$(CONFIG_BLK_DEV_IDEPCI) += setup-pci.o
ide-core-$(CONFIG_BLK_DEV_IDEDMA) += ide-dma.o ide-core-$(CONFIG_BLK_DEV_IDEDMA) += ide-dma.o
ide-core-$(CONFIG_PROC_FS) += ide-proc.o ide-core-$(CONFIG_PROC_FS) += ide-proc.o
ide-core-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o ide-core-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o
ide-core-$(CONFIG_BLK_DEV_IDEACPI) += ide-acpi.o
# built-in only drivers from arm/ # built-in only drivers from arm/
ide-core-$(CONFIG_IDE_ARM) += arm/ide_arm.o ide-core-$(CONFIG_IDE_ARM) += arm/ide_arm.o
......
This diff is collapsed.
...@@ -1384,6 +1384,9 @@ static int hwif_init(ide_hwif_t *hwif) ...@@ -1384,6 +1384,9 @@ static int hwif_init(ide_hwif_t *hwif)
done: done:
init_gendisk(hwif); init_gendisk(hwif);
ide_acpi_init(hwif);
hwif->present = 1; /* success */ hwif->present = 1; /* success */
return 1; return 1;
......
...@@ -187,6 +187,12 @@ int noautodma = 1; ...@@ -187,6 +187,12 @@ int noautodma = 1;
EXPORT_SYMBOL(noautodma); EXPORT_SYMBOL(noautodma);
#ifdef CONFIG_BLK_DEV_IDEACPI
int ide_noacpi = 0;
int ide_noacpitfs = 1;
int ide_noacpionboot = 1;
#endif
/* /*
* This is declared extern in ide.h, for access by other IDE modules: * This is declared extern in ide.h, for access by other IDE modules:
*/ */
...@@ -1214,10 +1220,15 @@ EXPORT_SYMBOL(system_bus_clock); ...@@ -1214,10 +1220,15 @@ EXPORT_SYMBOL(system_bus_clock);
static int generic_ide_suspend(struct device *dev, pm_message_t mesg) static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
{ {
ide_drive_t *drive = dev->driver_data; ide_drive_t *drive = dev->driver_data;
ide_hwif_t *hwif = HWIF(drive);
struct request rq; struct request rq;
struct request_pm_state rqpm; struct request_pm_state rqpm;
ide_task_t args; ide_task_t args;
/* Call ACPI _GTM only once */
if (!(drive->dn % 2))
ide_acpi_get_timing(hwif);
memset(&rq, 0, sizeof(rq)); memset(&rq, 0, sizeof(rq));
memset(&rqpm, 0, sizeof(rqpm)); memset(&rqpm, 0, sizeof(rqpm));
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
...@@ -1235,10 +1246,17 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg) ...@@ -1235,10 +1246,17 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
static int generic_ide_resume(struct device *dev) static int generic_ide_resume(struct device *dev)
{ {
ide_drive_t *drive = dev->driver_data; ide_drive_t *drive = dev->driver_data;
ide_hwif_t *hwif = HWIF(drive);
struct request rq; struct request rq;
struct request_pm_state rqpm; struct request_pm_state rqpm;
ide_task_t args; ide_task_t args;
/* Call ACPI _STM only once */
if (!(drive->dn % 2))
ide_acpi_push_timing(hwif);
ide_acpi_exec_tfs(drive);
memset(&rq, 0, sizeof(rq)); memset(&rq, 0, sizeof(rq));
memset(&rqpm, 0, sizeof(rqpm)); memset(&rqpm, 0, sizeof(rqpm));
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
...@@ -1543,6 +1561,24 @@ static int __init ide_setup(char *s) ...@@ -1543,6 +1561,24 @@ static int __init ide_setup(char *s)
} }
#endif /* CONFIG_BLK_DEV_IDEPCI */ #endif /* CONFIG_BLK_DEV_IDEPCI */
#ifdef CONFIG_BLK_DEV_IDEACPI
if (!strcmp(s, "ide=noacpi")) {
//printk(" : Disable IDE ACPI support.\n");
ide_noacpi = 1;
return 1;
}
if (!strcmp(s, "ide=acpigtf")) {
//printk(" : Enable IDE ACPI _GTF support.\n");
ide_noacpitfs = 0;
return 1;
}
if (!strcmp(s, "ide=acpionboot")) {
//printk(" : Call IDE ACPI methods on boot.\n");
ide_noacpionboot = 0;
return 1;
}
#endif /* CONFIG_BLK_DEV_IDEACPI */
/* /*
* Look for drive options: "hdx=" * Look for drive options: "hdx="
*/ */
......
...@@ -18,6 +18,9 @@ ...@@ -18,6 +18,9 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/completion.h> #include <linux/completion.h>
#ifdef CONFIG_BLK_DEV_IDEACPI
#include <acpi/acpi.h>
#endif
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -541,6 +544,11 @@ typedef enum { ...@@ -541,6 +544,11 @@ typedef enum {
struct ide_driver_s; struct ide_driver_s;
struct ide_settings_s; struct ide_settings_s;
#ifdef CONFIG_BLK_DEV_IDEACPI
struct ide_acpi_drive_link;
struct ide_acpi_hwif_link;
#endif
typedef struct ide_drive_s { typedef struct ide_drive_s {
char name[4]; /* drive name, such as "hda" */ char name[4]; /* drive name, such as "hda" */
char driver_req[10]; /* requests specific driver */ char driver_req[10]; /* requests specific driver */
...@@ -637,6 +645,9 @@ typedef struct ide_drive_s { ...@@ -637,6 +645,9 @@ typedef struct ide_drive_s {
int lun; /* logical unit */ int lun; /* logical unit */
int crc_count; /* crc counter to reduce drive speed */ int crc_count; /* crc counter to reduce drive speed */
#ifdef CONFIG_BLK_DEV_IDEACPI
struct ide_acpi_drive_link *acpidata;
#endif
struct list_head list; struct list_head list;
struct device gendev; struct device gendev;
struct completion gendev_rel_comp; /* to deal with device release() */ struct completion gendev_rel_comp; /* to deal with device release() */
...@@ -804,6 +815,10 @@ typedef struct hwif_s { ...@@ -804,6 +815,10 @@ typedef struct hwif_s {
void *hwif_data; /* extra hwif data */ void *hwif_data; /* extra hwif data */
unsigned dma; unsigned dma;
#ifdef CONFIG_BLK_DEV_IDEACPI
struct ide_acpi_hwif_link *acpidata;
#endif
} ____cacheline_internodealigned_in_smp ide_hwif_t; } ____cacheline_internodealigned_in_smp ide_hwif_t;
/* /*
...@@ -1298,6 +1313,18 @@ static inline void ide_dma_verbose(ide_drive_t *drive) { ; } ...@@ -1298,6 +1313,18 @@ static inline void ide_dma_verbose(ide_drive_t *drive) { ; }
static inline void ide_release_dma(ide_hwif_t *drive) {;} static inline void ide_release_dma(ide_hwif_t *drive) {;}
#endif #endif
#ifdef CONFIG_BLK_DEV_IDEACPI
extern int ide_acpi_exec_tfs(ide_drive_t *drive);
extern void ide_acpi_get_timing(ide_hwif_t *hwif);
extern void ide_acpi_push_timing(ide_hwif_t *hwif);
extern void ide_acpi_init(ide_hwif_t *hwif);
#else
static inline int ide_acpi_exec_tfs(ide_drive_t *drive) { return 0; }
static inline void ide_acpi_get_timing(ide_hwif_t *hwif) { ; }
static inline void ide_acpi_push_timing(ide_hwif_t *hwif) { ; }
static inline void ide_acpi_init(ide_hwif_t *hwif) { ; }
#endif
extern int ide_hwif_request_regions(ide_hwif_t *hwif); extern int ide_hwif_request_regions(ide_hwif_t *hwif);
extern void ide_hwif_release_regions(ide_hwif_t* hwif); extern void ide_hwif_release_regions(ide_hwif_t* hwif);
extern void ide_unregister (unsigned int index); extern void ide_unregister (unsigned int index);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment