aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorSahitya Tummala <stummala@codeaurora.org>2010-12-08 04:33:03 -0500
committerDavid Brown <davidb@codeaurora.org>2010-12-20 15:28:30 -0500
commit62612cf9d97068dc75b48a7a3044ee907a3283ec (patch)
treed72ec00cc807f67c284babf83e6b738d125ed0af /drivers/mmc
parent50bc0ef42c76879f5d68a88c7063603dc0c9789b (diff)
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 1290d14c583..b147971a96e 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)
189} 189}
190 190
191static void 191static void
192msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, 192msmsdcc_dma_complete_tlet(unsigned long data)
193 unsigned int result,
194 struct msm_dmov_errdata *err)
195{ 193{
196 struct msmsdcc_dma_data *dma_data = 194 struct msmsdcc_host *host = (struct msmsdcc_host *)data;
197 container_of(cmd, struct msmsdcc_dma_data, hdr);
198 struct msmsdcc_host *host = dma_data->host;
199 unsigned long flags; 195 unsigned long flags;
200 struct mmc_request *mrq; 196 struct mmc_request *mrq;
197 struct msm_dmov_errdata err;
201 198
202 spin_lock_irqsave(&host->lock, flags); 199 spin_lock_irqsave(&host->lock, flags);
203 host->dma.active = 0; 200 host->dma.active = 0;
204 201
202 err = host->dma.err;
205 mrq = host->curr.mrq; 203 mrq = host->curr.mrq;
206 BUG_ON(!mrq); 204 BUG_ON(!mrq);
207 WARN_ON(!mrq->data); 205 WARN_ON(!mrq->data);
208 206
209 if (!(result & DMOV_RSLT_VALID)) { 207 if (!(host->dma.result & DMOV_RSLT_VALID)) {
210 pr_err("msmsdcc: Invalid DataMover result\n"); 208 pr_err("msmsdcc: Invalid DataMover result\n");
211 goto out; 209 goto out;
212 } 210 }
213 211
214 if (result & DMOV_RSLT_DONE) { 212 if (host->dma.result & DMOV_RSLT_DONE) {
215 host->curr.data_xfered = host->curr.xfer_size; 213 host->curr.data_xfered = host->curr.xfer_size;
216 } else { 214 } else {
217 /* Error or flush */ 215 /* Error or flush */
218 if (result & DMOV_RSLT_ERROR) 216 if (host->dma.result & DMOV_RSLT_ERROR)
219 pr_err("%s: DMA error (0x%.8x)\n", 217 pr_err("%s: DMA error (0x%.8x)\n",
220 mmc_hostname(host->mmc), result); 218 mmc_hostname(host->mmc), host->dma.result);
221 if (result & DMOV_RSLT_FLUSH) 219 if (host->dma.result & DMOV_RSLT_FLUSH)
222 pr_err("%s: DMA channel flushed (0x%.8x)\n", 220 pr_err("%s: DMA channel flushed (0x%.8x)\n",
223 mmc_hostname(host->mmc), result); 221 mmc_hostname(host->mmc), host->dma.result);
224 if (err) 222
225 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n", 223 pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
226 err->flush[0], err->flush[1], err->flush[2], 224 err.flush[0], err.flush[1], err.flush[2],
227 err->flush[3], err->flush[4], err->flush[5]); 225 err.flush[3], err.flush[4], err.flush[5]);
228 if (!mrq->data->error) 226 if (!mrq->data->error)
229 mrq->data->error = -EIO; 227 mrq->data->error = -EIO;
230 } 228 }
@@ -273,6 +271,22 @@ out:
273 return; 271 return;
274} 272}
275 273
274static void
275msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
276 unsigned int result,
277 struct msm_dmov_errdata *err)
278{
279 struct msmsdcc_dma_data *dma_data =
280 container_of(cmd, struct msmsdcc_dma_data, hdr);
281 struct msmsdcc_host *host = dma_data->host;
282
283 dma_data->result = result;
284 if (err)
285 memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
286
287 tasklet_schedule(&host->dma_tlet);
288}
289
276static int validate_dma(struct msmsdcc_host *host, struct mmc_data *data) 290static int validate_dma(struct msmsdcc_host *host, struct mmc_data *data)
277{ 291{
278 if (host->dma.channel == -1) 292 if (host->dma.channel == -1)
@@ -1118,6 +1132,9 @@ msmsdcc_probe(struct platform_device *pdev)
1118 host->dmares = dmares; 1132 host->dmares = dmares;
1119 spin_lock_init(&host->lock); 1133 spin_lock_init(&host->lock);
1120 1134
1135 tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
1136 (unsigned long)host);
1137
1121 /* 1138 /*
1122 * Setup DMA 1139 * Setup DMA
1123 */ 1140 */
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index ff2b0f74f6f..996990dfc7c 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -172,6 +172,8 @@ struct msmsdcc_dma_data {
172 struct msmsdcc_host *host; 172 struct msmsdcc_host *host;
173 int busy; /* Set if DM is busy */ 173 int busy; /* Set if DM is busy */
174 int active; 174 int active;
175 unsigned int result;
176 struct msm_dmov_errdata err;
175}; 177};
176 178
177struct msmsdcc_pio_data { 179struct msmsdcc_pio_data {
@@ -235,6 +237,7 @@ struct msmsdcc_host {
235 int cmdpoll; 237 int cmdpoll;
236 struct msmsdcc_stats stats; 238 struct msmsdcc_stats stats;
237 239
240 struct tasklet_struct dma_tlet;
238 /* Command parameters */ 241 /* Command parameters */
239 unsigned int cmd_timeout; 242 unsigned int cmd_timeout;
240 unsigned int cmd_pio_irqmask; 243 unsigned int cmd_pio_irqmask;