Merge tag 'wireless-drivers-for-davem-2015-02-11' of git://git.kernel.org/pub/scm...
[cascardo/linux.git] / drivers / mmc / host / sdhci.c
index f1a488e..0ad412a 100644 (file)
@@ -53,6 +53,9 @@ static void sdhci_finish_command(struct sdhci_host *);
 static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
 static void sdhci_tuning_timer(unsigned long data);
 static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
+static int sdhci_pre_dma_transfer(struct sdhci_host *host,
+                                       struct mmc_data *data,
+                                       struct sdhci_host_next *next);
 
 #ifdef CONFIG_PM
 static int sdhci_runtime_pm_get(struct sdhci_host *host);
@@ -505,9 +508,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
                goto fail;
        BUG_ON(host->align_addr & host->align_mask);
 
-       host->sg_count = dma_map_sg(mmc_dev(host->mmc),
-               data->sg, data->sg_len, direction);
-       if (host->sg_count == 0)
+       host->sg_count = sdhci_pre_dma_transfer(host, data, NULL);
+       if (host->sg_count < 0)
                goto unmap_align;
 
        desc = host->adma_table;
@@ -531,8 +533,6 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
                if (offset) {
                        if (data->flags & MMC_DATA_WRITE) {
                                buffer = sdhci_kmap_atomic(sg, &flags);
-                               WARN_ON(((long)buffer & (PAGE_SIZE - 1)) >
-                                       (PAGE_SIZE - offset));
                                memcpy(align, buffer, offset);
                                sdhci_kunmap_atomic(buffer, &flags);
                        }
@@ -639,8 +639,6 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
                                       (sg_dma_address(sg) & host->align_mask);
 
                                buffer = sdhci_kmap_atomic(sg, &flags);
-                               WARN_ON(((long)buffer & (PAGE_SIZE - 1)) >
-                                       (PAGE_SIZE - size));
                                memcpy(buffer, align, size);
                                sdhci_kunmap_atomic(buffer, &flags);
 
@@ -649,8 +647,9 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
                }
        }
 
-       dma_unmap_sg(mmc_dev(host->mmc), data->sg,
-               data->sg_len, direction);
+       if (!data->host_cookie)
+               dma_unmap_sg(mmc_dev(host->mmc), data->sg,
+                       data->sg_len, direction);
 }
 
 static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
