aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host
diff options
context:
space:
mode:
authorKevin Liu <kliu5@marvell.com>2013-01-05 04:18:28 -0500
committerChris Ball <cjb@laptop.org>2013-02-11 13:28:50 -0500
commitb0a8dece55ebe792b394e0c73fa365ad24c3ec32 (patch)
tree6fb2a8d9836c133e6d286e835ada1a822f44541b /drivers/mmc/host
parent1a94715d4db7b71f825cd5585bc8d653eae1faf4 (diff)
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: Jialing Fu <jlfu@marvell.com> Signed-off-by: Kevin Liu <kliu5@marvell.com> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/host')
-rw-r--r--drivers/mmc/host/sdhci.c3
1 files changed, 3 insertions, 0 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 1b97fe2d70ab..1165376592b9 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2487,6 +2487,7 @@ int sdhci_suspend_host(struct sdhci_host *host)
2487 return ret; 2487 return ret;
2488 } 2488 }
2489 2489
2490 sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
2490 free_irq(host->irq, host); 2491 free_irq(host->irq, host);
2491 2492
2492 return ret; 2493 return ret;
@@ -3142,6 +3143,7 @@ int sdhci_add_host(struct sdhci_host *host)
3142#ifdef SDHCI_USE_LEDS_CLASS 3143#ifdef SDHCI_USE_LEDS_CLASS
3143reset: 3144reset:
3144 sdhci_reset(host, SDHCI_RESET_ALL); 3145 sdhci_reset(host, SDHCI_RESET_ALL);
3146 sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
3145 free_irq(host->irq, host); 3147 free_irq(host->irq, host);
3146#endif 3148#endif
3147untasklet: 3149untasklet:
@@ -3184,6 +3186,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
3184 if (!dead) 3186 if (!dead)
3185 sdhci_reset(host, SDHCI_RESET_ALL); 3187 sdhci_reset(host, SDHCI_RESET_ALL);
3186 3188
3189 sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
3187 free_irq(host->irq, host); 3190 free_irq(host->irq, host);
3188 3191
3189 del_timer_sync(&host->timer); 3192 del_timer_sync(&host->timer);