2008-12-02 15:41:40

by Ben Dooks

[permalink] [raw]
Subject: [patch 6/8] SDHCI: Check DMA for overruns at end of transfer

At the end of a transfer, check that the DMA engine in the
SDHCI controller actually did what it was meant to and didn't
overrun the end of the buffer.

This seems to be triggered by a timeout during an CMD25 (multiple block
write) to a card. The mmc_block module then issues a command to find out
how much data was moved and this seems to end up triggering this DMA
check. The result is the card's queue generates an OOPS as the stack has
been trampled on due to the extra data transfered.

Signed-off-by: Ben Dooks <[email protected]>

Index: linux.git/drivers/mmc/host/sdhci.c
===================================================================
--- linux.git.orig/drivers/mmc/host/sdhci.c 2008-10-29 16:59:38.000000000 +0000
+++ linux.git/drivers/mmc/host/sdhci.c 2008-10-29 16:59:41.000000000 +0000
@@ -736,6 +736,23 @@ static void sdhci_set_transfer_mode(stru
writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE);
}

+static void shdci_check_dma_overrun(struct sdhci_host *host, struct mmc_data *data)
+{
+ u32 dma_pos = readl(host->ioaddr + SDHCI_DMA_ADDRESS);
+ u32 dma_start = sg_dma_address(data->sg);
+ u32 dma_end = dma_start + data->sg->length;
+
+ /* Test whether we ended up moving more data than
+ * was originally requested. */
+
+ if (dma_pos <= dma_end)
+ return;
+
+ printk(KERN_ERR "%s: dma overrun, dma %08x, req %08x..%08x\n",
+ mmc_hostname(host->mmc), dma_pos,
+ dma_start, dma_end);
+}
+
static void sdhci_finish_data(struct sdhci_host *host)
{
struct mmc_data *data;
@@ -749,6 +766,8 @@ static void sdhci_finish_data(struct sdh
if (host->flags & SDHCI_USE_ADMA)
sdhci_adma_table_post(host, data);
else {
+ shdci_check_dma_overrun(host, data);
+
dma_unmap_sg(mmc_dev(host->mmc), data->sg,
data->sg_len, (data->flags & MMC_DATA_READ) ?
DMA_FROM_DEVICE : DMA_TO_DEVICE);

--
Ben ([email protected], http://www.fluff.org/)

'a smiley only costs 4 bytes'


2008-12-21 13:49:39

by Pierre Ossman

[permalink] [raw]
Subject: Re: [patch 6/8] SDHCI: Check DMA for overruns at end of transfer

On Tue, 02 Dec 2008 15:40:24 +0000
Ben Dooks <[email protected]> wrote:

> At the end of a transfer, check that the DMA engine in the
> SDHCI controller actually did what it was meant to and didn't
> overrun the end of the buffer.
>
> This seems to be triggered by a timeout during an CMD25 (multiple block
> write) to a card. The mmc_block module then issues a command to find out
> how much data was moved and this seems to end up triggering this DMA
> check. The result is the card's queue generates an OOPS as the stack has
> been trampled on due to the extra data transfered.
>

Hmm... this is even stranger. CMD25 (write) will only read from main
memory and should not be able to mess up the stack. And it shouldn't be
the stack getting messed up anyway as that is not near the buffer
memory.

I still consider this a critical bug since it seems to be provoked by
hitting the timeout condition.

I'll queue up your patches (once the other things are fixed), but I
will add a patch disabling DMA on this controller until this is
properly understood and handled.

RGds
--
-- Pierre Ossman

WARNING: This correspondence is being monitored by the
Swedish government. Make sure your server uses encryption
for SMTP traffic and consider using PGP for end-to-end
encryption.


Attachments:
signature.asc (197.00 B)