diff options
| author | Shaohua Li <shaohua.li@intel.com> | 2007-10-11 17:53:58 -0400 |
|---|---|---|
| committer | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2007-10-11 17:53:58 -0400 |
| commit | 5e32132befa5d2cefadf3141fee0bbb40cd11f0e (patch) | |
| tree | 7bf2002e49b169d24b87a8fe71364875e04d1e90 | |
| parent | 8cb1f567f4c0a2fde9cbf77c2af888a28cab3423 (diff) | |
ide: hook ACPI _PSx method to IDE power on/off
ACPI spec defines the sequence of IDE power on/off:
Powering down:
Call _GTM.
Power down drive (calls _PS3 method and turns off power planes).
Powering up:
Power up drive (calls _PS0 method if present and turns on power planes).
Call _STM passing info from _GTM (possibly modified), with ID data from
each drive.
Initialize the channel.
May modify the results of _GTF.
For each drive:
Call _GTF.
Execute task file (possibly modified).
This patch adds the missed _PS0/_PS3 methods call.
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
Acked-by: Len Brown <len.brown@intel.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
| -rw-r--r-- | drivers/acpi/bus.c | 4 | ||||
| -rw-r--r-- | drivers/ide/ide-acpi.c | 42 | ||||
| -rw-r--r-- | drivers/ide/ide.c | 14 | ||||
| -rw-r--r-- | include/linux/ide.h | 2 |
4 files changed, 59 insertions, 3 deletions
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 9ba778a2b4..feab124d8e 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c | |||
| @@ -262,10 +262,12 @@ int acpi_bus_set_power(acpi_handle handle, int state) | |||
| 262 | printk(KERN_WARNING PREFIX | 262 | printk(KERN_WARNING PREFIX |
| 263 | "Transitioning device [%s] to D%d\n", | 263 | "Transitioning device [%s] to D%d\n", |
| 264 | device->pnp.bus_id, state); | 264 | device->pnp.bus_id, state); |
| 265 | else | 265 | else { |
| 266 | device->power.state = state; | ||
| 266 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 267 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
| 267 | "Device [%s] transitioned to D%d\n", | 268 | "Device [%s] transitioned to D%d\n", |
| 268 | device->pnp.bus_id, state)); | 269 | device->pnp.bus_id, state)); |
| 270 | } | ||
| 269 | 271 | ||
| 270 | return result; | 272 | return result; |
| 271 | } | 273 | } |
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c index 17aea65d7d..6bff81a58b 100644 --- a/drivers/ide/ide-acpi.c +++ b/drivers/ide/ide-acpi.c | |||
| @@ -612,6 +612,46 @@ void ide_acpi_push_timing(ide_hwif_t *hwif) | |||
| 612 | EXPORT_SYMBOL_GPL(ide_acpi_push_timing); | 612 | EXPORT_SYMBOL_GPL(ide_acpi_push_timing); |
| 613 | 613 | ||
| 614 | /** | 614 | /** |
| 615 | * ide_acpi_set_state - set the channel power state | ||
| 616 | * @hwif: target IDE interface | ||
| 617 | * @on: state, on/off | ||
| 618 | * | ||
| 619 | * This function executes the _PS0/_PS3 ACPI method to set the power state. | ||
| 620 | * ACPI spec requires _PS0 when IDE power on and _PS3 when power off | ||
| 621 | */ | ||
| 622 | void ide_acpi_set_state(ide_hwif_t *hwif, int on) | ||
| 623 | { | ||
| 624 | int unit; | ||
| 625 | |||
| 626 | if (ide_noacpi) | ||
| 627 | return; | ||
| 628 | |||
| 629 | DEBPRINT("ENTER:\n"); | ||
| 630 | |||
| 631 | if (!hwif->acpidata) { | ||
| 632 | DEBPRINT("no ACPI data for %s\n", hwif->name); | ||
| 633 | return; | ||
| 634 | } | ||
| 635 | /* channel first and then drives for power on and verse versa for power off */ | ||
| 636 | if (on) | ||
| 637 | acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D0); | ||
| 638 | for (unit = 0; unit < MAX_DRIVES; ++unit) { | ||
| 639 | ide_drive_t *drive = &hwif->drives[unit]; | ||
| 640 | |||
| 641 | if (!drive->acpidata->obj_handle) | ||
| 642 | drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive); | ||
| 643 | |||
| 644 | if (drive->acpidata->obj_handle && drive->present) { | ||
| 645 | acpi_bus_set_power(drive->acpidata->obj_handle, | ||
| 646 | on? ACPI_STATE_D0: ACPI_STATE_D3); | ||
| 647 | } | ||
| 648 | } | ||
| 649 | if (!on) | ||
| 650 | acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D3); | ||
| 651 | } | ||
| 652 | EXPORT_SYMBOL_GPL(ide_acpi_set_state); | ||
| 653 | |||
| 654 | /** | ||
| 615 | * ide_acpi_init - initialize the ACPI link for an IDE interface | 655 | * ide_acpi_init - initialize the ACPI link for an IDE interface |
| 616 | * @hwif: target IDE interface (channel) | 656 | * @hwif: target IDE interface (channel) |
| 617 | * | 657 | * |
| @@ -679,6 +719,8 @@ void ide_acpi_init(ide_hwif_t *hwif) | |||
| 679 | return; | 719 | return; |
| 680 | } | 720 | } |
| 681 | 721 | ||
| 722 | /* ACPI _PS0 before _STM */ | ||
| 723 | ide_acpi_set_state(hwif, 1); | ||
| 682 | /* | 724 | /* |
| 683 | * ACPI requires us to call _STM on startup | 725 | * ACPI requires us to call _STM on startup |
| 684 | */ | 726 | */ |
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index de54306789..9fdc1fe1b2 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c | |||
| @@ -915,6 +915,7 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg) | |||
| 915 | struct request rq; | 915 | struct request rq; |
| 916 | struct request_pm_state rqpm; | 916 | struct request_pm_state rqpm; |
| 917 | ide_task_t args; | 917 | ide_task_t args; |
| 918 | int ret; | ||
| 918 | 919 | ||
| 919 | /* Call ACPI _GTM only once */ | 920 | /* Call ACPI _GTM only once */ |
| 920 | if (!(drive->dn % 2)) | 921 | if (!(drive->dn % 2)) |
| @@ -931,7 +932,14 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg) | |||
| 931 | mesg.event = PM_EVENT_FREEZE; | 932 | mesg.event = PM_EVENT_FREEZE; |
| 932 | rqpm.pm_state = mesg.event; | 933 | rqpm.pm_state = mesg.event; |
| 933 | 934 | ||
| 934 | return ide_do_drive_cmd(drive, &rq, ide_wait); | 935 | ret = ide_do_drive_cmd(drive, &rq, ide_wait); |
| 936 | /* only call ACPI _PS3 after both drivers are suspended */ | ||
| 937 | if (!ret && (((drive->dn % 2) && hwif->drives[0].present | ||
| 938 | && hwif->drives[1].present) | ||
| 939 | || !hwif->drives[0].present | ||
| 940 | || !hwif->drives[1].present)) | ||
| 941 | ide_acpi_set_state(hwif, 0); | ||
| 942 | return ret; | ||
| 935 | } | 943 | } |
| 936 | 944 | ||
| 937 | static int generic_ide_resume(struct device *dev) | 945 | static int generic_ide_resume(struct device *dev) |
| @@ -944,8 +952,10 @@ static int generic_ide_resume(struct device *dev) | |||
| 944 | int err; | 952 | int err; |
| 945 | 953 | ||
| 946 | /* Call ACPI _STM only once */ | 954 | /* Call ACPI _STM only once */ |
| 947 | if (!(drive->dn % 2)) | 955 | if (!(drive->dn % 2)) { |
| 956 | ide_acpi_set_state(hwif, 1); | ||
| 948 | ide_acpi_push_timing(hwif); | 957 | ide_acpi_push_timing(hwif); |
| 958 | } | ||
| 949 | 959 | ||
| 950 | ide_acpi_exec_tfs(drive); | 960 | ide_acpi_exec_tfs(drive); |
| 951 | 961 | ||
diff --git a/include/linux/ide.h b/include/linux/ide.h index 0665428356..80ea946282 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h | |||
| @@ -1338,11 +1338,13 @@ extern int ide_acpi_exec_tfs(ide_drive_t *drive); | |||
| 1338 | extern void ide_acpi_get_timing(ide_hwif_t *hwif); | 1338 | extern void ide_acpi_get_timing(ide_hwif_t *hwif); |
| 1339 | extern void ide_acpi_push_timing(ide_hwif_t *hwif); | 1339 | extern void ide_acpi_push_timing(ide_hwif_t *hwif); |
| 1340 | extern void ide_acpi_init(ide_hwif_t *hwif); | 1340 | extern void ide_acpi_init(ide_hwif_t *hwif); |
| 1341 | extern void ide_acpi_set_state(ide_hwif_t *hwif, int on); | ||
| 1341 | #else | 1342 | #else |
| 1342 | static inline int ide_acpi_exec_tfs(ide_drive_t *drive) { return 0; } | 1343 | static inline int ide_acpi_exec_tfs(ide_drive_t *drive) { return 0; } |
| 1343 | static inline void ide_acpi_get_timing(ide_hwif_t *hwif) { ; } | 1344 | static inline void ide_acpi_get_timing(ide_hwif_t *hwif) { ; } |
| 1344 | static inline void ide_acpi_push_timing(ide_hwif_t *hwif) { ; } | 1345 | static inline void ide_acpi_push_timing(ide_hwif_t *hwif) { ; } |
| 1345 | static inline void ide_acpi_init(ide_hwif_t *hwif) { ; } | 1346 | static inline void ide_acpi_init(ide_hwif_t *hwif) { ; } |
| 1347 | static inline void ide_acpi_set_state(ide_hwif_t *hwif, int on) {} | ||
| 1346 | #endif | 1348 | #endif |
| 1347 | 1349 | ||
| 1348 | extern int ide_hwif_request_regions(ide_hwif_t *hwif); | 1350 | extern int ide_hwif_request_regions(ide_hwif_t *hwif); |
