diff options
Diffstat (limited to 'drivers/mmc')
| -rw-r--r-- | drivers/mmc/card/block.c | 66 | ||||
| -rw-r--r-- | drivers/mmc/card/mmc_test.c | 2 | ||||
| -rw-r--r-- | drivers/mmc/core/bus.c | 14 | ||||
| -rw-r--r-- | drivers/mmc/core/core.c | 11 | ||||
| -rw-r--r-- | drivers/mmc/core/core.h | 1 | ||||
| -rw-r--r-- | drivers/mmc/core/mmc.c | 41 | ||||
| -rw-r--r-- | drivers/mmc/core/sd.c | 18 | ||||
| -rw-r--r-- | drivers/mmc/host/cmdq_hci.c | 9 | ||||
| -rw-r--r-- | drivers/mmc/host/cmdq_hci.h | 1 | ||||
| -rw-r--r-- | drivers/mmc/host/mxs-mmc.c | 6 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-msm-ice.c | 31 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-msm-ice.h | 6 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-msm.c | 31 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-msm.h | 8 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci.c | 63 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci.h | 2 |
16 files changed, 280 insertions, 30 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index ce0ecd1e9b7a..e9f1a19dfe3f 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -875,6 +875,14 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, cmd.arg = idata->ic.arg; cmd.flags = idata->ic.flags; + if (idata->ic.postsleep_max_us < idata->ic.postsleep_min_us) { + pr_err("%s: min value: %u must not be greater than max value: %u\n", + __func__, idata->ic.postsleep_min_us, + idata->ic.postsleep_max_us); + WARN_ON(1); + return -EPERM; + } + if (idata->buf_bytes) { data.sg = &sg; data.sg_len = 1; @@ -2181,6 +2189,17 @@ static int mmc_blk_err_check(struct mmc_card *card, int need_retune = card->host->need_retune; int ecc_err = 0, gen_err = 0; + if (card->host->sdr104_wa && mmc_card_sd(card) && + (card->host->ios.timing == MMC_TIMING_UHS_SDR104) && + !card->sdr104_blocked && + (brq->data.error == -EILSEQ || + brq->data.error == -EIO || + brq->data.error == -ETIMEDOUT || + brq->cmd.error == -EILSEQ || + brq->cmd.error == -EIO || + brq->cmd.error == -ETIMEDOUT)) + card->err_in_sdr104 = true; + /* * sbc.error indicates a problem with the set block count * command. No data will have been transferred. @@ -3637,6 +3656,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) struct mmc_async_req *areq; const u8 packed_nr = 2; u8 reqs = 0; + bool reset = false; #ifdef CONFIG_MMC_SIMULATE_MAX_SPEED unsigned long waitfor = jiffies; #endif @@ -3682,6 +3702,26 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE; mmc_queue_bounce_post(mq_rq); + if (card->err_in_sdr104) { + /* + * Data CRC/timeout errors will manifest as CMD/DATA + * ERR. But we'd like to retry these too. + * Moreover, no harm done if this fails too for multiple + * times, we anyway reduce the bus-speed and retry the + * same request. + * If that fails too, we don't override this status. + */ + if (status == MMC_BLK_ABORT || + status == MMC_BLK_CMD_ERR || + status == MMC_BLK_DATA_ERR || + status == MMC_BLK_RETRY) + /* reset on all of these errors and retry */ + reset = true; + + status = MMC_BLK_RETRY; + card->err_in_sdr104 = false; + } + switch (status) { case MMC_BLK_SUCCESS: case MMC_BLK_PARTIAL: @@ -3722,8 +3762,32 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) break; case MMC_BLK_RETRY: retune_retry_done = brq->retune_retry_done; - if (retry++ < MMC_BLK_MAX_RETRIES) + if (retry++ < MMC_BLK_MAX_RETRIES) { + break; + } else if (reset) { + reset = false; + /* + * If we exhaust all the retries due to + * CRC/timeout errors in SDR140 mode with UHS SD + * cards, re-configure the card in SDR50 + * bus-speed mode. + * All subsequent re-init of this card will be + * in SDR50 mode, unless it is removed and + * re-inserted. When new UHS SD cards are + * inserted, it may start at SDR104 mode if + * supported by the card. + */ + pr_err("%s: blocked SDR104, lower the bus-speed (SDR50 / DDR50)\n", + req->rq_disk->disk_name); + mmc_host_clear_sdr104(card->host); + mmc_suspend_clk_scaling(card->host); + mmc_blk_reset(md, card->host, type); + /* SDR104 mode is blocked from now on */ + card->sdr104_blocked = true; + /* retry 5 times again */ + retry = 0; break; + } /* Fall through */ case MMC_BLK_ABORT: if (!mmc_blk_reset(md, card->host, type) && diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index 9766dcc95602..12c66919f06f 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -791,7 +791,7 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test, struct mmc_async_req *cur_areq = &test_areq[0].areq; struct mmc_async_req *other_areq = &test_areq[1].areq; int i; - int ret; + int ret = RESULT_OK; test_areq[0].test = test; test_areq[1].test = test; diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 8101b77c2acf..311f6d639d06 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -167,6 +167,19 @@ static int mmc_bus_suspend(struct device *dev) if (mmc_bus_needs_resume(host)) return 0; ret = host->bus_ops->suspend(host); + + /* + * bus_ops->suspend may fail due to some reason + * In such cases if we return error to PM framework + * from here without calling pm_generic_resume then mmc + * request may get stuck since PM framework will assume + * that mmc bus is not suspended (because of error) and + * it won't call resume again. + * + * So in case of error call pm_generic_resume(). + */ + if (ret) + pm_generic_resume(dev); return ret; } @@ -415,7 +428,6 @@ void mmc_remove_card(struct mmc_card *card) } kfree(card->wr_pack_stats.packing_events); - kfree(card->cached_ext_csd); put_device(&card->dev); } diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 5396e1d00178..41f0935440fd 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2126,6 +2126,7 @@ int mmc_try_claim_host(struct mmc_host *host, unsigned int delay_ms) int claimed_host = 0; unsigned long flags; int retry_cnt = delay_ms/10; + bool pm = false; do { spin_lock_irqsave(&host->lock, flags); @@ -2134,11 +2135,17 @@ int mmc_try_claim_host(struct mmc_host *host, unsigned int delay_ms) host->claimer = current; host->claim_cnt += 1; claimed_host = 1; + if (host->claim_cnt == 1) + pm = true; } spin_unlock_irqrestore(&host->lock, flags); if (!claimed_host) mmc_delay(10); } while (!claimed_host && retry_cnt--); + + if (pm) + pm_runtime_get_sync(mmc_dev(host)); + if (host->ops->enable && claimed_host && host->claim_cnt == 1) host->ops->enable(host); return claimed_host; @@ -4033,6 +4040,10 @@ int _mmc_detect_card_removed(struct mmc_host *host) if (ret) { mmc_card_set_removed(host->card); + if (host->card->sdr104_blocked) { + mmc_host_set_sdr104(host); + host->card->sdr104_blocked = false; + } pr_debug("%s: card remove detected\n", mmc_hostname(host)); } diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 1116544eebc1..c66187299598 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -80,7 +80,6 @@ void mmc_init_context_info(struct mmc_host *host); extern bool mmc_can_scale_clk(struct mmc_host *host); extern int mmc_init_clk_scaling(struct mmc_host *host); -extern int mmc_suspend_clk_scaling(struct mmc_host *host); extern int mmc_resume_clk_scaling(struct mmc_host *host); extern int mmc_exit_clk_scaling(struct mmc_host *host); extern unsigned long mmc_get_max_frequency(struct mmc_host *host); diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 414877874190..3b79f514350e 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -722,7 +722,6 @@ static int mmc_read_ext_csd(struct mmc_card *card) return err; } - card->cached_ext_csd = ext_csd; err = mmc_decode_ext_csd(card, ext_csd); kfree(ext_csd); return err; @@ -2032,10 +2031,10 @@ reinit: err = mmc_select_hs400(card); if (err) goto free_card; - } else if (mmc_card_hs(card)) { + } else if (!mmc_card_hs400(card)) { /* Select the desired bus width optionally */ err = mmc_select_bus_width(card); - if (!IS_ERR_VALUE(err)) { + if (!IS_ERR_VALUE(err) && mmc_card_hs(card)) { err = mmc_select_hs_ddr(card); if (err) goto free_card; @@ -2494,7 +2493,7 @@ static int mmc_test_awake_ext_csd(struct mmc_host *host) static int _mmc_suspend(struct mmc_host *host, bool is_suspend) { - int err = 0; + int err = 0, ret; BUG_ON(!host); BUG_ON(!host->card); @@ -2503,6 +2502,8 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend) if (err) { pr_err("%s: %s: fail to suspend clock scaling (%d)\n", mmc_hostname(host), __func__, err); + if (host->card->cmdq_init) + wake_up(&host->cmdq_ctx.wait); return err; } @@ -2527,12 +2528,12 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend) if (mmc_card_doing_bkops(host->card)) { err = mmc_stop_bkops(host->card); if (err) - goto out; + goto out_err; } err = mmc_flush_cache(host->card); if (err) - goto out; + goto out_err; if (mmc_can_sleepawake(host)) { /* @@ -2549,16 +2550,38 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend) err = mmc_deselect_cards(host); } - if (!err) { - mmc_power_off(host); - mmc_card_set_suspended(host->card); + if (err) + goto out_err; + mmc_power_off(host); + mmc_card_set_suspended(host->card); + + goto out; + +out_err: + /* + * In case of err let's put controller back in cmdq mode and unhalt + * the controller. + * We expect cmdq_enable and unhalt won't return any error + * since it is anyway enabling few registers. + */ + if (host->card->cmdq_init) { + mmc_host_clk_hold(host); + ret = host->cmdq_ops->enable(host); + if (ret) + pr_err("%s: %s: enabling CMDQ mode failed (%d)\n", + mmc_hostname(host), __func__, ret); + mmc_host_clk_release(host); + mmc_cmdq_halt(host, false); } + out: /* Kick CMDQ thread to process any requests came in while suspending */ if (host->card->cmdq_init) wake_up(&host->cmdq_ctx.wait); mmc_release_host(host); + if (err) + mmc_resume_clk_scaling(host); return err; } diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index ec5ce79e84e7..5b4d5d74fe55 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -433,26 +433,26 @@ static void sd_update_bus_speed_mode(struct mmc_card *card) if ((card->host->caps & MMC_CAP_UHS_SDR104) && (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104) && (card->host->f_max > UHS_SDR104_MIN_DTR)) { - card->sd_bus_speed = UHS_SDR104_BUS_SPEED; - } else if ((card->host->caps & MMC_CAP_UHS_DDR50) && - (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50) && - (card->host->f_max > UHS_DDR50_MIN_DTR)) { - card->sd_bus_speed = UHS_DDR50_BUS_SPEED; + card->sd_bus_speed = UHS_SDR104_BUS_SPEED; } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR50) && (card->host->f_max > UHS_SDR50_MIN_DTR)) { - card->sd_bus_speed = UHS_SDR50_BUS_SPEED; + card->sd_bus_speed = UHS_SDR50_BUS_SPEED; + } else if ((card->host->caps & MMC_CAP_UHS_DDR50) && + (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50) && + (card->host->f_max > UHS_DDR50_MIN_DTR)) { + card->sd_bus_speed = UHS_DDR50_BUS_SPEED; } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) && (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25) && (card->host->f_max > UHS_SDR25_MIN_DTR)) { - card->sd_bus_speed = UHS_SDR25_BUS_SPEED; + card->sd_bus_speed = UHS_SDR25_BUS_SPEED; } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR12)) { - card->sd_bus_speed = UHS_SDR12_BUS_SPEED; + card->sd_bus_speed = UHS_SDR12_BUS_SPEED; } } @@ -1285,6 +1285,8 @@ static int _mmc_sd_resume(struct mmc_host *host) #endif mmc_card_clr_suspended(host->card); + if (host->card->sdr104_blocked) + goto out; err = mmc_resume_clk_scaling(host); if (err) { pr_err("%s: %s: fail to resume clock scaling (%d)\n", diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c index 1ad5fd0e0a78..a83960fd474f 100644 --- a/drivers/mmc/host/cmdq_hci.c +++ b/drivers/mmc/host/cmdq_hci.c @@ -852,6 +852,7 @@ static void cmdq_finish_data(struct mmc_host *mmc, unsigned int tag) struct mmc_request *mrq; struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc); int offset = 0; + int err = 0; if (cq_host->offset_changed) offset = CQ_V5_VENDOR_CFG; @@ -865,6 +866,14 @@ static void cmdq_finish_data(struct mmc_host *mmc, unsigned int tag) CMDQ_SEND_STATUS_TRIGGER, CQ_VENDOR_CFG + offset); cmdq_runtime_pm_put(cq_host); + + if (cq_host->ops->crypto_cfg_end) { + err = cq_host->ops->crypto_cfg_end(mmc, mrq); + if (err) { + pr_err("%s: failed to end ice config: err %d tag %d\n", + mmc_hostname(mmc), err, tag); + } + } if (!(cq_host->caps & CMDQ_CAP_CRYPTO_SUPPORT) && cq_host->ops->crypto_cfg_reset) cq_host->ops->crypto_cfg_reset(mmc, tag); diff --git a/drivers/mmc/host/cmdq_hci.h b/drivers/mmc/host/cmdq_hci.h index db0cd956ae90..ee5e6549fa4a 100644 --- a/drivers/mmc/host/cmdq_hci.h +++ b/drivers/mmc/host/cmdq_hci.h @@ -223,6 +223,7 @@ struct cmdq_host_ops { int (*reset)(struct mmc_host *mmc); int (*crypto_cfg)(struct mmc_host *mmc, struct mmc_request *mrq, u32 slot, u64 *ice_ctx); + int (*crypto_cfg_end)(struct mmc_host *mmc, struct mmc_request *mrq); void (*crypto_cfg_reset)(struct mmc_host *mmc, unsigned int slot); void (*post_cqe_halt)(struct mmc_host *mmc); }; diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index 44ecebd1ea8c..c8b8ac66ff7e 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -309,6 +309,9 @@ static void mxs_mmc_ac(struct mxs_mmc_host *host) cmd0 = BF_SSP(cmd->opcode, CMD0_CMD); cmd1 = cmd->arg; + if (cmd->opcode == MMC_STOP_TRANSMISSION) + cmd0 |= BM_SSP_CMD0_APPEND_8CYC; + if (host->sdio_irq_en) { ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN; @@ -417,8 +420,7 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) ssp->base + HW_SSP_BLOCK_SIZE); } - if ((cmd->opcode == MMC_STOP_TRANSMISSION) || - (cmd->opcode == SD_IO_RW_EXTENDED)) + if (cmd->opcode == SD_IO_RW_EXTENDED) cmd0 |= BM_SSP_CMD0_APPEND_8CYC; cmd1 = cmd->arg; diff --git a/drivers/mmc/host/sdhci-msm-ice.c b/drivers/mmc/host/sdhci-msm-ice.c index a6ef06aa6f1d..2799b21fb6e3 100644 --- a/drivers/mmc/host/sdhci-msm-ice.c +++ b/drivers/mmc/host/sdhci-msm-ice.c @@ -414,6 +414,37 @@ int sdhci_msm_ice_cmdq_cfg(struct sdhci_host *host, return 0; } +int sdhci_msm_ice_cfg_end(struct sdhci_host *host, struct mmc_request *mrq) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = pltfm_host->priv; + int err = 0; + struct request *req; + + if (!host->is_crypto_en) + return 0; + + if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) { + pr_err("%s: ice is in invalid state %d\n", + mmc_hostname(host->mmc), msm_host->ice.state); + return -EINVAL; + } + + req = mrq->req; + if (req) { + if (msm_host->ice.vops->config_end) { + err = msm_host->ice.vops->config_end(req); + if (err) { + pr_err("%s: ice config end failed %d\n", + mmc_hostname(host->mmc), err); + return err; + } + } + } + + return 0; +} + int sdhci_msm_ice_reset(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); diff --git a/drivers/mmc/host/sdhci-msm-ice.h b/drivers/mmc/host/sdhci-msm-ice.h index d8d640437522..7699464cf71e 100644 --- a/drivers/mmc/host/sdhci-msm-ice.h +++ b/drivers/mmc/host/sdhci-msm-ice.h @@ -107,6 +107,7 @@ int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq, u32 slot); int sdhci_msm_ice_cmdq_cfg(struct sdhci_host *host, struct mmc_request *mrq, u32 slot, u64 *ice_ctx); +int sdhci_msm_ice_cfg_end(struct sdhci_host *host, struct mmc_request *mrq); int sdhci_msm_ice_reset(struct sdhci_host *host); int sdhci_msm_ice_resume(struct sdhci_host *host); int sdhci_msm_ice_suspend(struct sdhci_host *host); @@ -143,6 +144,11 @@ inline int sdhci_msm_ice_cmdq_cfg(struct sdhci_host *host, { return 0; } +inline int sdhci_msm_ice_cfg_end(struct sdhci_host *host, + struct mmc_request *mrq) +{ + return 0; +} inline int sdhci_msm_ice_reset(struct sdhci_host *host) { return 0; diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 15d1eface2d4..987d61bdda2d 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -1960,6 +1960,8 @@ struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev, if (of_get_property(np, "qcom,core_3_0v_support", NULL)) pdata->core_3_0v_support = true; + pdata->sdr104_wa = of_property_read_bool(np, "qcom,sdr104-wa"); + return pdata; out: return NULL; @@ -2736,14 +2738,15 @@ static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type) msm_host->offset; unsigned long flags; bool done = false; - u32 io_sig_sts; + u32 io_sig_sts = SWITCHABLE_SIGNALLING_VOL; spin_lock_irqsave(&host->lock, flags); pr_debug("%s: %s: request %d curr_pwr_state %x curr_io_level %x\n", mmc_hostname(host->mmc), __func__, req_type, msm_host->curr_pwr_state, msm_host->curr_io_level); - io_sig_sts = sdhci_msm_readl_relaxed(host, - msm_host_offset->CORE_GENERICS); + if (!msm_host->mci_removed) + io_sig_sts = sdhci_msm_readl_relaxed(host, + msm_host_offset->CORE_GENERICS); /* * The IRQ for request type IO High/Low will be generated when - @@ -3304,6 +3307,21 @@ static void sdhci_msm_cmdq_dump_debug_ram(struct sdhci_host *host) pr_err("-------------------------\n"); } +static void sdhci_msm_cache_debug_data(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = pltfm_host->priv; + struct sdhci_msm_debug_data *cached_data = &msm_host->cached_data; + + memcpy(&cached_data->copy_mmc, msm_host->mmc, + sizeof(struct mmc_host)); + if (msm_host->mmc->card) + memcpy(&cached_data->copy_card, msm_host->mmc->card, + sizeof(struct mmc_card)); + memcpy(&cached_data->copy_host, host, + sizeof(struct sdhci_host)); +} + void sdhci_msm_dump_vendor_regs(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -3316,6 +3334,7 @@ void sdhci_msm_dump_vendor_regs(struct sdhci_host *host) u32 debug_reg[MAX_TEST_BUS] = {0}; u32 sts = 0; + sdhci_msm_cache_debug_data(host); pr_info("----------- VENDOR REGISTER DUMP -----------\n"); if (host->cq_host) sdhci_msm_cmdq_dump_debug_ram(host); @@ -3897,8 +3916,8 @@ void sdhci_msm_pm_qos_cpu_init(struct sdhci_host *host, group->req.type = PM_QOS_REQ_AFFINE_CORES; cpumask_copy(&group->req.cpus_affine, &msm_host->pdata->pm_qos_data.cpu_group_map.mask[i]); - /* For initialization phase, set the performance mode latency */ - group->latency = latency[i].latency[SDHCI_PERFORMANCE_MODE]; + /* We set default latency here for all pm_qos cpu groups. */ + group->latency = PM_QOS_DEFAULT_VALUE; pm_qos_add_request(&group->req, PM_QOS_CPU_DMA_LATENCY, group->latency); pr_info("%s (): voted for group #%d (mask=0x%lx) latency=%d (0x%p)\n", @@ -4008,6 +4027,7 @@ static unsigned int sdhci_msm_get_current_limit(struct sdhci_host *host) static struct sdhci_ops sdhci_msm_ops = { .crypto_engine_cfg = sdhci_msm_ice_cfg, .crypto_engine_cmdq_cfg = sdhci_msm_ice_cmdq_cfg, + .crypto_engine_cfg_end = sdhci_msm_ice_cfg_end, .crypto_cfg_reset = sdhci_msm_ice_cfg_reset, .crypto_engine_reset = sdhci_msm_ice_reset, .set_uhs_signaling = sdhci_msm_set_uhs_signaling, @@ -4561,6 +4581,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) if (msm_host->pdata->nonhotplug) msm_host->mmc->caps2 |= MMC_CAP2_NONHOTPLUG; + msm_host->mmc->sdr104_wa = msm_host->pdata->sdr104_wa; /* Initialize ICE if present */ if (msm_host->ice.pdev) { diff --git a/drivers/mmc/host/sdhci-msm.h b/drivers/mmc/host/sdhci-msm.h index c26636198a22..92f61708001e 100644 --- a/drivers/mmc/host/sdhci-msm.h +++ b/drivers/mmc/host/sdhci-msm.h @@ -153,6 +153,7 @@ struct sdhci_msm_pltfm_data { u32 ice_clk_min; struct sdhci_msm_pm_qos_data pm_qos_data; bool core_3_0v_support; + bool sdr104_wa; }; struct sdhci_msm_bus_vote { @@ -171,6 +172,12 @@ struct sdhci_msm_ice_data { int state; }; +struct sdhci_msm_debug_data { + struct mmc_host copy_mmc; + struct mmc_card copy_card; + struct sdhci_host copy_host; +}; + struct sdhci_msm_host { struct platform_device *pdev; void __iomem *core_mem; /* MSM SDCC mapped address */ @@ -186,6 +193,7 @@ struct sdhci_msm_host { atomic_t clks_on; /* Set if clocks are enabled */ struct sdhci_msm_pltfm_data *pdata; struct mmc_host *mmc; + struct sdhci_msm_debug_data cached_data; struct sdhci_pltfm_data sdhci_msm_pdata; u32 curr_pwr_state; u32 curr_io_level; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1fdc23365c8f..40a34c283955 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1668,6 +1668,22 @@ out: return err; } +static int sdhci_crypto_cfg_end(struct sdhci_host *host, + struct mmc_request *mrq) +{ + int err = 0; + + if (host->ops->crypto_engine_cfg_end) { + err = host->ops->crypto_engine_cfg_end(host, mrq); + if (err) { + pr_err("%s: failed to configure crypto\n", + mmc_hostname(host->mmc)); + return err; + } + } + return 0; +} + static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct sdhci_host *host; @@ -2491,7 +2507,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; } @@ -2787,6 +2823,7 @@ static void sdhci_tasklet_finish(unsigned long param) mmiowb(); spin_unlock_irqrestore(&host->lock, flags); + sdhci_crypto_cfg_end(host, mrq); mmc_request_done(host->mmc, mrq); sdhci_runtime_pm_put(host); } @@ -3046,7 +3083,10 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) mmc_hostname(host->mmc), intmask, host->data->error, ktime_to_ms(ktime_sub( ktime_get(), host->data_start_time))); - sdhci_dumpregs(host); + + if (!host->mmc->sdr104_wa || + (host->mmc->ios.timing != MMC_TIMING_UHS_SDR104)) + sdhci_dumpregs(host); } sdhci_finish_data(host); } else { @@ -3266,7 +3306,8 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) pr_err("%s: Card is consuming too much power!\n", mmc_hostname(host->mmc)); - if (intmask & SDHCI_INT_CARD_INT) { + if ((intmask & SDHCI_INT_CARD_INT) && + (host->ier & SDHCI_INT_CARD_INT)) { sdhci_enable_sdio_irq_nolock(host, false); host->thread_isr |= SDHCI_INT_CARD_INT; result = IRQ_WAKE_THREAD; @@ -3665,6 +3706,17 @@ out: return err; } +static int sdhci_cmdq_crypto_cfg_end(struct mmc_host *mmc, + struct mmc_request *mrq) +{ + struct sdhci_host *host = mmc_priv(mmc); + + if (!host->is_crypto_en) + return 0; + + return sdhci_crypto_cfg_end(host, mrq); +} + static void sdhci_cmdq_crypto_cfg_reset(struct mmc_host *mmc, unsigned int slot) { struct sdhci_host *host = mmc_priv(mmc); @@ -3730,6 +3782,12 @@ static int sdhci_cmdq_crypto_cfg(struct mmc_host *mmc, return 0; } +static int sdhci_cmdq_crypto_cfg_end(struct mmc_host *mmc, + struct mmc_request *mrq) +{ + return 0; +} + static void sdhci_cmdq_crypto_cfg_reset(struct mmc_host *mmc, unsigned int slot) { @@ -3747,6 +3805,7 @@ static const struct cmdq_host_ops sdhci_cmdq_ops = { .clear_set_dumpregs = sdhci_cmdq_clear_set_dumpregs, .enhanced_strobe_mask = sdhci_enhanced_strobe_mask, .crypto_cfg = sdhci_cmdq_crypto_cfg, + .crypto_cfg_end = sdhci_cmdq_crypto_cfg_end, .crypto_cfg_reset = sdhci_cmdq_crypto_cfg_reset, .post_cqe_halt = sdhci_cmdq_post_cqe_halt, .set_transfer_params = sdhci_cmdq_set_transfer_params, diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index c4bbdd80f29c..93129b26dc5e 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -659,6 +659,8 @@ struct sdhci_ops { struct mmc_request *mrq, u32 slot); int (*crypto_engine_cmdq_cfg)(struct sdhci_host *host, struct mmc_request *mrq, u32 slot, u64 *ice_ctx); + int (*crypto_engine_cfg_end)(struct sdhci_host *host, + struct mmc_request *mrq); int (*crypto_engine_reset)(struct sdhci_host *host); void (*crypto_cfg_reset)(struct sdhci_host *host, unsigned int slot); void (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs); |
