diff options
author | Stefan Nilsson XK <stefan.xk.nilsson@stericsson.com> | 2011-06-08 15:11:33 +0200 |
---|---|---|
committer | said m bagheri <ebgheri@steludxu2848.(none)> | 2011-06-17 13:42:16 +0200 |
commit | 37b4ef58aad8bc2c86fdbb63b8cf298c41e0795b (patch) | |
tree | 30f2b4587ce9c732d8cc02d6c1b260bd77e685bc /drivers/mmc | |
parent | fb2e0bdc985f8560568ad5b93a55e9155997edd4 (diff) |
SDIO: Fix deadlock when destroying IRQ work queue
This patch fixes a deadlock in sdio_release_irq. If there was work
scheduled that had not yet claimed the mmc host at the point of calling
sdio_release_irq, then it never could claim the host since the caller
of sdio_release_irq already had claimed the host.
Now the host is released to allow the work queue to flush out any
pending work. A check is also added to make sure IRQ:s are not
enabled as a consequence of this cleanup work.
ST-Ericsson Linux next: NA
ST-Ericsson ID: ER339608
ST-Ericsson FOSS-OUT ID: Trivial
Change-Id: I700719e10c779d69561f0cc66b1df5fb41cbd21e
Signed-off-by: Stefan Nilsson XK <stefan.xk.nilsson@stericsson.com>
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/24675
Reviewed-by: Ulf HANSSON <ulf.hansson@stericsson.com>
Reviewed-by: QATEST
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/core/sdio_irq.c | 26 |
1 files changed, 24 insertions, 2 deletions
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index 7502ba3ebda..ff6bdaef680 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -104,9 +104,13 @@ static void sdio_irq_work_func(struct work_struct *work) */ mmc_claim_host(host); - ret = process_sdio_pending_irqs(host->card); + /* Check if there are any subscribers to IRQ:s */ + if (!host->sdio_irqs) { + mmc_release_host(host); + return; + } - mmc_release_host(host); + ret = process_sdio_pending_irqs(host->card); if (host->caps & MMC_CAP_SDIO_IRQ) host->ops->enable_sdio_irq(host, true); @@ -127,6 +131,8 @@ static void sdio_irq_work_func(struct work_struct *work) &host->sdio_irq_work, msecs_to_jiffies(host->sdio_poll_period)); } + + mmc_release_host(host); } static int sdio_card_irq_get(struct mmc_card *card) @@ -173,9 +179,25 @@ static int sdio_card_irq_put(struct mmc_card *card) if (!--host->sdio_irqs) { host->ops->enable_sdio_irq(host, false); + + /* + * Temporarily release the host in order to complete + * any pending work before destroying the work queue. + * + * There is a theroetical chance of messing up here, + * if a calling driver is waiting to claim the host + * in order to claim an SDIO IRQ, and that call falls through + * while releasing the IRQ:s here, there is no guarantee + * that that IRQ:s will be reliably turned on or off. + * This will be fixed in a coming patch, but this solution + * is deemed good enough for now since it fixes an obvious + * error and the failing case deemed not likely to happen. + */ + mmc_release_host(card->host); cancel_delayed_work_sync(&host->sdio_irq_work); destroy_workqueue(host->sdio_irq_workqueue); host->sdio_irq_workqueue = NULL; + mmc_claim_host(card->host); } return 0; |