Commit f945901f authored by Andreas Fenkart's avatar Andreas Fenkart Committed by Ulf Hansson

mmc: omap_hsmmc: abort runtime suspend if pending sdio irq detected

On multicores, an sdio irq handler could be running in parallel to
runtime suspend. In the worst case it could be waiting for the spinlock
held by the runtime suspend. When runtime suspend is complete and the
functional clock (fclk) turned off, the irq handler will continue and
cause a SIGBUS on the first register access.
Acked-by: default avatarBalaji T K <balajitk@ti.com>
Signed-off-by: default avatarAndreas Fenkart <afenkart@gmail.com>
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
parent 5a52b08b
...@@ -107,6 +107,9 @@ ...@@ -107,6 +107,9 @@
#define SRD (1 << 26) #define SRD (1 << 26)
#define SOFTRESET (1 << 1) #define SOFTRESET (1 << 1)
/* PSTATE */
#define DLEV_DAT(x) (1 << (20 + (x)))
/* Interrupt masks for IE and ISE register */ /* Interrupt masks for IE and ISE register */
#define CC_EN (1 << 0) #define CC_EN (1 << 0)
#define TC_EN (1 << 1) #define TC_EN (1 << 1)
...@@ -2387,6 +2390,7 @@ static int omap_hsmmc_runtime_suspend(struct device *dev) ...@@ -2387,6 +2390,7 @@ static int omap_hsmmc_runtime_suspend(struct device *dev)
{ {
struct omap_hsmmc_host *host; struct omap_hsmmc_host *host;
unsigned long flags; unsigned long flags;
int ret = 0;
host = platform_get_drvdata(to_platform_device(dev)); host = platform_get_drvdata(to_platform_device(dev));
omap_hsmmc_context_save(host); omap_hsmmc_context_save(host);
...@@ -2398,14 +2402,29 @@ static int omap_hsmmc_runtime_suspend(struct device *dev) ...@@ -2398,14 +2402,29 @@ static int omap_hsmmc_runtime_suspend(struct device *dev)
/* disable sdio irq handling to prevent race */ /* disable sdio irq handling to prevent race */
OMAP_HSMMC_WRITE(host->base, ISE, 0); OMAP_HSMMC_WRITE(host->base, ISE, 0);
OMAP_HSMMC_WRITE(host->base, IE, 0); OMAP_HSMMC_WRITE(host->base, IE, 0);
OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
if (!(OMAP_HSMMC_READ(host->base, PSTATE) & DLEV_DAT(1))) {
/*
* dat1 line low, pending sdio irq
* race condition: possible irq handler running on
* multi-core, abort
*/
dev_dbg(dev, "pending sdio irq, abort suspend\n");
OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
OMAP_HSMMC_WRITE(host->base, ISE, CIRQ_EN);
OMAP_HSMMC_WRITE(host->base, IE, CIRQ_EN);
pm_runtime_mark_last_busy(dev);
ret = -EBUSY;
goto abort;
}
WARN_ON(host->flags & HSMMC_WAKE_IRQ_ENABLED); WARN_ON(host->flags & HSMMC_WAKE_IRQ_ENABLED);
enable_irq(host->wake_irq); enable_irq(host->wake_irq);
host->flags |= HSMMC_WAKE_IRQ_ENABLED; host->flags |= HSMMC_WAKE_IRQ_ENABLED;
} }
abort:
spin_unlock_irqrestore(&host->irq_lock, flags); spin_unlock_irqrestore(&host->irq_lock, flags);
return 0; return ret;
} }
static int omap_hsmmc_runtime_resume(struct device *dev) static int omap_hsmmc_runtime_resume(struct device *dev)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment