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 | |
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')
-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, | |||
888 | } | 888 | } |
889 | } | 889 | } |
890 | 890 | ||
891 | static void mv_wait_for_edma_empty_idle(struct ata_port *ap) | ||
892 | { | ||
893 | void __iomem *port_mmio = mv_ap_base(ap); | ||
894 | const u32 empty_idle = (EDMA_STATUS_CACHE_EMPTY | EDMA_STATUS_IDLE); | ||
895 | const int per_loop = 5, timeout = (15 * 1000 / per_loop); | ||
896 | int i; | ||
897 | |||
898 | /* | ||
899 | * Wait for the EDMA engine to finish transactions in progress. | ||
900 | */ | ||
901 | for (i = 0; i < timeout; ++i) { | ||
902 | u32 edma_stat = readl(port_mmio + EDMA_STATUS_OFS); | ||
903 | if ((edma_stat & empty_idle) == empty_idle) | ||
904 | break; | ||
905 | udelay(per_loop); | ||
906 | } | ||
907 | /* ata_port_printk(ap, KERN_INFO, "%s: %u+ usecs\n", __func__, i); */ | ||
908 | } | ||
909 | |||
891 | /** | 910 | /** |
892 | * mv_stop_edma_engine - Disable eDMA engine | 911 | * mv_stop_edma_engine - Disable eDMA engine |
893 | * @port_mmio: io base address | 912 | * @port_mmio: io base address |
@@ -920,6 +939,7 @@ static int mv_stop_edma(struct ata_port *ap) | |||
920 | if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN)) | 939 | if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN)) |
921 | return 0; | 940 | return 0; |
922 | pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; | 941 | pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; |
942 | mv_wait_for_edma_empty_idle(ap); | ||
923 | if (mv_stop_edma_engine(port_mmio)) { | 943 | if (mv_stop_edma_engine(port_mmio)) { |
924 | ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n"); | 944 | ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n"); |
925 | return -EIO; | 945 | return -EIO; |