Commit b0a8dece authored by Kevin Liu's avatar Kevin Liu Committed by Chris Ball

mmc: sdhci: disable interrupt before free_irq

Current code missed disabling interrupts before free irq which is shared.

Notice below comments for function free_irq (kernel/irq/manage.c):
On a shared IRQ the caller must ensure the interrupt is disabled
on the card it drives before calling this function.

Original code has below issue during suspend/resume when multiple SD
hosts share the same IRQ:
1. Assume there are two hosts (host1 for emmc while host2 for sd) share
the same mmc irq.
2. When system suspend, host2 will be suspended before host1.
So the sequence is below:
	step1: irq handler for host2 removed ->
	step2: irq handler for host1 removed and irq disabled ->
	... system suspended ...
	... system resumed ...
	step3: irq enabled and the irq handler for host1 restored ->
	step4: irq handler for host2 restored
3. So there is the buggy time slot that the irq is enabled but the irq
handler for host2 is removed. Then host2 interrupt can be triggered
but can't be handled at that moment.
Signed-off-by: default avatarJialing Fu <jlfu@marvell.com>
Signed-off-by: default avatarKevin Liu <kliu5@marvell.com>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent 1a94715d
...@@ -2487,6 +2487,7 @@ int sdhci_suspend_host(struct sdhci_host *host) ...@@ -2487,6 +2487,7 @@ int sdhci_suspend_host(struct sdhci_host *host)
return ret; return ret;
} }
sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
free_irq(host->irq, host); free_irq(host->irq, host);
return ret; return ret;
...@@ -3142,6 +3143,7 @@ int sdhci_add_host(struct sdhci_host *host) ...@@ -3142,6 +3143,7 @@ int sdhci_add_host(struct sdhci_host *host)
#ifdef SDHCI_USE_LEDS_CLASS #ifdef SDHCI_USE_LEDS_CLASS
reset: reset:
sdhci_reset(host, SDHCI_RESET_ALL); sdhci_reset(host, SDHCI_RESET_ALL);
sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
free_irq(host->irq, host); free_irq(host->irq, host);
#endif #endif
untasklet: untasklet:
...@@ -3184,6 +3186,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) ...@@ -3184,6 +3186,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
if (!dead) if (!dead)
sdhci_reset(host, SDHCI_RESET_ALL); sdhci_reset(host, SDHCI_RESET_ALL);
sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
free_irq(host->irq, host); free_irq(host->irq, host);
del_timer_sync(&host->timer); del_timer_sync(&host->timer);
......
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