diff options
author | Daniel Mack <daniel@caiaq.de> | 2010-04-27 06:24:42 -0400 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2010-05-17 05:44:13 -0400 |
commit | 4a31f2eff3b8fcf009db35f89eb222ed7835b6b9 (patch) | |
tree | d66ba9333096b167248ab0a10c3bde6c0a19cfd6 /drivers/mmc | |
parent | a2ef4562c25317f3d0731e79eb432db8ed9eb1ca (diff) |
ARM: mx3: Fix a race condition in mxcmmc
From cefcdab08d1c9636c4a7290bc2bbe937d051bce4 Mon Sep 17 00:00:00 2001
From: Volker Ernst <volker.ernst@txtr.com>
Date: Mon, 26 Apr 2010 22:51:07 +0200
Subject: [PATCH] ARM: mx3: Fix a race condition in mxcmmc
This fixes a race condition regarding interrupt bits in the SDHC
controller driver code.
In case of PIO-transfer it does not clear SDHC-status bit#11/12
in the INT-handler anymore. INT-handler might be called during
an ongoing PIO-data-transfer (with some other INT-flag set) and
PIO-transfer depends on these bits being set to detect the end
of the data-transfer. This also means that at the end of PIO-
transfer that PIO-software has to clear these bits itself.
However in case of DMA-transfer these bits have to be cleared
in the INT-handler, because they are used to generate INTs then.
Works solid, no more problems here, can transfer big files.
Signed-off-by: Volker Ernst <volker.ernst@txtr.com>
Acked-by: Daniel Mack <daniel@caiaq.de>
Cc: Andy Green <andy@warmcat.com>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/mxcmmc.c | 13 |
1 files changed, 12 insertions, 1 deletions
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 2c53024ee439..ec18e3b60342 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c | |||
@@ -489,6 +489,9 @@ static void mxcmci_datawork(struct work_struct *work) | |||
489 | struct mxcmci_host *host = container_of(work, struct mxcmci_host, | 489 | struct mxcmci_host *host = container_of(work, struct mxcmci_host, |
490 | datawork); | 490 | datawork); |
491 | int datastat = mxcmci_transfer_data(host); | 491 | int datastat = mxcmci_transfer_data(host); |
492 | |||
493 | writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE, | ||
494 | host->base + MMC_REG_STATUS); | ||
492 | mxcmci_finish_data(host, datastat); | 495 | mxcmci_finish_data(host, datastat); |
493 | 496 | ||
494 | if (host->req->stop) { | 497 | if (host->req->stop) { |
@@ -553,7 +556,8 @@ static irqreturn_t mxcmci_irq(int irq, void *devid) | |||
553 | u32 stat; | 556 | u32 stat; |
554 | 557 | ||
555 | stat = readl(host->base + MMC_REG_STATUS); | 558 | stat = readl(host->base + MMC_REG_STATUS); |
556 | writel(stat & ~STATUS_SDIO_INT_ACTIVE, host->base + MMC_REG_STATUS); | 559 | writel(stat & ~(STATUS_SDIO_INT_ACTIVE | STATUS_DATA_TRANS_DONE | |
560 | STATUS_WRITE_OP_DONE), host->base + MMC_REG_STATUS); | ||
557 | 561 | ||
558 | dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat); | 562 | dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat); |
559 | 563 | ||
@@ -561,6 +565,13 @@ static irqreturn_t mxcmci_irq(int irq, void *devid) | |||
561 | sdio_irq = (stat & STATUS_SDIO_INT_ACTIVE) && host->use_sdio; | 565 | sdio_irq = (stat & STATUS_SDIO_INT_ACTIVE) && host->use_sdio; |
562 | spin_unlock_irqrestore(&host->lock, flags); | 566 | spin_unlock_irqrestore(&host->lock, flags); |
563 | 567 | ||
568 | #ifdef HAS_DMA | ||
569 | if (mxcmci_use_dma(host) && | ||
570 | (stat & (STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE))) | ||
571 | writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE, | ||
572 | host->base + MMC_REG_STATUS); | ||
573 | #endif | ||
574 | |||
564 | if (sdio_irq) { | 575 | if (sdio_irq) { |
565 | writel(STATUS_SDIO_INT_ACTIVE, host->base + MMC_REG_STATUS); | 576 | writel(STATUS_SDIO_INT_ACTIVE, host->base + MMC_REG_STATUS); |
566 | mmc_signal_sdio_irq(host->mmc); | 577 | mmc_signal_sdio_irq(host->mmc); |