@@ -846,11 +845,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
                } else {
                        int sg_cnt;
 
-                       sg_cnt = dma_map_sg(mmc_dev(host->mmc),
-                                       data->sg, data->sg_len,
-                                       (data->flags & MMC_DATA_READ) ?
-                                               DMA_FROM_DEVICE :
-                                               DMA_TO_DEVICE);
+                       sg_cnt = sdhci_pre_dma_transfer(host, data, NULL);
                        if (sg_cnt == 0) {
                                /*
                                 * This only happens when someone fed
@@ -909,7 +904,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
 static void sdhci_set_transfer_mode(struct sdhci_host *host,
        struct mmc_command *cmd)
 {
-       u16 mode;
+       u16 mode = 0;
        struct mmc_data *data = cmd->data;
 
        if (data == NULL) {
@@ -927,9 +922,11 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
 
        WARN_ON(!host->data);
 
-       mode = SDHCI_TRNS_BLK_CNT_EN;
+       if (!(host->quirks2 & SDHCI_QUIRK2_SUPPORT_SINGLE))
+               mode = SDHCI_TRNS_BLK_CNT_EN;
+
        if (mmc_op_multi(cmd->opcode) || data->blocks > 1) {
-               mode |= SDHCI_TRNS_MULTI;
+               mode = SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_MULTI;
                /*
                 * If we are sending CMD23, CMD12 never gets sent
                 * on successful completion (so no Auto-CMD12).
@@ -963,8 +960,10 @@ static void sdhci_finish_data(struct sdhci_host *host)
                if (host->flags & SDHCI_USE_ADMA)
                        sdhci_adma_table_post(host, data);
                else {
-                       dma_unmap_sg(mmc_dev(host->mmc), data->sg,
-                               data->sg_len, (data->flags & MMC_DATA_READ) ?
+                       if (!data->host_cookie)
+                               dma_unmap_sg(mmc_dev(host->mmc),
+                                       data->sg, data->sg_len,
+                                       (data->flags & MMC_DATA_READ) ?
                                        DMA_FROM_DEVICE : DMA_TO_DEVICE);
                }
        }
@@ -1630,7 +1629,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
         * signalling timeout and CRC errors even on CMD0. Resetting
         * it on each ios seems to solve the problem.
         */
-       if(host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
+       if (host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
                sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
 
        mmiowb();
@@ -1832,6 +1831,10 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
                ctrl |= SDHCI_CTRL_VDD_180;
                sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
+               /* Some controller need to do more when switching */
+               if (host->ops->voltage_switch)
+                       host->ops->voltage_switch(host);
+
                /* 1.8V regulator output should be stable within 5 ms */
                ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
                if (ctrl & SDHCI_CTRL_VDD_180)
@@ -1960,6 +1963,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 
        ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
        ctrl |= SDHCI_CTRL_EXEC_TUNING;
+       if (host->quirks2 & SDHCI_QUIRK2_TUNING_WORK_AROUND)
+               ctrl |= SDHCI_CTRL_TUNED_CLK;
        sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
        /*
@@ -2129,6 +2134,77 @@ static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
        }
 }
 
+static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
+                               int err)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+       struct mmc_data *data = mrq->data;
+
+       if (host->flags & SDHCI_REQ_USE_DMA) {
+               if (data->host_cookie)
+                       dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+                                        data->flags & MMC_DATA_WRITE ?
+                                        DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               mrq->data->host_cookie = 0;
+       }
+}
+
+static int sdhci_pre_dma_transfer(struct sdhci_host *host,
+                                      struct mmc_data *data,
+                                      struct sdhci_host_next *next)
+{
+       int sg_count;
+
+       if (!next && data->host_cookie &&
+           data->host_cookie != host->next_data.cookie) {
+               pr_debug(DRIVER_NAME "[%s] invalid cookie: %d, next-cookie %d\n",
+                       __func__, data->host_cookie, host->next_data.cookie);
+               data->host_cookie = 0;
+       }
+
+       /* Check if next job is already prepared */
+       if (next ||
+           (!next && data->host_cookie != host->next_data.cookie)) {
+               sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg,
+                                    data->sg_len,
+                                    data->flags & MMC_DATA_WRITE ?
+                                    DMA_TO_DEVICE : DMA_FROM_DEVICE);
+
+       } else {
+               sg_count = host->next_data.sg_count;
+               host->next_data.sg_count = 0;
+       }
+
+
+       if (sg_count == 0)
+               return -EINVAL;
+
+       if (next) {
+               next->sg_count = sg_count;
+               data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie;
+       } else
+               host->sg_count = sg_count;
+
+       return sg_count;
+}
+
+static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
+                              bool is_first_req)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+
+       if (mrq->data->host_cookie) {
+               mrq->data->host_cookie = 0;
+               return;
+       }
+
+       if (host->flags & SDHCI_REQ_USE_DMA)
+               if (sdhci_pre_dma_transfer(host,
+                                       mrq->data,
+                                       &host->next_data) < 0)
+                       mrq->data->host_cookie = 0;
+}
+
 static void sdhci_card_event(struct mmc_host *mmc)
 {
        struct sdhci_host *host = mmc_priv(mmc);
@@ -2162,6 +2238,8 @@ static void sdhci_card_event(struct mmc_host *mmc)
 
 static const struct mmc_host_ops sdhci_ops = {
        .request        = sdhci_request,
+       .post_req       = sdhci_post_req,
+       .pre_req        = sdhci_pre_req,
        .set_ios        = sdhci_set_ios,
        .get_cd         = sdhci_get_cd,
        .get_ro         = sdhci_get_ro,
@@ -2793,9 +2871,9 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
        /* Force clock and power re-program */
        host->pwr = 0;
        host->clock = 0;
+       sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios);
        sdhci_do_set_ios(host, &host->mmc->ios);
 
-       sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios);
        if ((host_flags & SDHCI_PV_ENABLED) &&
                !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) {
                spin_lock_irqsave(&host->lock, flags);
@@ -3019,6 +3097,7 @@ int sdhci_add_host(struct sdhci_host *host)
                host->max_clk = host->ops->get_max_clock(host);
        }
 
+       host->next_data.cookie = 1;
        /*
         * In case of Host Controller v3.00, find out whether clock
         * multiplier is supported.
@@ -3338,9 +3417,9 @@ int sdhci_add_host(struct sdhci_host *host)
 
        setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
 
-       if (host->version >= SDHCI_SPEC_300) {
-               init_waitqueue_head(&host->buf_ready_int);
+       init_waitqueue_head(&host->buf_ready_int);
 
+       if (host->version >= SDHCI_SPEC_300) {
                /* Initialize re-tuning timer */
                init_timer(&host->tuning_timer);
                host->tuning_timer.data = (unsigned long)host;