mmc: sdhci: more efficient interrupt enable register handling
authorRussell King <rmk+kernel@arm.linux.org.uk>
Fri, 25 Apr 2014 11:56:01 +0000 (12:56 +0100)
committerChris Ball <chris@printf.net>
Thu, 22 May 2014 11:26:26 +0000 (07:26 -0400)
Rather than wasting cycles read-modify-writing the interrupt enable
registers, cache the value locally instead.

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
include/linux/mmc/sdhci.h

index 0ecbcc4c29d217a7062bbeb1ecf961024c3e97ff..4a98ee29d1369a555faacee6a2ea582071126dea 100644 (file)
@@ -131,27 +131,6 @@ static void sdhci_dumpregs(struct sdhci_host *host)
  *                                                                           *
 \*****************************************************************************/
 
-static void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
-{
-       u32 ier;
-
-       ier = sdhci_readl(host, SDHCI_INT_ENABLE);
-       ier &= ~clear;
-       ier |= set;
-       sdhci_writel(host, ier, SDHCI_INT_ENABLE);
-       sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE);
-}
-
-static void sdhci_unmask_irqs(struct sdhci_host *host, u32 irqs)
-{
-       sdhci_clear_set_irqs(host, 0, irqs);
-}
-
-static void sdhci_mask_irqs(struct sdhci_host *host, u32 irqs)
-{
-       sdhci_clear_set_irqs(host, irqs, 0);
-}
-
 static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
 {
        u32 present, irqs;
@@ -165,9 +144,12 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
        irqs = present ? SDHCI_INT_CARD_REMOVE : SDHCI_INT_CARD_INSERT;
 
        if (enable)
-               sdhci_unmask_irqs(host, irqs);
+               host->ier |= irqs;
        else
-               sdhci_mask_irqs(host, irqs);
+               host->ier &= ~irqs;
+
+       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 }
 
 static void sdhci_enable_card_detection(struct sdhci_host *host)
@@ -183,17 +165,12 @@ static void sdhci_disable_card_detection(struct sdhci_host *host)
 static void sdhci_reset(struct sdhci_host *host, u8 mask)
 {
        unsigned long timeout;
-       u32 uninitialized_var(ier);
-
        if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
                if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
                        SDHCI_CARD_PRESENT))
                        return;
        }
 
-       if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
-               ier = sdhci_readl(host, SDHCI_INT_ENABLE);
-
        if (host->ops->platform_reset_enter)
                host->ops->platform_reset_enter(host, mask);
 
@@ -224,8 +201,10 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
        if (host->ops->platform_reset_exit)
                host->ops->platform_reset_exit(host, mask);
 
-       if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
-               sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier);
+       if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET) {
+               sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+               sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+       }
 
        if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
                if ((host->ops->enable_dma) && (mask & SDHCI_RESET_ALL))
@@ -242,11 +221,14 @@ static void sdhci_init(struct sdhci_host *host, int soft)
        else
                sdhci_reset(host, SDHCI_RESET_ALL);
 
-       sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK,
-               SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
-               SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
-               SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
-               SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE);
+       host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
+                   SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT |
+                   SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC |
+                   SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END |
+                   SDHCI_INT_RESPONSE;
+
+       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 
        if (soft) {
                /* force clock reconfiguration */
@@ -721,9 +703,12 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host)
        u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR;
 
        if (host->flags & SDHCI_REQ_USE_DMA)
-               sdhci_clear_set_irqs(host, pio_irqs, dma_irqs);
+               host->ier = (host->ier & ~pio_irqs) | dma_irqs;
        else
-               sdhci_clear_set_irqs(host, dma_irqs, pio_irqs);
+               host->ier = (host->ier & ~dma_irqs) | pio_irqs;
+
+       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 }
 
 static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
@@ -1713,9 +1698,12 @@ static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable)
 {
        if (!(host->flags & SDHCI_DEVICE_DEAD)) {
                if (enable)
-                       sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT);
+                       host->ier |= SDHCI_INT_CARD_INT;
                else
-                       sdhci_mask_irqs(host, SDHCI_INT_CARD_INT);
+                       host->ier &= ~SDHCI_INT_CARD_INT;
+
+               sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+               sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
                mmiowb();
        }
 }
@@ -1857,7 +1845,6 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
        struct sdhci_host *host;
        u16 ctrl;
-       u32 ier;
        int tuning_loop_counter = MAX_TUNING_LOOP;
        unsigned long timeout;
        int err = 0;
@@ -1911,8 +1898,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
         * to make sure we don't hit a controller bug, we _only_
         * enable Buffer Read Ready interrupt here.
         */
-       ier = sdhci_readl(host, SDHCI_INT_ENABLE);
-       sdhci_clear_set_irqs(host, ier, SDHCI_INT_DATA_AVAIL);
+       sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE);
+       sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE);
 
        /*
         * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number
@@ -2047,7 +2034,8 @@ out:
        if (err && (host->flags & SDHCI_USING_RETUNING_TIMER))
                err = 0;
 
-       sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier);
+       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
        spin_unlock_irqrestore(&host->lock, flags);
        sdhci_runtime_pm_put(host);
 
@@ -2460,10 +2448,12 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
                         * 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);
+                       host->ier &= ~(SDHCI_INT_CARD_INSERT |
+                                      SDHCI_INT_CARD_REMOVE);
+                       host->ier |= present ? SDHCI_INT_CARD_REMOVE :
+                                              SDHCI_INT_CARD_INSERT;
+                       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+                       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 
                        sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
                                     SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
@@ -2592,7 +2582,9 @@ int sdhci_suspend_host(struct sdhci_host *host)
        }
 
        if (!device_may_wakeup(mmc_dev(host->mmc))) {
-               sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
+               host->ier = 0;
+               sdhci_writel(host, 0, SDHCI_INT_ENABLE);
+               sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
                free_irq(host->irq, host);
        } else {
                sdhci_enable_irq_wakeups(host);
@@ -2691,7 +2683,9 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
        }
 
        spin_lock_irqsave(&host->lock, flags);
-       sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK & ~SDHCI_INT_CARD_INT);
+       host->ier &= SDHCI_INT_CARD_INT;
+       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
        spin_unlock_irqrestore(&host->lock, flags);
 
        synchronize_hardirq(host->irq);
@@ -3282,7 +3276,8 @@ int sdhci_add_host(struct sdhci_host *host)
 #ifdef SDHCI_USE_LEDS_CLASS
 reset:
        sdhci_reset(host, SDHCI_RESET_ALL);
-       sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
+       sdhci_writel(host, 0, SDHCI_INT_ENABLE);
+       sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
        free_irq(host->irq, host);
 #endif
 untasklet:
@@ -3324,7 +3319,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
        if (!dead)
                sdhci_reset(host, SDHCI_RESET_ALL);
 
-       sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
+       sdhci_writel(host, 0, SDHCI_INT_ENABLE);
+       sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
        free_irq(host->irq, host);
 
        del_timer_sync(&host->timer);
index f1c8e14e8751839cf76bc0d923d71f3aad1b9300..9361d8ef509d737ca048295d20a717eb6f8ac60f 100644 (file)
@@ -178,6 +178,9 @@ struct sdhci_host {
 
        u32                     thread_isr;
 
+       /* cached registers */
+       u32                     ier;
+
        wait_queue_head_t       buf_ready_int;  /* Waitqueue for Buffer Read Ready interrupt */
        unsigned int            tuning_done;    /* Condition flag set when CMD19 succeeds */