2008-12-29 22:27:37 +03:00
# include <linux/kernel.h>
# include <linux/ide.h>
int generic_ide_suspend ( struct device * dev , pm_message_t mesg )
{
2009-05-01 01:43:31 +04:00
ide_drive_t * drive = dev_get_drvdata ( dev ) ;
ide_drive_t * pair = ide_get_pair_dev ( drive ) ;
2009-01-06 19:20:52 +03:00
ide_hwif_t * hwif = drive - > hwif ;
2008-12-29 22:27:37 +03:00
struct request * rq ;
struct request_pm_state rqpm ;
int ret ;
2009-06-30 06:20:42 +04:00
if ( ide_port_acpi ( hwif ) ) {
/* call ACPI _GTM only once */
if ( ( drive - > dn & 1 ) = = 0 | | pair = = NULL )
ide_acpi_get_timing ( hwif ) ;
}
2008-12-29 22:27:37 +03:00
memset ( & rqpm , 0 , sizeof ( rqpm ) ) ;
rq = blk_get_request ( drive - > queue , READ , __GFP_WAIT ) ;
rq - > cmd_type = REQ_TYPE_PM_SUSPEND ;
2009-04-19 02:00:43 +04:00
rq - > special = & rqpm ;
2008-12-29 22:27:37 +03:00
rqpm . pm_step = IDE_PM_START_SUSPEND ;
if ( mesg . event = = PM_EVENT_PRETHAW )
mesg . event = PM_EVENT_FREEZE ;
rqpm . pm_state = mesg . event ;
ret = blk_execute_rq ( drive - > queue , NULL , rq , 0 ) ;
blk_put_request ( rq ) ;
2009-06-30 06:20:42 +04:00
if ( ret = = 0 & & ide_port_acpi ( hwif ) ) {
/* call ACPI _PS3 only after both devices are suspended */
if ( ( drive - > dn & 1 ) | | pair = = NULL )
ide_acpi_set_state ( hwif , 0 ) ;
}
2008-12-29 22:27:37 +03:00
return ret ;
}
int generic_ide_resume ( struct device * dev )
{
2009-05-01 01:43:31 +04:00
ide_drive_t * drive = dev_get_drvdata ( dev ) ;
ide_drive_t * pair = ide_get_pair_dev ( drive ) ;
2009-01-06 19:20:52 +03:00
ide_hwif_t * hwif = drive - > hwif ;
2008-12-29 22:27:37 +03:00
struct request * rq ;
struct request_pm_state rqpm ;
int err ;
2009-06-30 06:20:42 +04:00
if ( ide_port_acpi ( hwif ) ) {
/* call ACPI _PS0 / _STM only once */
if ( ( drive - > dn & 1 ) = = 0 | | pair = = NULL ) {
ide_acpi_set_state ( hwif , 1 ) ;
ide_acpi_push_timing ( hwif ) ;
}
2008-12-29 22:27:37 +03:00
2009-06-30 06:20:42 +04:00
ide_acpi_exec_tfs ( drive ) ;
}
2008-12-29 22:27:37 +03:00
memset ( & rqpm , 0 , sizeof ( rqpm ) ) ;
rq = blk_get_request ( drive - > queue , READ , __GFP_WAIT ) ;
rq - > cmd_type = REQ_TYPE_PM_RESUME ;
rq - > cmd_flags | = REQ_PREEMPT ;
2009-04-19 02:00:43 +04:00
rq - > special = & rqpm ;
2008-12-29 22:27:37 +03:00
rqpm . pm_step = IDE_PM_START_RESUME ;
rqpm . pm_state = PM_EVENT_ON ;
err = blk_execute_rq ( drive - > queue , NULL , rq , 1 ) ;
blk_put_request ( rq ) ;
if ( err = = 0 & & dev - > driver ) {
2009-01-06 19:20:53 +03:00
struct ide_driver * drv = to_ide_driver ( dev - > driver ) ;
2008-12-29 22:27:37 +03:00
if ( drv - > resume )
drv - > resume ( drive ) ;
}
return err ;
}
void ide_complete_power_step ( ide_drive_t * drive , struct request * rq )
{
2009-04-19 02:00:43 +04:00
struct request_pm_state * pm = rq - > special ;
2008-12-29 22:27:37 +03:00
# ifdef DEBUG_PM
printk ( KERN_INFO " %s: complete_power_step(step: %d) \n " ,
drive - > name , pm - > pm_step ) ;
# endif
if ( drive - > media ! = ide_disk )
return ;
switch ( pm - > pm_step ) {
case IDE_PM_FLUSH_CACHE : /* Suspend step 1 (flush cache) */
if ( pm - > pm_state = = PM_EVENT_FREEZE )
pm - > pm_step = IDE_PM_COMPLETED ;
else
pm - > pm_step = IDE_PM_STANDBY ;
break ;
case IDE_PM_STANDBY : /* Suspend step 2 (standby) */
pm - > pm_step = IDE_PM_COMPLETED ;
break ;
case IDE_PM_RESTORE_PIO : /* Resume step 1 (restore PIO) */
pm - > pm_step = IDE_PM_IDLE ;
break ;
case IDE_PM_IDLE : /* Resume step 2 (idle)*/
pm - > pm_step = IDE_PM_RESTORE_DMA ;
break ;
}
}
ide_startstop_t ide_start_power_step ( ide_drive_t * drive , struct request * rq )
{
2009-04-19 02:00:43 +04:00
struct request_pm_state * pm = rq - > special ;
struct ide_cmd cmd = { } ;
2008-12-29 22:27:37 +03:00
switch ( pm - > pm_step ) {
case IDE_PM_FLUSH_CACHE : /* Suspend step 1 (flush cache) */
if ( drive - > media ! = ide_disk )
break ;
/* Not supported? Switch to next step now. */
if ( ata_id_flush_enabled ( drive - > id ) = = 0 | |
( drive - > dev_flags & IDE_DFLAG_WCACHE ) = = 0 ) {
ide_complete_power_step ( drive , rq ) ;
return ide_stopped ;
}
if ( ata_id_flush_ext_enabled ( drive - > id ) )
2009-04-19 02:00:43 +04:00
cmd . tf . command = ATA_CMD_FLUSH_EXT ;
2008-12-29 22:27:37 +03:00
else
2009-04-19 02:00:43 +04:00
cmd . tf . command = ATA_CMD_FLUSH ;
2008-12-29 22:27:37 +03:00
goto out_do_tf ;
case IDE_PM_STANDBY : /* Suspend step 2 (standby) */
2009-04-19 02:00:43 +04:00
cmd . tf . command = ATA_CMD_STANDBYNOW1 ;
2008-12-29 22:27:37 +03:00
goto out_do_tf ;
case IDE_PM_RESTORE_PIO : /* Resume step 1 (restore PIO) */
ide_set_max_pio ( drive ) ;
/*
* skip IDE_PM_IDLE for ATAPI devices
*/
if ( drive - > media ! = ide_disk )
pm - > pm_step = IDE_PM_RESTORE_DMA ;
else
ide_complete_power_step ( drive , rq ) ;
return ide_stopped ;
case IDE_PM_IDLE : /* Resume step 2 (idle) */
2009-04-19 02:00:43 +04:00
cmd . tf . command = ATA_CMD_IDLEIMMEDIATE ;
2008-12-29 22:27:37 +03:00
goto out_do_tf ;
case IDE_PM_RESTORE_DMA : /* Resume step 3 (restore DMA) */
/*
* Right now , all we do is call ide_set_dma ( drive ) ,
* we could be smarter and check for current xfer_speed
* in struct drive etc . . .
*/
if ( drive - > hwif - > dma_ops = = NULL )
break ;
/*
* TODO : respect IDE_DFLAG_USING_DMA
*/
ide_set_dma ( drive ) ;
break ;
}
pm - > pm_step = IDE_PM_COMPLETED ;
2009-03-27 14:46:37 +03:00
2008-12-29 22:27:37 +03:00
return ide_stopped ;
out_do_tf :
2009-04-19 02:00:43 +04:00
cmd . valid . out . tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE ;
cmd . valid . in . tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE ;
cmd . protocol = ATA_PROT_NODATA ;
2009-03-27 14:46:37 +03:00
2009-04-19 02:00:43 +04:00
return do_rw_taskfile ( drive , & cmd ) ;
2008-12-29 22:27:37 +03:00
}
/**
2009-03-27 14:46:29 +03:00
* ide_complete_pm_rq - end the current Power Management request
2008-12-29 22:27:37 +03:00
* @ drive : target drive
* @ rq : request
*
* This function cleans up the current PM request and stops the queue
* if necessary .
*/
2009-03-27 14:46:29 +03:00
void ide_complete_pm_rq ( ide_drive_t * drive , struct request * rq )
2008-12-29 22:27:37 +03:00
{
struct request_queue * q = drive - > queue ;
2009-04-19 02:00:43 +04:00
struct request_pm_state * pm = rq - > special ;
2008-12-29 22:27:37 +03:00
unsigned long flags ;
2009-03-27 14:46:29 +03:00
ide_complete_power_step ( drive , rq ) ;
if ( pm - > pm_step ! = IDE_PM_COMPLETED )
return ;
2008-12-29 22:27:37 +03:00
# ifdef DEBUG_PM
printk ( " %s: completing PM request, %s \n " , drive - > name ,
blk_pm_suspend_request ( rq ) ? " suspend " : " resume " ) ;
# endif
spin_lock_irqsave ( q - > queue_lock , flags ) ;
2009-01-14 21:19:04 +03:00
if ( blk_pm_suspend_request ( rq ) )
2008-12-29 22:27:37 +03:00
blk_stop_queue ( q ) ;
2009-01-14 21:19:04 +03:00
else
2008-12-29 22:27:37 +03:00
drive - > dev_flags & = ~ IDE_DFLAG_BLOCKED ;
spin_unlock_irqrestore ( q - > queue_lock , flags ) ;
2009-01-06 19:20:50 +03:00
drive - > hwif - > rq = NULL ;
2008-12-29 22:27:37 +03:00
if ( blk_end_request ( rq , 0 , 0 ) )
BUG ( ) ;
}
void ide_check_pm_state ( ide_drive_t * drive , struct request * rq )
{
2009-04-19 02:00:43 +04:00
struct request_pm_state * pm = rq - > special ;
2008-12-29 22:27:37 +03:00
if ( blk_pm_suspend_request ( rq ) & &
pm - > pm_step = = IDE_PM_START_SUSPEND )
/* Mark drive blocked when starting the suspend sequence. */
drive - > dev_flags | = IDE_DFLAG_BLOCKED ;
else if ( blk_pm_resume_request ( rq ) & &
pm - > pm_step = = IDE_PM_START_RESUME ) {
/*
* The first thing we do on wakeup is to wait for BSY bit to
* go away ( with a looong timeout ) as a drive on this hwif may
* just be POSTing itself .
* We do that before even selecting as the " other " device on
* the bus may be broken enough to walk on our toes at this
* point .
*/
ide_hwif_t * hwif = drive - > hwif ;
2009-03-31 22:15:33 +04:00
const struct ide_tp_ops * tp_ops = hwif - > tp_ops ;
2009-01-14 21:19:04 +03:00
struct request_queue * q = drive - > queue ;
unsigned long flags ;
2008-12-29 22:27:37 +03:00
int rc ;
# ifdef DEBUG_PM
printk ( " %s: Wakeup request inited, waiting for !BSY... \n " , drive - > name ) ;
# endif
rc = ide_wait_not_busy ( hwif , 35000 ) ;
if ( rc )
printk ( KERN_WARNING " %s: bus not ready on wakeup \n " , drive - > name ) ;
2009-03-31 22:15:33 +04:00
tp_ops - > dev_select ( drive ) ;
tp_ops - > write_devctl ( hwif , ATA_DEVCTL_OBS ) ;
2008-12-29 22:27:37 +03:00
rc = ide_wait_not_busy ( hwif , 100000 ) ;
if ( rc )
printk ( KERN_WARNING " %s: drive not ready on wakeup \n " , drive - > name ) ;
2009-01-14 21:19:04 +03:00
spin_lock_irqsave ( q - > queue_lock , flags ) ;
blk_start_queue ( q ) ;
spin_unlock_irqrestore ( q - > queue_lock , flags ) ;
2008-12-29 22:27:37 +03:00
}
}