From 4438ed377ed96b14c5b212dcbda68cdbe4ae45f9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 26 Feb 2010 20:23:26 +0100 Subject: [PATCH] mmc: omap_hsmmc: Fix the locking mess commit dcfb059a06c1f62061edaece74560f44925279f2 in tip. Conditional locking on (!in_interrupt()) is broken by design and there is no reason to keep the host->irq_lock across the call to mmc_request_done(). Also the host->protect_card magic hack does not depend on the context Fix the mess by dropping host->irq_lock before calling mmc_request_done(). Signed-off-by: Thomas Gleixner Signed-off-by: Paul Gortmaker --- drivers/mmc/host/omap_hsmmc.c | 70 ++++++++++++++++++----------------------- 1 files changed, 31 insertions(+), 39 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index e9caf69..076598a 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -806,14 +806,6 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd, if (host->use_dma) cmdreg |= DMA_EN; - /* - * In an interrupt context (i.e. STOP command), the spinlock is unlocked - * by the interrupt handler, otherwise (i.e. for a new request) it is - * unlocked here. - */ - if (!in_interrupt()) - spin_unlock_irqrestore(&host->irq_lock, host->flags); - OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg); OMAP_HSMMC_WRITE(host->base, CMD, cmdreg); } @@ -844,7 +836,9 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data) } host->mrq = NULL; + spin_unlock(&host->irq_lock); mmc_request_done(host->mmc, mrq); + spin_lock(&host->irq_lock); return; } @@ -861,7 +855,9 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data) if (!data->stop) { host->mrq = NULL; + spin_unlock(&host->irq_lock); mmc_request_done(host->mmc, data->mrq); + spin_lock(&host->irq_lock); return; } omap_hsmmc_start_command(host, data->stop, NULL); @@ -889,7 +885,9 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd) } if ((host->data == NULL && !host->response_busy) || cmd->error) { host->mrq = NULL; + spin_unlock(&host->irq_lock); mmc_request_done(host->mmc, cmd->mrq); + spin_lock(&host->irq_lock); } } @@ -1410,37 +1408,31 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req) struct omap_hsmmc_host *host = mmc_priv(mmc); int err; + spin_lock_irqsave(&host->irq_lock, host->flags); /* - * Prevent races with the interrupt handler because of unexpected - * interrupts, but not if we are already in interrupt context i.e. - * retries. + * Protect the card from I/O if there is a possibility + * it can be removed. */ - if (!in_interrupt()) { - spin_lock_irqsave(&host->irq_lock, host->flags); - /* - * Protect the card from I/O if there is a possibility - * it can be removed. - */ - if (host->protect_card) { - if (host->reqs_blocked < 3) { - /* - * Ensure the controller is left in a consistent - * state by resetting the command and data state - * machines. - */ - omap_hsmmc_reset_controller_fsm(host, SRD); - omap_hsmmc_reset_controller_fsm(host, SRC); - host->reqs_blocked += 1; - } - req->cmd->error = -EBADF; - if (req->data) - req->data->error = -EBADF; - spin_unlock_irqrestore(&host->irq_lock, host->flags); - mmc_request_done(mmc, req); - return; - } else if (host->reqs_blocked) - host->reqs_blocked = 0; - } + if (host->protect_card) { + if (host->reqs_blocked < 3) { + /* + * Ensure the controller is left in a consistent + * state by resetting the command and data state + * machines. + */ + omap_hsmmc_reset_controller_fsm(host, SRD); + omap_hsmmc_reset_controller_fsm(host, SRC); + host->reqs_blocked += 1; + } + req->cmd->error = -EBADF; + if (req->data) + req->data->error = -EBADF; + spin_unlock_irqrestore(&host->irq_lock, host->flags); + mmc_request_done(mmc, req); + return; + } else if (host->reqs_blocked) + host->reqs_blocked = 0; + WARN_ON(host->mrq != NULL); host->mrq = req; err = omap_hsmmc_prepare_data(host, req); @@ -1449,13 +1441,13 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req) if (req->data) req->data->error = err; host->mrq = NULL; - if (!in_interrupt()) - spin_unlock_irqrestore(&host->irq_lock, host->flags); + spin_unlock_irqrestore(&host->irq_lock, host->flags); mmc_request_done(mmc, req); return; } omap_hsmmc_start_command(host, req->cmd, req->data); + spin_unlock_irqrestore(&host->irq_lock, host->flags); } /* Routine to configure clock values. Exposed API to core */ -- 1.7.0.4