提交 41005003 编写于 作者: R Russell King 提交者: 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: NRussell King <rmk+kernel@arm.linux.org.uk>
Tested-by: NMarkus Pargmann <mpa@pengutronix.de>
Tested-by: NStephen Warren <swarren@nvidia.com>
Signed-off-by: NUlf Hansson <ulf.hansson@linaro.org>
Signed-off-by: NChris Ball <chris@printf.net>
上级 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% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册