mmc: sdhci: Fix recovery from tuning timeout
[firefly-linux-kernel-4.4.55.git] / drivers / mmc / host / sdhci.c
index b48565ed5616c79302008963a05aa7e1e18d742c..7277dfd7338fb4bfa2b68bd400ee7b3e81618a2f 100644 (file)
@@ -492,7 +492,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
                host->align_buffer, host->align_buffer_sz, direction);
        if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr))
                goto fail;
-       BUG_ON(host->align_addr & host->align_mask);
+       BUG_ON(host->align_addr & SDHCI_ADMA2_MASK);
 
        host->sg_count = sdhci_pre_dma_transfer(host, data);
        if (host->sg_count < 0)
@@ -514,8 +514,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
                 * the (up to three) bytes that screw up the
                 * alignment.
                 */
-               offset = (host->align_sz - (addr & host->align_mask)) &
-                        host->align_mask;
+               offset = (SDHCI_ADMA2_ALIGN - (addr & SDHCI_ADMA2_MASK)) &
+                        SDHCI_ADMA2_MASK;
                if (offset) {
                        if (data->flags & MMC_DATA_WRITE) {
                                buffer = sdhci_kmap_atomic(sg, &flags);
@@ -529,8 +529,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
 
                        BUG_ON(offset > 65536);
 
-                       align += host->align_sz;
-                       align_addr += host->align_sz;
+                       align += SDHCI_ADMA2_ALIGN;
+                       align_addr += SDHCI_ADMA2_ALIGN;
 
                        desc += host->desc_sz;
 
@@ -540,9 +540,12 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
 
                BUG_ON(len > 65536);
 
-               /* tran, valid */
-               sdhci_adma_write_desc(host, desc, addr, len, ADMA2_TRAN_VALID);
-               desc += host->desc_sz;
+               if (len) {
+                       /* tran, valid */
+                       sdhci_adma_write_desc(host, desc, addr, len,
+                                             ADMA2_TRAN_VALID);
+                       desc += host->desc_sz;
+               }
 
                /*
                 * If this triggers then we have a calculation bug
@@ -608,7 +611,7 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
        /* Do a quick scan of the SG list for any unaligned mappings */
        has_unaligned = false;
        for_each_sg(data->sg, sg, host->sg_count, i)
-               if (sg_dma_address(sg) & host->align_mask) {
+               if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) {
                        has_unaligned = true;
                        break;
                }
@@ -620,15 +623,15 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
                align = host->align_buffer;
 
                for_each_sg(data->sg, sg, host->sg_count, i) {
-                       if (sg_dma_address(sg) & host->align_mask) {
-                               size = host->align_sz -
-                                      (sg_dma_address(sg) & host->align_mask);
+                       if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) {
+                               size = SDHCI_ADMA2_ALIGN -
+                                      (sg_dma_address(sg) & SDHCI_ADMA2_MASK);
 
                                buffer = sdhci_kmap_atomic(sg, &flags);
                                memcpy(buffer, align, size);
                                sdhci_kunmap_atomic(buffer, &flags);
 
-                               align += host->align_sz;
+                               align += SDHCI_ADMA2_ALIGN;
                        }
                }
        }
@@ -663,9 +666,20 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
        if (!data)
                target_timeout = cmd->busy_timeout * 1000;
        else {
-               target_timeout = data->timeout_ns / 1000;
-               if (host->clock)
-                       target_timeout += data->timeout_clks / host->clock;
+               target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000);
+               if (host->clock && data->timeout_clks) {
+                       unsigned long long val;
+
+                       /*
+                        * data->timeout_clks is in units of clock cycles.
+                        * host->clock is in Hz.  target_timeout is in us.
+                        * Hence, us = 1000000 * cycles / Hz.  Round up.
+                        */
+                       val = 1000000ULL * data->timeout_clks;
+                       if (do_div(val, host->clock))
+                               target_timeout++;
+                       target_timeout += val;
+               }
        }
 
        /*
@@ -1301,7 +1315,9 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
                        pwr = SDHCI_POWER_330;
                        break;
                default:
-                       BUG();
+                       WARN(1, "%s: Invalid vdd %#x\n",
+                            mmc_hostname(host->mmc), vdd);
+                       break;
                }
        }
 
@@ -1364,7 +1380,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
        sdhci_runtime_pm_get(host);
 
        /* Firstly check card presence */
-       present = sdhci_do_get_cd(host);
+       present = mmc->ops->get_cd(mmc);
 
        spin_lock_irqsave(&host->lock, flags);
 
@@ -2024,7 +2040,27 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
                        ctrl &= ~SDHCI_CTRL_EXEC_TUNING;
                        sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
