aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Walleij <triad@df.lth.se>2008-04-26 23:39:44 +0100
committerRussell King <rmk+kernel@arm.linux.org.uk>2008-04-28 17:03:34 +0100
commit26eed9a5c61edd93d88e147188d4feae6770174e (patch)
tree91e514baffe79035513185013d765fc4063a1c8c
parent136eb955773dc99f82e6e754038eb1c530e03fdf (diff)
[ARM] 5022/1: Race in ARM MMCI PL18x driver, V2
Updated version of 4446/1. This also drops the suggested comparison of host_remain for == 0, since that doesn't make sense (still works for us, too). We have verified that this patch solve race problems on atleast 2 archs at high frequencies. (Verbatim copy of old patch text below.) The patch below fixes a race condition in the ARM MMCI PL18x driver. If new data arrives in the FIFO while existing data is being read then we get a second iteration of the loop in mmci_pio_read. However host->size is not updated until after mmci_pio_read returns, so we get count = number of new bytes PLUS number of bytes already copied in the first iteration. This results in a FIFO underrun as we try and read mode data than is available. The fix is to compensating for data read on previous iterations when calculating the amount of data in the FIFO. Signed-off-by: Linus Walleij <triad@df.lth.se> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--drivers/mmc/host/mmci.c4
1 files changed, 3 insertions, 1 deletions
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 95244a7e735..626ac083f4e 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -213,9 +213,10 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema
void __iomem *base = host->base;
char *ptr = buffer;
u32 status;
+ int host_remain = host->size;
do {
- int count = host->size - (readl(base + MMCIFIFOCNT) << 2);
+ int count = host_remain - (readl(base + MMCIFIFOCNT) << 2);
if (count > remain)
count = remain;
@@ -227,6 +228,7 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema
ptr += count;
remain -= count;
+ host_remain -= count;
if (remain == 0)
break;