On Wed, Dec 19, 2007 at 05:28:04PM +0200, ext Jarkko Lavinen wrote: > 0002-MMC-OMAP-Move-failing-command-abortion-to-workqueu.patch ... > Also if the controller if ever stuck, and mmc_omap_set_ios() is > called to change voltage or frequency, the initialization command > status could be polled for ever. Better to have have some limit > there. The limit was a fixed 100k limit in the busy loop, which is not accurate. It would better to have time limit for the worst case which occurs when sending 80 cycles at 400 kHz and takes about 200 microseconds, so limit the max time spend in the busy loop for some 250 microseconds. I moved the busy loop escape from 0002 to a new patch 0005: 0002-MMC-OMAP-Move-failing-command-abortion-to-workqueu.patch 0005-MMC-OMAP-Do-not-busy-wait-for-end-of-command-for-e.patch Cheers Jarkko Lavinen
>From 9a76b1b5099bbc868a441a20580185c45c830402 Mon Sep 17 00:00:00 2001 From: Jarkko Lavinen <jarkko.lavinen@xxxxxxxxx> Date: Fri, 21 Dec 2007 13:45:26 +0200 Subject: [PATCH] MMC: OMAP: Move failing command abortion to workqueue Abort failed command from workqueue rather than from an interrupt, allowing longer delays in aborion. Signed-off-by: Jarkko Lavinen <jarkko.lavinen@xxxxxxxxx> --- 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 98c886b..234b7d7 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -136,8 +136,9 @@ struct mmc_omap_host { unsigned char bus_mode; unsigned char hw_bus_mode; - struct work_struct cmd_abort; - struct timer_list cmd_timer; + struct work_struct cmd_abort_work; + unsigned abort:1; + struct timer_list cmd_abort_timer; unsigned int sg_len; int sg_idx; @@ -335,7 +336,7 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd) if (host->data && !(host->data->flags & MMC_DATA_WRITE)) cmdreg |= 1 << 15; - mod_timer(&host->cmd_timer, jiffies + HZ/2); + mod_timer(&host->cmd_abort_timer, jiffies + HZ/2); OMAP_MMC_WRITE(host, CTO, 200); OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff); @@ -396,7 +397,7 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) } static void -mmc_omap_send_abort(struct mmc_omap_host *host) +mmc_omap_send_abort(struct mmc_omap_host *host, int maxloops) { struct mmc_omap_slot *slot = host->current_slot; unsigned int restarts, passes, timeout; @@ -405,7 +406,7 @@ mmc_omap_send_abort(struct mmc_omap_host *host) /* Sending abort takes 80 clocks. Have some extra and round up */ timeout = (120*1000000 + slot->fclk_freq - 1)/slot->fclk_freq; restarts = 0; - while (restarts < 10000) { + while (restarts < maxloops) { OMAP_MMC_WRITE(host, STAT, 0xFFFF); OMAP_MMC_WRITE(host, CMD, (3 << 12) | (1 << 7)); @@ -427,18 +428,13 @@ out: static void mmc_omap_abort_xfer(struct mmc_omap_host *host, struct mmc_data *data) { - u16 ie; - if (host->dma_in_use) mmc_omap_release_dma(host, data, 1); host->data = NULL; host->sg_len = 0; - ie = OMAP_MMC_READ(host, IE); - OMAP_MMC_WRITE(host, IE, 0); - OMAP_MMC_WRITE(host, IE, ie); - mmc_omap_send_abort(host); + mmc_omap_send_abort(host, 10000); } static void @@ -494,7 +490,7 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd) { host->cmd = NULL; - del_timer(&host->cmd_timer); + del_timer(&host->cmd_abort_timer); if (cmd->flags & MMC_RSP_PRESENT) { if (cmd->flags & MMC_RSP_136) { @@ -538,38 +534,48 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd) static void mmc_omap_abort_command(struct work_struct *work) { struct mmc_omap_host *host = container_of(work, struct mmc_omap_host, - cmd_abort); - u16 ie; - - ie = OMAP_MMC_READ(host, IE); - OMAP_MMC_WRITE(host, IE, 0); - - if (!host->cmd) { - OMAP_MMC_WRITE(host, IE, ie); - return; - } + cmd_abort_work); + BUG_ON(!host->cmd); dev_dbg(mmc_dev(host->mmc), "Aborting stuck command CMD%d\n", host->cmd->opcode); - if (host->data && host->dma_in_use) - mmc_omap_release_dma(host, host->data, 1); + if (host->cmd->error == 0) + host->cmd->error = -ETIMEDOUT; - host->data = NULL; - host->sg_len = 0; + if (host->data == NULL) { + struct mmc_command *cmd; + struct mmc_host *mmc; + + cmd = host->cmd; + host->cmd = NULL; + mmc_omap_send_abort(host, 10000); + + host->mrq = NULL; + mmc = host->mmc; + mmc_omap_release_slot(host->current_slot); + mmc_request_done(mmc, cmd->mrq); + } else + mmc_omap_cmd_done(host, host->cmd); - mmc_omap_send_abort(host); - host->cmd->error = -ETIMEDOUT; - mmc_omap_cmd_done(host, host->cmd); - OMAP_MMC_WRITE(host, IE, ie); + host->abort = 0; + enable_irq(host->irq); } static void mmc_omap_cmd_timer(unsigned long data) { struct mmc_omap_host *host = (struct mmc_omap_host *) data; + unsigned long flags; - schedule_work(&host->cmd_abort); + spin_lock_irqsave(&host->slot_lock, flags); + if (host->cmd != NULL && !host->abort) { + OMAP_MMC_WRITE(host, IE, 0); + disable_irq(host->irq); + host->abort = 1; + schedule_work(&host->cmd_abort_work); + } + spin_unlock_irqrestore(&host->slot_lock, flags); } /* PIO only */ @@ -746,6 +752,15 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) } } + if (cmd_error && host->data) { + del_timer(&host->cmd_abort_timer); + host->abort = 1; + OMAP_MMC_WRITE(host, IE, 0); + disable_irq(host->irq); + schedule_work(&host->cmd_abort_work); + return IRQ_HANDLED; + } + if (end_command) mmc_omap_cmd_done(host, host->cmd); if (host->data != NULL) { @@ -1356,8 +1371,9 @@ static int __init mmc_omap_probe(struct platform_device *pdev) goto err_free_mem_region; } - INIT_WORK(&host->cmd_abort, mmc_omap_abort_command); - setup_timer(&host->cmd_timer, mmc_omap_cmd_timer, (unsigned long) host); + INIT_WORK(&host->cmd_abort_work, mmc_omap_abort_command); + setup_timer(&host->cmd_abort_timer, mmc_omap_cmd_timer, + (unsigned long) host); spin_lock_init(&host->dma_lock); setup_timer(&host->dma_timer, mmc_omap_dma_timer, (unsigned long) host); -- 1.5.3.7
>From d5f015647d38b18c492437e02f0c50a1e3859161 Mon Sep 17 00:00:00 2001 From: Jarkko Lavinen <jarkko.lavinen@xxxxxxxxx> Date: Fri, 21 Dec 2007 13:59:48 +0200 Subject: [PATCH] MMC: OMAP: Do not busy wait for end of command for ever Signed-off-by: Jarkko Lavinen <jarkko.lavinen@xxxxxxxxx> --- drivers/mmc/host/omap.c | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-) diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 47150a2..60e3fd7 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -1294,11 +1294,17 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) OMAP_MMC_WRITE(host, CON, dsor); slot->saved_con = dsor; if (ios->power_mode == MMC_POWER_ON) { + /* worst case at 400kHz, 80 cycles makes 200 microsecs */ + int usecs = 250; + /* Send clock cycles, poll completion */ OMAP_MMC_WRITE(host, IE, 0); OMAP_MMC_WRITE(host, STAT, 0xffff); OMAP_MMC_WRITE(host, CMD, 1 << 7); - while ((OMAP_MMC_READ(host, STAT) & 1) == 0); + while (usecs > 0 && (OMAP_MMC_READ(host, STAT) & 1) == 0) { + udelay(1); + usecs--; + } OMAP_MMC_WRITE(host, STAT, 1); } -- 1.5.3.7