+                       sdhci_do_reset(host, SDHCI_RESET_CMD);
+                       sdhci_do_reset(host, SDHCI_RESET_DATA);
+
                        err = -EIO;
+
+                       if (cmd.opcode != MMC_SEND_TUNING_BLOCK_HS200)
+                               goto out;
+
+                       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+                       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+
+                       spin_unlock_irqrestore(&host->lock, flags);
+
+                       memset(&cmd, 0, sizeof(cmd));
+                       cmd.opcode = MMC_STOP_TRANSMISSION;
+                       cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+                       cmd.busy_timeout = 50;
+                       mmc_wait_for_cmd(mmc, &cmd, 0);
+
+                       spin_lock_irqsave(&host->lock, flags);
+
                        goto out;
                }
 
@@ -2760,7 +2796,7 @@ static int sdhci_runtime_pm_put(struct sdhci_host *host)
 
 static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
 {
-       if (host->runtime_suspended || host->bus_on)
+       if (host->bus_on)
                return;
        host->bus_on = true;
        pm_runtime_get_noresume(host->mmc->parent);
@@ -2768,7 +2804,7 @@ static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
 
 static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
 {
-       if (host->runtime_suspended || !host->bus_on)
+       if (!host->bus_on)
                return;
        host->bus_on = false;
        pm_runtime_put_noidle(host->mmc->parent);
@@ -2861,6 +2897,8 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev,
 
        host = mmc_priv(mmc);
        host->mmc = mmc;
+       host->mmc_host_ops = sdhci_ops;
+       mmc->ops = &host->mmc_host_ops;
 
        return host;
 }
@@ -2967,24 +3005,17 @@ int sdhci_add_host(struct sdhci_host *host)
                if (host->flags & SDHCI_USE_64_BIT_DMA) {
                        host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) *
                                              SDHCI_ADMA2_64_DESC_SZ;
-                       host->align_buffer_sz = SDHCI_MAX_SEGS *
-                                               SDHCI_ADMA2_64_ALIGN;
                        host->desc_sz = SDHCI_ADMA2_64_DESC_SZ;
-                       host->align_sz = SDHCI_ADMA2_64_ALIGN;
-                       host->align_mask = SDHCI_ADMA2_64_ALIGN - 1;
                } else {
                        host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) *
                                              SDHCI_ADMA2_32_DESC_SZ;
-                       host->align_buffer_sz = SDHCI_MAX_SEGS *
-                                               SDHCI_ADMA2_32_ALIGN;
                        host->desc_sz = SDHCI_ADMA2_32_DESC_SZ;
-                       host->align_sz = SDHCI_ADMA2_32_ALIGN;
-                       host->align_mask = SDHCI_ADMA2_32_ALIGN - 1;
                }
                host->adma_table = dma_alloc_coherent(mmc_dev(mmc),
                                                      host->adma_table_sz,
                                                      &host->adma_addr,
                                                      GFP_KERNEL);
+               host->align_buffer_sz = SDHCI_MAX_SEGS * SDHCI_ADMA2_ALIGN;
                host->align_buffer = kmalloc(host->align_buffer_sz, GFP_KERNEL);
                if (!host->adma_table || !host->align_buffer) {
                        if (host->adma_table)
@@ -2998,7 +3029,7 @@ int sdhci_add_host(struct sdhci_host *host)
                        host->flags &= ~SDHCI_USE_ADMA;
                        host->adma_table = NULL;
                        host->align_buffer = NULL;
-               } else if (host->adma_addr & host->align_mask) {
+               } else if (host->adma_addr & (SDHCI_ADMA2_DESC_ALIGN - 1)) {
                        pr_warn("%s: unable to allocate aligned ADMA descriptor\n",
                                mmc_hostname(mmc));
                        host->flags &= ~SDHCI_USE_ADMA;
@@ -3057,7 +3088,6 @@ int sdhci_add_host(struct sdhci_host *host)
        /*
         * Set host parameters.
         */
-       mmc->ops = &sdhci_ops;
        max_clk = host->max_clk;
 
        if (host->ops->get_min_clock)
@@ -3091,14 +3121,14 @@ int sdhci_add_host(struct sdhci_host *host)
                if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT)
                        host->timeout_clk *= 1000;
 
+               if (override_timeout_clk)
+                       host->timeout_clk = override_timeout_clk;
+
                mmc->max_busy_timeout = host->ops->get_max_timeout_count ?
                        host->ops->get_max_timeout_count(host) : 1 << 27;
                mmc->max_busy_timeout /= host->timeout_clk;
        }
 
-       if (override_timeout_clk)
-               host->timeout_clk = override_timeout_clk;
-
        mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
        mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;