diff options
| author | Mark Lord <liml@rtr.ca> | 2008-05-02 02:09:14 -0400 | 
|---|---|---|
| committer | Jeff Garzik <jgarzik@redhat.com> | 2008-05-06 11:37:39 -0400 | 
| commit | 9b2c4e0bae854fb5e88c9cacc0dacf21631c5cb0 (patch) | |
| tree | 52f4be46f543e22c35d43806ad38764c165e9b3d /drivers/ata/sata_mv.c | |
| parent | 616d4a98ad8749ebe17a8fcac67df65c321350ac (diff) | |
sata_mv wait for empty+idle
When performing EH, it is recommended to wait for the EDMA engine
to empty out requests-in-progress before disabling EDMA.
Introduce code to poll the EDMA_STATUS register for idle/empty bits
before disabling EDMA.  For non-EH operation, this will normally exit
without delay, other than the register read.
A later series of patches may focus on eliminating this and various
other register reads (when possible) throughout the driver,
but for now we're focussing on solid reliablity.
Signed-off-by: Mark Lord <mlord@pobox.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata/sata_mv.c')
| -rw-r--r-- | drivers/ata/sata_mv.c | 20 | 
1 files changed, 20 insertions, 0 deletions
| diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 10ef9683f048..692996216b1a 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -888,6 +888,25 @@ static void mv_start_dma(struct ata_port *ap, void __iomem *port_mmio,  	}  } +static void mv_wait_for_edma_empty_idle(struct ata_port *ap) +{ +	void __iomem *port_mmio = mv_ap_base(ap); +	const u32 empty_idle = (EDMA_STATUS_CACHE_EMPTY | EDMA_STATUS_IDLE); +	const int per_loop = 5, timeout = (15 * 1000 / per_loop); +	int i; + +	/* +	 * Wait for the EDMA engine to finish transactions in progress. +	 */ +	for (i = 0; i < timeout; ++i) { +		u32 edma_stat = readl(port_mmio + EDMA_STATUS_OFS); +		if ((edma_stat & empty_idle) == empty_idle) +			break; +		udelay(per_loop); +	} +	/* ata_port_printk(ap, KERN_INFO, "%s: %u+ usecs\n", __func__, i); */ +} +  /**   *      mv_stop_edma_engine - Disable eDMA engine   *      @port_mmio: io base address @@ -920,6 +939,7 @@ static int mv_stop_edma(struct ata_port *ap)  	if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN))  		return 0;  	pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; +	mv_wait_for_edma_empty_idle(ap);  	if (mv_stop_edma_engine(port_mmio)) {  		ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n");  		return -EIO; | 
