aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJavier Martin <javier.martin@vista-silicon.com>2012-09-07 06:43:37 -0400
committerChris Ball <cjb@laptop.org>2012-10-03 10:05:24 -0400
commitf6ad0a481342223b2e7ae9f55b154e14f1391ada (patch)
tree94559fe56544dae3fd145547da5536a5f002b7aa
parentc4c8eeb4df00aabb641553d6fbcd46f458e56cd9 (diff)
mmc: mxcmmc: fix bug that may block a data transfer forever
The problem can be easily reproduced using a script that loops copying a file in an SD card to another place in the same SD card and its related to read transfers. This only happens with DMA enabled. This is related to the fact that, when reading, an MMC irq signals the fact that all data from the SD card has been copied to the internal buffers. However, it doesn't signal whether the DMA transfer that is in charge of moving data from these internal buffers to RAM has finished or not. Thus, calling dmaengine_terminate_all() in the MMC irq routine can cancel an ongoing DMA transfer leaving some data in the internal buffers that produces an accumulative effect which, in the end, blocks a read data transfer forever. The following patch watches DMA irq for reading and MMC irqs for writing transfers. The 'dangerous' usage of dmaengine_terminate_all() is removed and a timeout of 10 seconds is added so that the MMC won't block forever anymore. Signed-off-by: Javier Martin <javier.martin@vista-silicon.com> Reviewed-by: Sascha Hauer <s.hauer@pengutronix.de> Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r--drivers/mmc/host/mxcmmc.c76
1 files changed, 70 insertions, 6 deletions
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index 28ed52d58f7f..fc42a2e088ee 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -44,6 +44,7 @@
44#include <mach/hardware.h> 44#include <mach/hardware.h>
45 45
46#define DRIVER_NAME "mxc-mmc" 46#define DRIVER_NAME "mxc-mmc"
47#define MXCMCI_TIMEOUT_MS 10000
47 48
48#define MMC_REG_STR_STP_CLK 0x00 49#define MMC_REG_STR_STP_CLK 0x00
49#define MMC_REG_STATUS 0x04 50#define MMC_REG_STATUS 0x04
@@ -150,6 +151,8 @@ struct mxcmci_host {
150 int dmareq; 151 int dmareq;
151 struct dma_slave_config dma_slave_config; 152 struct dma_slave_config dma_slave_config;
152 struct imx_dma_data dma_data; 153 struct imx_dma_data dma_data;
154
155 struct timer_list watchdog;
153}; 156};
154 157
155static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios); 158static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios);
@@ -271,9 +274,32 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
271 dmaengine_submit(host->desc); 274 dmaengine_submit(host->desc);
272 dma_async_issue_pending(host->dma); 275 dma_async_issue_pending(host->dma);
273 276
277 mod_timer(&host->watchdog, jiffies + msecs_to_jiffies(MXCMCI_TIMEOUT_MS));
278
274 return 0; 279 return 0;
275} 280}
276 281
282static void mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat);
283static void mxcmci_data_done(struct mxcmci_host *host, unsigned int stat);
284
285static void mxcmci_dma_callback(void *data)
286{
287 struct mxcmci_host *host = data;
288 u32 stat;
289
290 del_timer(&host->watchdog);
291
292 stat = readl(host->base + MMC_REG_STATUS);
293 writel(stat & ~STATUS_DATA_TRANS_DONE, host->base + MMC_REG_STATUS);
294
295 dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat);
296
297 if (stat & STATUS_READ_OP_DONE)
298 writel(STATUS_READ_OP_DONE, host->base + MMC_REG_STATUS);
299
300 mxcmci_data_done(host, stat);
301}
302
277static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd, 303static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd,
278 unsigned int cmdat) 304 unsigned int cmdat)
279{ 305{
@@ -305,8 +331,14 @@ static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd,
305 331
306 int_cntr = INT_END_CMD_RES_EN; 332 int_cntr = INT_END_CMD_RES_EN;
307 333
308 if (mxcmci_use_dma(host)) 334 if (mxcmci_use_dma(host)) {
309 int_cntr |= INT_READ_OP_EN | INT_WRITE_OP_DONE_EN; 335 if (host->dma_dir == DMA_FROM_DEVICE) {
336 host->desc->callback = mxcmci_dma_callback;
337 host->desc->callback_param = host;
338 } else {
339 int_cntr |= INT_WRITE_OP_DONE_EN;
340 }
341 }
310 342
311 spin_lock_irqsave(&host->lock, flags); 343 spin_lock_irqsave(&host->lock, flags);
312 if (host->use_sdio) 344 if (host->use_sdio)
@@ -345,11 +377,9 @@ static int mxcmci_finish_data(struct mxcmci_host *host, unsigned int stat)
345 struct mmc_data *data = host->data; 377 struct mmc_data *data = host->data;
346 int data_error; 378 int data_error;
347 379
348 if (mxcmci_use_dma(host)) { 380 if (mxcmci_use_dma(host))
349 dmaengine_terminate_all(host->dma);
350 dma_unmap_sg(host->dma->device->dev, data->sg, data->sg_len, 381 dma_unmap_sg(host->dma->device->dev, data->sg, data->sg_len,
351 host->dma_dir); 382 host->dma_dir);
352 }
353 383
354 if (stat & STATUS_ERR_MASK) { 384 if (stat & STATUS_ERR_MASK) {
355 dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n", 385 dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",
@@ -624,8 +654,10 @@ static irqreturn_t mxcmci_irq(int irq, void *devid)
624 mxcmci_cmd_done(host, stat); 654 mxcmci_cmd_done(host, stat);
625 655
626 if (mxcmci_use_dma(host) && 656 if (mxcmci_use_dma(host) &&
627 (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE))) 657 (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE))) {
658 del_timer(&host->watchdog);
628 mxcmci_data_done(host, stat); 659 mxcmci_data_done(host, stat);
660 }
629 661
630 if (host->default_irq_mask && 662 if (host->default_irq_mask &&
631 (stat & (STATUS_CARD_INSERTION | STATUS_CARD_REMOVAL))) 663 (stat & (STATUS_CARD_INSERTION | STATUS_CARD_REMOVAL)))
@@ -836,6 +868,34 @@ static bool filter(struct dma_chan *chan, void *param)
836 return true; 868 return true;
837} 869}
838 870
871static void mxcmci_watchdog(unsigned long data)
872{
873 struct mmc_host *mmc = (struct mmc_host *)data;
874 struct mxcmci_host *host = mmc_priv(mmc);
875 struct mmc_request *req = host->req;
876 unsigned int stat = readl(host->base + MMC_REG_STATUS);
877
878 if (host->dma_dir == DMA_FROM_DEVICE) {
879 dmaengine_terminate_all(host->dma);
880 dev_err(mmc_dev(host->mmc),
881 "%s: read time out (status = 0x%08x)\n",
882 __func__, stat);
883 } else {
884 dev_err(mmc_dev(host->mmc),
885 "%s: write time out (status = 0x%08x)\n",
886 __func__, stat);
887 mxcmci_softreset(host);
888 }
889
890 /* Mark transfer as erroneus and inform the upper layers */
891
892 host->data->error = -ETIMEDOUT;
893 host->req = NULL;
894 host->cmd = NULL;
895 host->data = NULL;
896 mmc_request_done(host->mmc, req);
897}
898
839static const struct mmc_host_ops mxcmci_ops = { 899static const struct mmc_host_ops mxcmci_ops = {
840 .request = mxcmci_request, 900 .request = mxcmci_request,
841 .set_ios = mxcmci_set_ios, 901 .set_ios = mxcmci_set_ios,
@@ -968,6 +1028,10 @@ static int mxcmci_probe(struct platform_device *pdev)
968 1028
969 mmc_add_host(mmc); 1029 mmc_add_host(mmc);
970 1030
1031 init_timer(&host->watchdog);
1032 host->watchdog.function = &mxcmci_watchdog;
1033 host->watchdog.data = (unsigned long)mmc;
1034
971 return 0; 1035 return 0;
972 1036
973out_free_irq: 1037out_free_irq: