From a4b36d773babd517b8208d487ea6beb060aab610 Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Fri, 31 Mar 2017 16:50:59 -0700 Subject: mmc: sdhci-msm: add SDR104 CRC workaround enablement control On Certain chipsets, SDR104 mode might be unstable causing CRC error on the interface. So we need a workaround which would skip printing register dumps on CRC errors and also downgrade bus speed mode to SDR50/DDR50 in case of continuous CRC errors. This patch adds "qcom,sdr104-wa" property to enable this workaround if required. Change-Id: I626d8ef45a97e8e6558e7f20be496de1f5a2a438 Signed-off-by: Subhash Jadavani --- Documentation/devicetree/bindings/mmc/sdhci-msm.txt | 5 +++++ drivers/mmc/host/sdhci-msm.c | 3 +++ drivers/mmc/host/sdhci-msm.h | 1 + include/linux/mmc/host.h | 1 + 4 files changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index 0b46fd3d8ebf..d00e26b4d5ed 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -75,6 +75,11 @@ Optional Properties: during clock scaling. If this property is not defined, then it falls back to the default HS bus speed mode to maintain backward compatibility. + - qcom,sdr104-wa: On Certain chipsets, SDR104 mode might be unstable causing CRC errors + on the interface. So there is a workaround implemented to skip printing + register dumps on CRC errors and also downgrade bus speed mode to + SDR50/DDR50 in case of continuous CRC errors. Set this flag to enable + this workaround. In the following, can be vdd (flash core voltage) or vdd-io (I/O voltage). - qcom,-always-on - specifies whether supply should be kept "on" always. diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 2eaac11ec8ba..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; @@ -4579,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 2e4f2179378e..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 { diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 055b879dfa6b..37069eb12861 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -595,6 +595,7 @@ struct mmc_host { struct io_latency_state io_lat_s; #endif + bool sdr104_wa; unsigned long private[0] ____cacheline_aligned; }; -- cgit v1.2.3 From 0cbf1d2db710f0b9fb0b63934d214b2ef19cd650 Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Thu, 30 Mar 2017 14:41:16 -0700 Subject: mmc: sd: reduce the bus speed in case of multiple CRC errors in SDR104 UHS-I SD cards support SDR104 mode which runs the SD card interface clock upto 208 MHz. But we may see repeated CRC errors in SDR104 with some SDCC controllers. If this happens, this change would reinit the card to lower speed (SDR50) hoping that CRC error rate would reduce at lower clock speed (100MHz for SDR50). Change-Id: I140d29fdf500bb89881a0f2c1f768fe0c5afa9d5 Signed-off-by: Asutosh Das Signed-off-by: Subhash Jadavani --- drivers/mmc/card/block.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++- drivers/mmc/core/core.c | 4 ++++ drivers/mmc/core/core.h | 1 - drivers/mmc/core/sd.c | 2 ++ include/linux/mmc/card.h | 2 ++ include/linux/mmc/core.h | 1 + include/linux/mmc/host.h | 10 +++++++++ 7 files changed, 76 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 5d6c44b00bc2..e9f1a19dfe3f 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -2189,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. @@ -3645,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 @@ -3690,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: @@ -3730,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/core/core.c b/drivers/mmc/core/core.c index 5396e1d00178..11a83126ad1b 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -4033,6 +4033,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/sd.c b/drivers/mmc/core/sd.c index 9e147a667edf..5b4d5d74fe55 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -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/include/linux/mmc/card.h b/include/linux/mmc/card.h index 1c87478b5fc0..e7e172a23a16 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -435,6 +435,8 @@ struct mmc_card { u8 *cached_ext_csd; bool cmdq_init; struct mmc_bkops_info bkops; + bool err_in_sdr104; + bool sdr104_blocked; }; /* diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 1068953943d8..2a1a6fec179f 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -169,6 +169,7 @@ extern int __mmc_switch_cmdq_mode(struct mmc_command *cmd, u8 set, u8 index, extern int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error); extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd); extern int mmc_set_auto_bkops(struct mmc_card *card, bool enable); +extern int mmc_suspend_clk_scaling(struct mmc_host *host); #define MMC_ERASE_ARG 0x00000000 #define MMC_SECURE_ERASE_ARG 0x80000000 diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 37069eb12861..d9e12c1b1748 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -729,6 +729,16 @@ static inline int mmc_host_uhs(struct mmc_host *host) MMC_CAP_UHS_DDR50); } +static inline void mmc_host_clear_sdr104(struct mmc_host *host) +{ + host->caps &= ~MMC_CAP_UHS_SDR104; +} + +static inline void mmc_host_set_sdr104(struct mmc_host *host) +{ + host->caps |= MMC_CAP_UHS_SDR104; +} + static inline int mmc_host_packed_wr(struct mmc_host *host) { return host->caps2 & MMC_CAP2_PACKED_WR; -- cgit v1.2.3 From 00b15340ab3f6b69d4ff188c3b34281b824dd598 Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Thu, 30 Mar 2017 14:42:44 -0700 Subject: mmc: sdhci: skip printing register dumps on CRC errors On Certain chipsets, SDR104 mode might be unstable causing CRC error on the interface. So we need a workaround to skip printing register dumps on CRC errors to reduce the recovery time. Change-Id: I73986d89a080a842e01cdf88ad8d3b953755e993 Signed-off-by: Subhash Jadavani --- drivers/mmc/host/sdhci.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 44633dc5d2be..40a34c283955 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3083,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 { -- cgit v1.2.3 From df018af6406858c212034c47385a62917390160c Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Fri, 31 Mar 2017 17:28:31 -0700 Subject: ARM: dts: msm: enable SDR104 workaround for MSM8998 On MSM8998, SDR104 mode might be unstable causing CRC error on the interface. So we need a workaround which would skip printing register dumps on CRC errors and also downgrade bus speed mode to SDR50/DDR50 in case of continuos CRC errors. This patch enables "qcom,sdr104-wa" property to enable this workaround. Change-Id: Ib2dbf974d1312c00ca22a114f0b9e8130624090c Signed-off-by: Subhash Jadavani --- arch/arm/boot/dts/qcom/msm8998.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi index 02b7a44ee0d2..d1194b3ffcec 100644 --- a/arch/arm/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998.dtsi @@ -1575,6 +1575,8 @@ qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 100000000 200000000 4294967295>; + qcom,sdr104-wa; + status = "disabled"; }; -- cgit v1.2.3