diff options
author | Alexander Stein <alexander.stein@systec-electronic.com> | 2012-03-14 04:52:10 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2012-03-27 12:20:13 -0400 |
commit | 6379b2375a0c5a6ad437616a4018e6b8fd95e97c (patch) | |
tree | f30a7782e36bff0ef4784547e1146d782af1c8b1 /drivers | |
parent | e6039832bed9a9b967796d7021f17f25b625b616 (diff) |
mmc: sdhci: check interrupt flags in ISR again
When using MSI it is possible that a new MSI is sent while an earlier
MSI is currently handled. In this case SDHCI_INT_STATUS only contains
SDHCI_INT_RESPONSE and the ISR would not be called again. But at the end
of the ISR SDHCI_INT_DATA_END is now also pending which would be ignored.
Fix this by rereading the interrupt flags in the ISR until no interrupt
we care is pending.
Signed-off-by: Alexander Stein <alexander.stein@systec-electronic.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mmc/host/sdhci.c | 19 |
1 files changed, 12 insertions, 7 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 80cc7847c531..8262cadfdab7 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c | |||
@@ -2267,8 +2267,8 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) | |||
2267 | { | 2267 | { |
2268 | irqreturn_t result; | 2268 | irqreturn_t result; |
2269 | struct sdhci_host *host = dev_id; | 2269 | struct sdhci_host *host = dev_id; |
2270 | u32 intmask; | 2270 | u32 intmask, unexpected = 0; |
2271 | int cardint = 0; | 2271 | int cardint = 0, max_loops = 16; |
2272 | 2272 | ||
2273 | spin_lock(&host->lock); | 2273 | spin_lock(&host->lock); |
2274 | 2274 | ||
@@ -2286,6 +2286,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) | |||
2286 | goto out; | 2286 | goto out; |
2287 | } | 2287 | } |
2288 | 2288 | ||
2289 | again: | ||
2289 | DBG("*** %s got interrupt: 0x%08x\n", | 2290 | DBG("*** %s got interrupt: 0x%08x\n", |
2290 | mmc_hostname(host->mmc), intmask); | 2291 | mmc_hostname(host->mmc), intmask); |
2291 | 2292 | ||
@@ -2344,19 +2345,23 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) | |||
2344 | intmask &= ~SDHCI_INT_CARD_INT; | 2345 | intmask &= ~SDHCI_INT_CARD_INT; |
2345 | 2346 | ||
2346 | if (intmask) { | 2347 | if (intmask) { |
2347 | pr_err("%s: Unexpected interrupt 0x%08x.\n", | 2348 | unexpected |= intmask; |
2348 | mmc_hostname(host->mmc), intmask); | ||
2349 | sdhci_dumpregs(host); | ||
2350 | |||
2351 | sdhci_writel(host, intmask, SDHCI_INT_STATUS); | 2349 | sdhci_writel(host, intmask, SDHCI_INT_STATUS); |
2352 | } | 2350 | } |
2353 | 2351 | ||
2354 | result = IRQ_HANDLED; | 2352 | result = IRQ_HANDLED; |
2355 | 2353 | ||
2356 | mmiowb(); | 2354 | intmask = sdhci_readl(host, SDHCI_INT_STATUS); |
2355 | if (intmask && --max_loops) | ||
2356 | goto again; | ||
2357 | out: | 2357 | out: |
2358 | spin_unlock(&host->lock); | 2358 | spin_unlock(&host->lock); |
2359 | 2359 | ||
2360 | if (unexpected) { | ||
2361 | pr_err("%s: Unexpected interrupt 0x%08x.\n", | ||
2362 | mmc_hostname(host->mmc), unexpected); | ||
2363 | sdhci_dumpregs(host); | ||
2364 | } | ||
2360 | /* | 2365 | /* |
2361 | * We have to delay this as it calls back into the driver. | 2366 | * We have to delay this as it calls back into the driver. |
2362 | */ | 2367 | */ |