Skip to content

Commit

Permalink
ide: hook ACPI _PSx method to IDE power on/off
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Shaohua Li authored and Bartlomiej Zolnierkiewicz committed Oct 11, 2007
1 parent 8cb1f56 commit 5e32132
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 3 deletions.
4 changes: 3 additions & 1 deletion drivers/acpi/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,10 +262,12 @@ int acpi_bus_set_power(acpi_handle handle, int state)
printk(KERN_WARNING PREFIX
"Transitioning device [%s] to D%d\n",
device->pnp.bus_id, state);
else
else {
device->power.state = state;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Device [%s] transitioned to D%d\n",
device->pnp.bus_id, state));
}

return result;
}
Expand Down
42 changes: 42 additions & 0 deletions drivers/ide/ide-acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,46 @@ void ide_acpi_push_timing(ide_hwif_t *hwif)
}
EXPORT_SYMBOL_GPL(ide_acpi_push_timing);

/**
* ide_acpi_set_state - set the channel power state
* @hwif: target IDE interface
* @on: state, on/off
*
* This function executes the _PS0/_PS3 ACPI method to set the power state.
* ACPI spec requires _PS0 when IDE power on and _PS3 when power off
*/
void ide_acpi_set_state(ide_hwif_t *hwif, int on)
{
int unit;

if (ide_noacpi)
return;

DEBPRINT("ENTER:\n");

if (!hwif->acpidata) {
DEBPRINT("no ACPI data for %s\n", hwif->name);
return;
}
/* channel first and then drives for power on and verse versa for power off */
if (on)
acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D0);
for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit];

if (!drive->acpidata->obj_handle)
drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive);

if (drive->acpidata->obj_handle && drive->present) {
acpi_bus_set_power(drive->acpidata->obj_handle,
on? ACPI_STATE_D0: ACPI_STATE_D3);
}
}
if (!on)
acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D3);
}
EXPORT_SYMBOL_GPL(ide_acpi_set_state);

/**
* ide_acpi_init - initialize the ACPI link for an IDE interface
* @hwif: target IDE interface (channel)
Expand Down Expand Up @@ -679,6 +719,8 @@ void ide_acpi_init(ide_hwif_t *hwif)
return;
}

/* ACPI _PS0 before _STM */
ide_acpi_set_state(hwif, 1);
/*
* ACPI requires us to call _STM on startup
*/
Expand Down
14 changes: 12 additions & 2 deletions drivers/ide/ide.c
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,7 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
struct request rq;
struct request_pm_state rqpm;
ide_task_t args;
int ret;

/* Call ACPI _GTM only once */
if (!(drive->dn % 2))
Expand All @@ -931,7 +932,14 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
mesg.event = PM_EVENT_FREEZE;
rqpm.pm_state = mesg.event;

return ide_do_drive_cmd(drive, &rq, ide_wait);
ret = ide_do_drive_cmd(drive, &rq, ide_wait);
/* only call ACPI _PS3 after both drivers are suspended */
if (!ret && (((drive->dn % 2) && hwif->drives[0].present
&& hwif->drives[1].present)
|| !hwif->drives[0].present
|| !hwif->drives[1].present))
ide_acpi_set_state(hwif, 0);
return ret;
}

static int generic_ide_resume(struct device *dev)
Expand All @@ -944,8 +952,10 @@ static int generic_ide_resume(struct device *dev)
int err;

/* Call ACPI _STM only once */
if (!(drive->dn % 2))
if (!(drive->dn % 2)) {
ide_acpi_set_state(hwif, 1);
ide_acpi_push_timing(hwif);
}

ide_acpi_exec_tfs(drive);

Expand Down
2 changes: 2 additions & 0 deletions include/linux/ide.h
Original file line number Diff line number Diff line change
Expand Up @@ -1338,11 +1338,13 @@ 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);
extern void ide_acpi_set_state(ide_hwif_t *hwif, int on);
#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) { ; }
static inline void ide_acpi_set_state(ide_hwif_t *hwif, int on) {}
#endif

extern int ide_hwif_request_regions(ide_hwif_t *hwif);
Expand Down

0 comments on commit 5e32132

Please sign in to comment.