From d94ffceb040d0db0cc0112660bb2bcf49d913a8f Mon Sep 17 00:00:00 2001 From: Can Guo Date: Mon, 3 Jul 2017 15:06:55 +0800 Subject: [PATCH 1/2] mmc: core: Fix card remove detect when use extcon Since SDM845 uses extcon for card insertion and remove detection and cd_gpio in device tree is not given, so the mmc_gpio_get_cd function cannot detect card remove by reading gpio value. Fix it by checking extcon state if extcon is initialized during sdhci msm probe. Change-Id: Ib44d211f707393cb440c387a06fa70d3adc99736 Signed-off-by: Can Guo --- drivers/mmc/core/slot-gpio.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index b5c81e444c80..91ad9465476a 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -77,6 +77,15 @@ EXPORT_SYMBOL(mmc_gpio_get_ro); int mmc_gpio_get_cd(struct mmc_host *host) { struct mmc_gpio *ctx = host->slot.handler_priv; + int ret; + + if (host->extcon) { + ret = extcon_get_state(host->extcon, EXTCON_MECHANICAL); + if (ret < 0) + dev_err(mmc_dev(host), "%s: Extcon failed to check card state, ret=%d\n", + __func__, ret); + return ret; + } if (!ctx || !ctx->cd_gpio) return -ENOSYS; From 6514fbefbcb604786ee560e1593a361bc7d05719 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Tue, 4 Jul 2017 12:36:09 +0800 Subject: [PATCH 2/2] mmc: core: extend SDR104 workaround for other paths 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, commit ("mmc: sd: reduce the bus speed in case of multiple CRC errors") would reinit the card to lower speed (SDR50) hoping that CRC error rate would reduce at lower clock speed (100MHz for SDR50). As the error may happen for any cmd, this change tries to fix several other paths - clock scaling, mmc_rescan, non-data commands error path. This change was backed out from msm-4.9 because SDM845 is unable to detect mmc card remove by reading cd_gpio. Now it is safe to be merged in once again because mmc card detect is fixed. Change-Id: I87505cdc8614ff0c41ad345b2c181603d0235983 Signed-off-by: Sahitya Tummala Signed-off-by: Subhash Jadavani Signed-off-by: Veerabhadrarao Badiganti Signed-off-by: Can Guo --- drivers/mmc/card/block.c | 5 +++- drivers/mmc/core/core.c | 58 +++++++++++++++++++++++++++++++++------- include/linux/mmc/core.h | 1 + 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index f3004355053f..c6f34964d839 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -1718,6 +1718,8 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, /* We couldn't get a response from the card. Give up. */ if (err) { + if (card->err_in_sdr104) + return ERR_RETRY; /* Check if the card is removed */ if (mmc_detect_card_removed(card->host)) return ERR_NOMEDIUM; @@ -2208,7 +2210,8 @@ static int mmc_blk_err_check(struct mmc_card *card, brq->data.error == -ETIMEDOUT || brq->cmd.error == -EILSEQ || brq->cmd.error == -EIO || - brq->cmd.error == -ETIMEDOUT)) + brq->cmd.error == -ETIMEDOUT || + brq->sbc.error)) card->err_in_sdr104 = true; /* diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 787779c6699b..a2219daf5296 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -456,6 +456,22 @@ out: } EXPORT_SYMBOL(mmc_clk_update_freq); +void mmc_recovery_fallback_lower_speed(struct mmc_host *host) +{ + if (!host->card) + return; + + if (host->sdr104_wa && mmc_card_sd(host->card) && + (host->ios.timing == MMC_TIMING_UHS_SDR104) && + !host->card->sdr104_blocked) { + pr_err("%s: %s: blocked SDR104, lower the bus-speed (SDR50 / DDR50)\n", + mmc_hostname(host), __func__); + mmc_host_clear_sdr104(host); + mmc_hw_reset(host); + host->card->sdr104_blocked = true; + } +} + static int mmc_devfreq_set_target(struct device *dev, unsigned long *freq, u32 devfreq_flags) { @@ -507,6 +523,9 @@ static int mmc_devfreq_set_target(struct device *dev, if (abort) goto out; + if (mmc_card_sd(host->card) && host->card->sdr104_blocked) + goto rel_host; + /* * In case we were able to claim host there is no need to * defer the frequency change. It will be done now @@ -515,15 +534,18 @@ static int mmc_devfreq_set_target(struct device *dev, mmc_host_clk_hold(host); err = mmc_clk_update_freq(host, *freq, clk_scaling->state); - if (err && err != -EAGAIN) + if (err && err != -EAGAIN) { pr_err("%s: clock scale to %lu failed with error %d\n", mmc_hostname(host), *freq, err); - else + mmc_recovery_fallback_lower_speed(host); + } else { pr_debug("%s: clock change to %lu finished successfully (%s)\n", mmc_hostname(host), *freq, current->comm); + } mmc_host_clk_release(host); +rel_host: mmc_release_host(host); out: return err; @@ -544,6 +566,9 @@ void mmc_deferred_scaling(struct mmc_host *host) if (!host->clk_scaling.enable) return; + if (mmc_card_sd(host->card) && host->card->sdr104_blocked) + return; + spin_lock_bh(&host->clk_scaling.lock); if (host->clk_scaling.clk_scaling_in_progress || @@ -564,13 +589,15 @@ void mmc_deferred_scaling(struct mmc_host *host) err = mmc_clk_update_freq(host, target_freq, host->clk_scaling.state); - if (err && err != -EAGAIN) + if (err && err != -EAGAIN) { pr_err("%s: failed on deferred scale clocks (%d)\n", mmc_hostname(host), err); - else + mmc_recovery_fallback_lower_speed(host); + } else { pr_debug("%s: clocks were successfully scaled to %lu (%s)\n", mmc_hostname(host), target_freq, current->comm); + } host->clk_scaling.clk_scaling_in_progress = false; atomic_dec(&host->clk_scaling.devfreq_abort); } @@ -1571,8 +1598,13 @@ void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq) } } if (!cmd->error || !cmd->retries || - mmc_card_removed(host->card)) + mmc_card_removed(host->card)) { + if (cmd->error && !cmd->retries && + cmd->opcode != MMC_SEND_STATUS && + cmd->opcode != MMC_SEND_TUNING_BLOCK) + mmc_recovery_fallback_lower_speed(host); break; + } mmc_retune_recheck(host); @@ -4257,12 +4289,18 @@ 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; + if (host->ops->get_cd && host->ops->get_cd(host)) { + mmc_recovery_fallback_lower_speed(host); + ret = 0; + } else { + 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)); } - pr_debug("%s: card remove detected\n", mmc_hostname(host)); } return ret; diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 0f2e65101b7c..b71810518922 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -233,6 +233,7 @@ extern void mmc_cmdq_clk_scaling_start_busy(struct mmc_host *host, bool lock_needed); extern void mmc_cmdq_clk_scaling_stop_busy(struct mmc_host *host, bool lock_needed, bool is_cmdq_dcmd); +extern void mmc_recovery_fallback_lower_speed(struct mmc_host *host); /** * mmc_claim_host - exclusively claim a host