summaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorSahitya Tummala <stummala@codeaurora.org>2010-12-08 15:03:03 +0530
committerDavid Brown <davidb@codeaurora.org>2010-12-20 12:28:30 -0800
commit62612cf9d97068dc75b48a7a3044ee907a3283ec (patch)
treed72ec00cc807f67c284babf83e6b738d125ed0af /drivers/mmc
parent50bc0ef42c76879f5d68a88c7063603dc0c9789b (diff)
downloadlinux-62612cf9d97068dc75b48a7a3044ee907a3283ec.tar.bz2
mmc: msm_sdcc: Fix possible circular locking dependency warning
In the context of request processing thread, data mover lock is acquired after the host lock. In another context, in the completion handler of data mover the locks are acquired in the reverse order, resulting in possible circular lock dependency warning. Hence, schedule a tasklet to process the dma completion so as to avoid nested locks. Signed-off-by: Sahitya Tummala <stummala@codeaurora.org> Signed-off-by: David Brown <davidb@codeaurora.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/msm_sdcc.c49
-rw-r--r--drivers/mmc/host/msm_sdcc.h3
2 files changed, 36 insertions, 16 deletions
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 1290d14c5839..b147971a96ef 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -189,42 +189,40 @@ msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
}
static void
-msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
- unsigned int result,
- struct msm_dmov_errdata *err)
+msmsdcc_dma_complete_tlet(unsigned long data)
{
- struct msmsdcc_dma_data *dma_data =
- container_of(cmd, struct msmsdcc_dma_data, hdr);
- struct msmsdcc_host *host = dma_data->host;
+ struct msmsdcc_host *host = (struct msmsdcc_host *)data;
unsigned long flags;
struct mmc_request *mrq;
+ struct msm_dmov_errdata err;
spin_lock_irqsave(&host->lock, flags);
host->dma.active = 0;
+ err = host->dma.err;
mrq = host->curr.mrq;
BUG_ON(!mrq);
WARN_ON(!mrq->data);
- if (!(result & DMOV_RSLT_VALID)) {
+ if (!(host->dma.result & DMOV_RSLT_VALID)) {
pr_err("msmsdcc: Invalid DataMover result\n");
goto out;
}
- if (result & DMOV_RSLT_DONE) {
+ if (host->dma.result & DMOV_RSLT_DONE) {
host->curr.data_xfered = host->curr.xfer_size;
} else {
/* Error or flush */
- if (result & DMOV_RSLT_ERROR)
+ if (host->dma.result & DMOV_RSLT_ERROR)
pr_err("%s: DMA error (0x%.8x)\n",
- mmc_hostname(host->mmc), result);
- if (result & DMOV_RSLT_FLUSH)
+ mmc_hostname(host->mmc), host->dma.result);
+ if (host->dma.result & DMOV_RSLT_FLUSH)
pr_err("%s: DMA channel flushed (0x%.8x)\n",
- mmc_hostname(host->mmc), result);
- if (err)
- pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
- err->flush[0], err->flush[1], err->flush[2],
- err->flush[3], err->flush[4], err->flush[5]);
+ mmc_hostname(host->mmc), host->dma.result);
+
+ pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
+ err.flush[0], err.flush[1], err.flush[2],
+ err.flush[3], err.flush[4], err.flush[5]);
if (!mrq->data->error)
mrq->data->error = -EIO;
}
@@ -273,6 +271,22 @@ out:
return;
}
+static void
+msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
+ unsigned int result,
+ struct msm_dmov_errdata *err)
+{
+ struct msmsdcc_dma_data *dma_data =
+ container_of(cmd, struct msmsdcc_dma_data, hdr);
+ struct msmsdcc_host *host = dma_data->host;
+
+ dma_data->result = result;
+ if (err)
+ memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
+
+ tasklet_schedule(&host->dma_tlet);
+}
+
static int validate_dma(struct msmsdcc_host *host, struct mmc_data *data)
{
if (host->dma.channel == -1)
@@ -1118,6 +1132,9 @@ msmsdcc_probe(struct platform_device *pdev)
host->dmares = dmares;
spin_lock_init(&host->lock);
+ tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
+ (unsigned long)host);
+
/*
* Setup DMA
*/
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index ff2b0f74f6f4..996990dfc7cc 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -172,6 +172,8 @@ struct msmsdcc_dma_data {
struct msmsdcc_host *host;
int busy; /* Set if DM is busy */
int active;
+ unsigned int result;
+ struct msm_dmov_errdata err;
};
struct msmsdcc_pio_data {
@@ -235,6 +237,7 @@ struct msmsdcc_host {
int cmdpoll;
struct msmsdcc_stats stats;
+ struct tasklet_struct dma_tlet;
/* Command parameters */
unsigned int cmd_timeout;
unsigned int cmd_pio_irqmask;