summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Nilsson XK <stefan.xk.nilsson@stericsson.com>2011-06-08 15:11:33 +0200
committersaid m bagheri <ebgheri@steludxu2848.(none)>2011-06-17 13:42:16 +0200
commit37b4ef58aad8bc2c86fdbb63b8cf298c41e0795b (patch)
tree30f2b4587ce9c732d8cc02d6c1b260bd77e685bc
parentfb2e0bdc985f8560568ad5b93a55e9155997edd4 (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
-rw-r--r--drivers/mmc/core/sdio_irq.c26
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;