mmc: sdhci: clean up interrupt handling

sdhci interrupt handling is a mess; there is a lot of code doing very
similar things.  Let's clean this up a bit:

1. set's clear down cmd, data and bus power interrupts in one go - we're
   always going to handle these.
2. use a do { } while () loop for looping while there are pending
   interrupts.
3. group clearing of bits in intmask into one place.

This results in the code becoming simpler and easier to read.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Tested-by: Markus Pargmann <mpa@pengutronix.de>
Tested-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Chris Ball <chris@printf.net>
This commit is contained in:
Russell King 2014-04-25 12:55:36 +01:00 committed by Chris Ball
parent bf3b5ec66b
commit 41005003bc
1 changed files with 66 additions and 74 deletions

View File

@ -2431,7 +2431,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
{
irqreturn_t result;
struct sdhci_host *host = dev_id;
u32 intmask, unexpected = 0;
u32 intmask, mask, unexpected = 0;
int cardint = 0, max_loops = 16;
spin_lock(&host->lock);
@ -2442,13 +2442,17 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
}
intmask = sdhci_readl(host, SDHCI_INT_STATUS);
if (!intmask || intmask == 0xffffffff) {
result = IRQ_NONE;
goto out;
}
again:
do {
/* Clear selected interrupts. */
mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
SDHCI_INT_BUS_POWER);
sdhci_writel(host, mask, SDHCI_INT_STATUS);
DBG("*** %s got interrupt: 0x%08x\n",
mmc_hostname(host->mmc), intmask);
@ -2457,14 +2461,15 @@ again:
SDHCI_CARD_PRESENT;
/*
* There is a observation on i.mx esdhc. INSERT bit will be
* immediately set again when it gets cleared, if a card is
* inserted. We have to mask the irq to prevent interrupt
* storm which will freeze the system. And the REMOVE gets
* the same situation.
* There is a observation on i.mx esdhc. INSERT
* bit will be immediately set again when it gets
* cleared, if a card is inserted. We have to mask
* the irq to prevent interrupt storm which will
* freeze the system. And the REMOVE gets the
* same situation.
*
* More testing are needed here to ensure it works for other
* platforms though.
* More testing are needed here to ensure it works
* for other platforms though.
*/
sdhci_mask_irqs(host, present ? SDHCI_INT_CARD_INSERT :
SDHCI_INT_CARD_REMOVE);
@ -2473,38 +2478,26 @@ again:
sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
tasklet_schedule(&host->card_tasklet);
}
if (intmask & SDHCI_INT_CMD_MASK) {
sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK,
SDHCI_INT_STATUS);
if (intmask & SDHCI_INT_CMD_MASK)
sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
}
if (intmask & SDHCI_INT_DATA_MASK) {
sdhci_writel(host, intmask & SDHCI_INT_DATA_MASK,
SDHCI_INT_STATUS);
if (intmask & SDHCI_INT_DATA_MASK)
sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
}
intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
intmask &= ~SDHCI_INT_ERROR;
if (intmask & SDHCI_INT_BUS_POWER) {
if (intmask & SDHCI_INT_BUS_POWER)
pr_err("%s: Card is consuming too much power!\n",
mmc_hostname(host->mmc));
sdhci_writel(host, SDHCI_INT_BUS_POWER, SDHCI_INT_STATUS);
}
intmask &= ~SDHCI_INT_BUS_POWER;
if (intmask & SDHCI_INT_CARD_INT)
cardint = 1;
intmask &= ~SDHCI_INT_CARD_INT;
intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE |
SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
SDHCI_INT_ERROR | SDHCI_INT_BUS_POWER |
SDHCI_INT_CARD_INT);
if (intmask) {
unexpected |= intmask;
@ -2516,14 +2509,13 @@ again:
intmask = sdhci_readl(host, SDHCI_INT_STATUS);
/*
* If we know we'll call the driver to signal SDIO IRQ, disregard
* further indications of Card Interrupt in the status to avoid a
* needless loop.
* If we know we'll call the driver to signal SDIO IRQ,
* disregard further indications of Card Interrupt in
* the status to avoid a needless loop.
*/
if (cardint)
intmask &= ~SDHCI_INT_CARD_INT;
if (intmask && --max_loops)
goto again;
} while (intmask && --max_loops);
out:
spin_unlock(&host->lock);