mmc: sdhci: clean up interrupt handling
authorRussell King <rmk+kernel@arm.linux.org.uk>
Fri, 25 Apr 2014 11:55:36 +0000 (12:55 +0100)
committerChris Ball <chris@printf.net>
Thu, 22 May 2014 11:26:23 +0000 (07:26 -0400)
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>
drivers/mmc/host/sdhci.c

index 255aaf18db3556a6f73bb2d27b9dad356b422d11..53168e4721a6c1d1d61220cb0a6a8e124c05d6f5 100644 (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,88 +2442,80 @@ 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:
-       DBG("*** %s got interrupt: 0x%08x\n",
-               mmc_hostname(host->mmc), intmask);
-
-       if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
-               u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
-                             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.
-                *
-                * 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);
-               sdhci_unmask_irqs(host, present ? SDHCI_INT_CARD_REMOVE :
-                                                 SDHCI_INT_CARD_INSERT);
-
-               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);
-       }
+       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);
 
-       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);
-       }
+               DBG("*** %s got interrupt: 0x%08x\n",
+                       mmc_hostname(host->mmc), intmask);
 
-       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);
-       }
+               if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
+                       u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
+                                     SDHCI_CARD_PRESENT;
 
-       intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
+                       /*
+                        * 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.
+                        */
+                       sdhci_mask_irqs(host, present ? SDHCI_INT_CARD_INSERT :
+                                                       SDHCI_INT_CARD_REMOVE);
+                       sdhci_unmask_irqs(host, present ? SDHCI_INT_CARD_REMOVE :
+                                                         SDHCI_INT_CARD_INSERT);
+
+                       sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
+                                    SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
+                       tasklet_schedule(&host->card_tasklet);
+               }
 
-       intmask &= ~SDHCI_INT_ERROR;
+               if (intmask & SDHCI_INT_CMD_MASK)
+                       sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
 
-       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);
-       }
+               if (intmask & SDHCI_INT_DATA_MASK)
+                       sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
 
-       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));
 
-       if (intmask & SDHCI_INT_CARD_INT)
-               cardint = 1;
+               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;
-               sdhci_writel(host, intmask, SDHCI_INT_STATUS);
-       }
+               if (intmask) {
+                       unexpected |= intmask;
+                       sdhci_writel(host, intmask, SDHCI_INT_STATUS);
+               }
 
-       result = IRQ_HANDLED;
+               result = IRQ_HANDLED;
 
-       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
-        * 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;
+               /*
+                * 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;
+       } while (intmask && --max_loops);
 out:
        spin_unlock(&host->lock);