Commit 5e32132befa5d2cefadf3141fee0bbb40cd11f0e

Authored by Shaohua Li
Committed by Bartlomiej Zolnierkiewicz
1 parent 8cb1f567f4

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>

Showing 4 changed files with 59 additions and 3 deletions Side-by-side Diff

... ... @@ -262,10 +262,12 @@
262 262 printk(KERN_WARNING PREFIX
263 263 "Transitioning device [%s] to D%d\n",
264 264 device->pnp.bus_id, state);
265   - else
  265 + else {
  266 + device->power.state = state;
266 267 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
267 268 "Device [%s] transitioned to D%d\n",
268 269 device->pnp.bus_id, state));
  270 + }
269 271  
270 272 return result;
271 273 }
drivers/ide/ide-acpi.c
... ... @@ -612,6 +612,46 @@
612 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 655 * ide_acpi_init - initialize the ACPI link for an IDE interface
616 656 * @hwif: target IDE interface (channel)
617 657 *
... ... @@ -679,6 +719,8 @@
679 719 return;
680 720 }
681 721  
  722 + /* ACPI _PS0 before _STM */
  723 + ide_acpi_set_state(hwif, 1);
682 724 /*
683 725 * ACPI requires us to call _STM on startup
684 726 */
... ... @@ -915,6 +915,7 @@
915 915 struct request rq;
916 916 struct request_pm_state rqpm;
917 917 ide_task_t args;
  918 + int ret;
918 919  
919 920 /* Call ACPI _GTM only once */
920 921 if (!(drive->dn % 2))
... ... @@ -931,7 +932,14 @@
931 932 mesg.event = PM_EVENT_FREEZE;
932 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 945 static int generic_ide_resume(struct device *dev)
938 946  
... ... @@ -944,8 +952,10 @@
944 952 int err;
945 953  
946 954 /* Call ACPI _STM only once */
947   - if (!(drive->dn % 2))
  955 + if (!(drive->dn % 2)) {
  956 + ide_acpi_set_state(hwif, 1);
948 957 ide_acpi_push_timing(hwif);
  958 + }
949 959  
950 960 ide_acpi_exec_tfs(drive);
951 961  
... ... @@ -1338,11 +1338,13 @@
1338 1338 extern void ide_acpi_get_timing(ide_hwif_t *hwif);
1339 1339 extern void ide_acpi_push_timing(ide_hwif_t *hwif);
1340 1340 extern void ide_acpi_init(ide_hwif_t *hwif);
  1341 +extern void ide_acpi_set_state(ide_hwif_t *hwif, int on);
1341 1342 #else
1342 1343 static inline int ide_acpi_exec_tfs(ide_drive_t *drive) { return 0; }
1343 1344 static inline void ide_acpi_get_timing(ide_hwif_t *hwif) { ; }
1344 1345 static inline void ide_acpi_push_timing(ide_hwif_t *hwif) { ; }
1345 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 1348 #endif
1347 1349  
1348 1350 extern int ide_hwif_request_regions(ide_hwif_t *hwif);