diff options
| author | Jarkko Lavinen <jarkko.lavinen@nokia.com> | 2008-03-26 16:09:48 -0400 |
|---|---|---|
| committer | Pierre Ossman <drzeus@drzeus.cx> | 2008-04-18 14:05:31 -0400 |
| commit | 0fb4723d405111a13bb8f04e902eadf14402c7ba (patch) | |
| tree | 55820793ff1b536442d7e7bdfd7bee1bbb95d477 | |
| parent | 7584d276d47a55afaeb614ed16cf306cbe2d6117 (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>
| -rw-r--r-- | drivers/mmc/host/omap.c | 82 |
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 | ||
| 383 | static void | 384 | static void |
| 384 | mmc_omap_send_abort(struct mmc_omap_host *host) | 385 | mmc_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: | |||
| 412 | static void | 413 | static void |
| 413 | mmc_omap_abort_xfer(struct mmc_omap_host *host, struct mmc_data *data) | 414 | mmc_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 | ||
| 429 | static void | 425 | static 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) | |||
| 523 | static void mmc_omap_abort_command(struct work_struct *work) | 519 | static 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 | ||
| 552 | static void | 550 | static void |
| 553 | mmc_omap_cmd_timer(unsigned long data) | 551 | mmc_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); |
