aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/omap.c
diff options
context:
space:
mode:
authorJarkko Lavinen <jarkko.lavinen@nokia.com>2008-03-26 16:09:48 -0400
committerPierre Ossman <drzeus@drzeus.cx>2008-04-18 14:05:31 -0400
commit0fb4723d405111a13bb8f04e902eadf14402c7ba (patch)
tree55820793ff1b536442d7e7bdfd7bee1bbb95d477 /drivers/mmc/host/omap.c
parent7584d276d47a55afaeb614ed16cf306cbe2d6117 (diff)
MMC: OMAP: Move failing command abortion to workqueue
Abort failed command from workqueue rather than from an interrupt, allowing longer delays in abortion. Signed-off-by: Jarkko Lavinen <jarkko.lavinen@nokia.com> Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc/host/omap.c')
-rw-r--r--drivers/mmc/host/omap.c82
1 files changed, 49 insertions, 33 deletions
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index 8f393e8ed42f..7cc104ce0f07 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -134,8 +134,9 @@ struct mmc_omap_host {
134 unsigned char bus_mode; 134 unsigned char bus_mode;
135 unsigned char hw_bus_mode; 135 unsigned char hw_bus_mode;
136 136
137 struct work_struct cmd_abort; 137 struct work_struct cmd_abort_work;
138 struct timer_list cmd_timer; 138 unsigned abort:1;
139 struct timer_list cmd_abort_timer;
139 140
140 unsigned int sg_len; 141 unsigned int sg_len;
141 int sg_idx; 142 int sg_idx;
@@ -320,7 +321,7 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd)
320 if (host->data && !(host->data->flags & MMC_DATA_WRITE)) 321 if (host->data && !(host->data->flags & MMC_DATA_WRITE))
321 cmdreg |= 1 << 15; 322 cmdreg |= 1 << 15;
322 323
323 mod_timer(&host->cmd_timer, jiffies + HZ/2); 324 mod_timer(&host->cmd_abort_timer, jiffies + HZ/2);
324 325
325 OMAP_MMC_WRITE(host, CTO, 200); 326 OMAP_MMC_WRITE(host, CTO, 200);
326 OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff); 327 OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff);
@@ -381,7 +382,7 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
381} 382}
382 383
383static void 384static void
384mmc_omap_send_abort(struct mmc_omap_host *host) 385mmc_omap_send_abort(struct mmc_omap_host *host, int maxloops)
385{ 386{
386 struct mmc_omap_slot *slot = host->current_slot; 387 struct mmc_omap_slot *slot = host->current_slot;
387 unsigned int restarts, passes, timeout; 388 unsigned int restarts, passes, timeout;
@@ -390,7 +391,7 @@ mmc_omap_send_abort(struct mmc_omap_host *host)
390 /* Sending abort takes 80 clocks. Have some extra and round up */ 391 /* Sending abort takes 80 clocks. Have some extra and round up */
391 timeout = (120*1000000 + slot->fclk_freq - 1)/slot->fclk_freq; 392 timeout = (120*1000000 + slot->fclk_freq - 1)/slot->fclk_freq;
392 restarts = 0; 393 restarts = 0;
393 while (restarts < 10000) { 394 while (restarts < maxloops) {
394 OMAP_MMC_WRITE(host, STAT, 0xFFFF); 395 OMAP_MMC_WRITE(host, STAT, 0xFFFF);
395 OMAP_MMC_WRITE(host, CMD, (3 << 12) | (1 << 7)); 396 OMAP_MMC_WRITE(host, CMD, (3 << 12) | (1 << 7));
396 397
@@ -412,18 +413,13 @@ out:
412static void 413static void
413mmc_omap_abort_xfer(struct mmc_omap_host *host, struct mmc_data *data) 414mmc_omap_abort_xfer(struct mmc_omap_host *host, struct mmc_data *data)
414{ 415{
415 u16 ie;
416
417 if (host->dma_in_use) 416 if (host->dma_in_use)
418 mmc_omap_release_dma(host, data, 1); 417 mmc_omap_release_dma(host, data, 1);
419 418
420 host->data = NULL; 419 host->data = NULL;
421 host->sg_len = 0; 420 host->sg_len = 0;
422 421
423 ie = OMAP_MMC_READ(host, IE); 422 mmc_omap_send_abort(host, 10000);
424 OMAP_MMC_WRITE(host, IE, 0);
425 OMAP_MMC_WRITE(host, IE, ie);
426 mmc_omap_send_abort(host);
427} 423}
428 424
429static void 425static void
@@ -479,7 +475,7 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)
479{ 475{
480 host->cmd = NULL; 476 host->cmd = NULL;
481 477
482 del_timer(&host->cmd_timer); 478 del_timer(&host->cmd_abort_timer);
483 479
484 if (cmd->flags & MMC_RSP_PRESENT) { 480 if (cmd->flags & MMC_RSP_PRESENT) {
485 if (cmd->flags & MMC_RSP_136) { 481 if (cmd->flags & MMC_RSP_136) {
@@ -523,38 +519,48 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)
523static void mmc_omap_abort_command(struct work_struct *work) 519static void mmc_omap_abort_command(struct work_struct *work)
524{ 520{
525 struct mmc_omap_host *host = container_of(work, struct mmc_omap_host, 521 struct mmc_omap_host *host = container_of(work, struct mmc_omap_host,
526 cmd_abort); 522 cmd_abort_work);
527 u16 ie; 523 BUG_ON(!host->cmd);
528
529 ie = OMAP_MMC_READ(host, IE);
530 OMAP_MMC_WRITE(host, IE, 0);
531
532 if (!host->cmd) {
533 OMAP_MMC_WRITE(host, IE, ie);
534 return;
535 }
536 524
537 dev_dbg(mmc_dev(host->mmc), "Aborting stuck command CMD%d\n", 525 dev_dbg(mmc_dev(host->mmc), "Aborting stuck command CMD%d\n",
538 host->cmd->opcode); 526 host->cmd->opcode);
539 527
540 if (host->data && host->dma_in_use) 528 if (host->cmd->error == 0)
541 mmc_omap_release_dma(host, host->data, 1); 529 host->cmd->error = -ETIMEDOUT;
542 530
543 host->data = NULL; 531 if (host->data == NULL) {
544 host->sg_len = 0; 532 struct mmc_command *cmd;
533 struct mmc_host *mmc;
534
535 cmd = host->cmd;
536 host->cmd = NULL;
537 mmc_omap_send_abort(host, 10000);
538
539 host->mrq = NULL;
540 mmc = host->mmc;
541 mmc_omap_release_slot(host->current_slot);
542 mmc_request_done(mmc, cmd->mrq);
543 } else
544 mmc_omap_cmd_done(host, host->cmd);
545 545
546 mmc_omap_send_abort(host); 546 host->abort = 0;
547 host->cmd->error = -ETIMEDOUT; 547 enable_irq(host->irq);
548 mmc_omap_cmd_done(host, host->cmd);
549 OMAP_MMC_WRITE(host, IE, ie);
550} 548}
551 549
552static void 550static void
553mmc_omap_cmd_timer(unsigned long data) 551mmc_omap_cmd_timer(unsigned long data)
554{ 552{
555 struct mmc_omap_host *host = (struct mmc_omap_host *) data; 553 struct mmc_omap_host *host = (struct mmc_omap_host *) data;
554 unsigned long flags;
556 555
557 schedule_work(&host->cmd_abort); 556 spin_lock_irqsave(&host->slot_lock, flags);
557 if (host->cmd != NULL && !host->abort) {
558 OMAP_MMC_WRITE(host, IE, 0);
559 disable_irq(host->irq);
560 host->abort = 1;
561 schedule_work(&host->cmd_abort_work);
562 }
563 spin_unlock_irqrestore(&host->slot_lock, flags);
558} 564}
559 565
560/* PIO only */ 566/* PIO only */
@@ -728,6 +734,15 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
728 } 734 }
729 } 735 }
730 736
737 if (cmd_error && host->data) {
738 del_timer(&host->cmd_abort_timer);
739 host->abort = 1;
740 OMAP_MMC_WRITE(host, IE, 0);
741 disable_irq(host->irq);
742 schedule_work(&host->cmd_abort_work);
743 return IRQ_HANDLED;
744 }
745
731 if (end_command) 746 if (end_command)
732 mmc_omap_cmd_done(host, host->cmd); 747 mmc_omap_cmd_done(host, host->cmd);
733 if (host->data != NULL) { 748 if (host->data != NULL) {
@@ -1316,8 +1331,9 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
1316 goto err_free_mem_region; 1331 goto err_free_mem_region;
1317 } 1332 }
1318 1333
1319 INIT_WORK(&host->cmd_abort, mmc_omap_abort_command); 1334 INIT_WORK(&host->cmd_abort_work, mmc_omap_abort_command);
1320 setup_timer(&host->cmd_timer, mmc_omap_cmd_timer, (unsigned long) host); 1335 setup_timer(&host->cmd_abort_timer, mmc_omap_cmd_timer,
1336 (unsigned long) host);
1321 1337
1322 spin_lock_init(&host->dma_lock); 1338 spin_lock_init(&host->dma_lock);
1323 setup_timer(&host->dma_timer, mmc_omap_dma_timer, (unsigned long) host); 1339 setup_timer(&host->dma_timer, mmc_omap_dma_timer, (unsigned long) host);