Skip to content

Commit

Permalink
mmc: msm_sdcc: Fix possible circular locking dependency warning
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Sahitya Tummala authored and David Brown committed Dec 20, 2010
1 parent 50bc0ef commit 62612cf
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 16 deletions.
49 changes: 33 additions & 16 deletions drivers/mmc/host/msm_sdcc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -273,6 +271,22 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
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)
Expand Down Expand Up @@ -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
*/
Expand Down
3 changes: 3 additions & 0 deletions drivers/mmc/host/msm_sdcc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 62612cf

Please sign in to comment.