Commit 41005003 authored by Russell King's avatar Russell King Committed by Chris Ball

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: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
Tested-by: default avatarMarkus Pargmann <mpa@pengutronix.de>
Tested-by: default avatarStephen Warren <swarren@nvidia.com>
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
Signed-off-by: default avatarChris Ball <chris@printf.net>
parent bf3b5ec6
...@@ -2431,7 +2431,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) ...@@ -2431,7 +2431,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
{ {
irqreturn_t result; irqreturn_t result;
struct sdhci_host *host = dev_id; struct sdhci_host *host = dev_id;
u32 intmask, unexpected = 0; u32 intmask, mask, unexpected = 0;
int cardint = 0, max_loops = 16; int cardint = 0, max_loops = 16;
spin_lock(&host->lock); spin_lock(&host->lock);
...@@ -2442,13 +2442,17 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) ...@@ -2442,13 +2442,17 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
} }
intmask = sdhci_readl(host, SDHCI_INT_STATUS); intmask = sdhci_readl(host, SDHCI_INT_STATUS);
if (!intmask || intmask == 0xffffffff) { if (!intmask || intmask == 0xffffffff) {
result = IRQ_NONE; result = IRQ_NONE;
goto out; 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", DBG("*** %s got interrupt: 0x%08x\n",
mmc_hostname(host->mmc), intmask); mmc_hostname(host->mmc), intmask);
...@@ -2457,14 +2461,15 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) ...@@ -2457,14 +2461,15 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
SDHCI_CARD_PRESENT; SDHCI_CARD_PRESENT;
/* /*
* There is a observation on i.mx esdhc. INSERT bit will be * There is a observation on i.mx esdhc. INSERT
* immediately set again when it gets cleared, if a card is * bit will be immediately set again when it gets
* inserted. We have to mask the irq to prevent interrupt * cleared, if a card is inserted. We have to mask
* storm which will freeze the system. And the REMOVE gets * the irq to prevent interrupt storm which will
* the same situation. * freeze the system. And the REMOVE gets the
* same situation.
* *
* More testing are needed here to ensure it works for other * More testing are needed here to ensure it works
* platforms though. * for other platforms though.
*/ */
sdhci_mask_irqs(host, present ? SDHCI_INT_CARD_INSERT : sdhci_mask_irqs(host, present ? SDHCI_INT_CARD_INSERT :
SDHCI_INT_CARD_REMOVE); SDHCI_INT_CARD_REMOVE);
...@@ -2473,38 +2478,26 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) ...@@ -2473,38 +2478,26 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT | sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS); SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
tasklet_schedule(&host->card_tasklet); tasklet_schedule(&host->card_tasklet);
} }
if (intmask & SDHCI_INT_CMD_MASK) { if (intmask & SDHCI_INT_CMD_MASK)
sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK,
SDHCI_INT_STATUS);
sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK); sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
}
if (intmask & SDHCI_INT_DATA_MASK) { if (intmask & SDHCI_INT_DATA_MASK)
sdhci_writel(host, intmask & SDHCI_INT_DATA_MASK,
SDHCI_INT_STATUS);
sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK); sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
}
intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK); if (intmask & SDHCI_INT_BUS_POWER)
intmask &= ~SDHCI_INT_ERROR;
if (intmask & SDHCI_INT_BUS_POWER) {
pr_err("%s: Card is consuming too much power!\n", pr_err("%s: Card is consuming too much power!\n",
mmc_hostname(host->mmc)); 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) if (intmask & SDHCI_INT_CARD_INT)
cardint = 1; 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) { if (intmask) {
unexpected |= intmask; unexpected |= intmask;
...@@ -2516,14 +2509,13 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) ...@@ -2516,14 +2509,13 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
intmask = sdhci_readl(host, SDHCI_INT_STATUS); intmask = sdhci_readl(host, SDHCI_INT_STATUS);
/* /*
* If we know we'll call the driver to signal SDIO IRQ, disregard * If we know we'll call the driver to signal SDIO IRQ,
* further indications of Card Interrupt in the status to avoid a * disregard further indications of Card Interrupt in
* needless loop. * the status to avoid a needless loop.
*/ */
if (cardint) if (cardint)
intmask &= ~SDHCI_INT_CARD_INT; intmask &= ~SDHCI_INT_CARD_INT;
if (intmask && --max_loops) } while (intmask && --max_loops);
goto again;
out: out:
spin_unlock(&host->lock); spin_unlock(&host->lock);
......
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