From 3a3db6030b64ceb4b4e41a6811168c5d90a9f7f8 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 5 Apr 2018 13:24:43 +0200 Subject: mmc: core: Rename ->reset() bus ops to ->hw_reset() The bus ops ->reset() executes a full HW reset of the card, as the calling function mmc_hw_reset() also indicates by its name. Let's convert to follow the similar names, for both the bus ops callback and for the corresponding bus ops functions, as to clarify the purpose of code. Signed-off-by: Ulf Hansson Tested-by: Quentin Schulz Reviewed-by: Shawn Lin --- drivers/mmc/core/core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/mmc/core/core.c') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 121ce50b6d5e..3e17c62eea86 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2435,16 +2435,16 @@ int mmc_hw_reset(struct mmc_host *host) return -EINVAL; mmc_bus_get(host); - if (!host->bus_ops || host->bus_dead || !host->bus_ops->reset) { + if (!host->bus_ops || host->bus_dead || !host->bus_ops->hw_reset) { mmc_bus_put(host); return -EOPNOTSUPP; } - ret = host->bus_ops->reset(host); + ret = host->bus_ops->hw_reset(host); mmc_bus_put(host); if (ret) - pr_warn("%s: tried to reset card, got error %d\n", + pr_warn("%s: tried to HW reset card, got error %d\n", mmc_hostname(host), ret); return ret; -- cgit v1.2.3 From 1433269c4d2461be1f36db5dbb453976b38996ff Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 5 Apr 2018 13:42:00 +0200 Subject: mmc: core: Export a function mmc_sw_reset() to allow soft reset of cards It's rather common that a firmware is loaded into an SDIO func device memory, by the corresponding SDIO func driver during ->probe() time. However, to actually start running the new firmware, sometimes a soft reset (no power cycle) and a re-initialization of the card is needed. This is for example the case with the Espressif ESP8089 WiFi chips, when connected to an SDIO interface. To cope with this scenario, let's add a new exported function, mmc_sw_reset(), which may be called when a soft reset and re-initialization of the card are needed. The mmc_sw_reset() is implemented on top of a new bus ops callback, similar to how the mmc_hw_reset() has been implemented. Signed-off-by: Ulf Hansson Tested-by: Quentin Schulz Reviewed-by: Shawn Lin --- drivers/mmc/core/core.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/mmc/core/core.c') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 3e17c62eea86..7a79dc1599e5 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2451,6 +2451,30 @@ int mmc_hw_reset(struct mmc_host *host) } EXPORT_SYMBOL(mmc_hw_reset); +int mmc_sw_reset(struct mmc_host *host) +{ + int ret; + + if (!host->card) + return -EINVAL; + + mmc_bus_get(host); + if (!host->bus_ops || host->bus_dead || !host->bus_ops->sw_reset) { + mmc_bus_put(host); + return -EOPNOTSUPP; + } + + ret = host->bus_ops->sw_reset(host); + mmc_bus_put(host); + + if (ret) + pr_warn("%s: tried to SW reset card, got error %d\n", + mmc_hostname(host), ret); + + return ret; +} +EXPORT_SYMBOL(mmc_sw_reset); + static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) { host->f_init = freq; -- cgit v1.2.3 From 508c9864ccede5dd4b8a7220b3fe6998763e4407 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 5 Apr 2018 21:24:15 +0200 Subject: mmc: core: Share internal function to set initial signal voltage Move the corresponding code for setting the initial signal voltage, from mmc_power_up() into a new function, mmc_set_initial_signal_voltage(). Make the function internally available to the mmc core, as to allow the following changes to make use of it. Signed-off-by: Ulf Hansson Tested-by: Quentin Schulz Reviewed-by: Shawn Lin --- drivers/mmc/core/core.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers/mmc/core/core.c') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 7a79dc1599e5..2c1a220531c4 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1484,6 +1484,17 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage) } +void mmc_set_initial_signal_voltage(struct mmc_host *host) +{ + /* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */ + if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330)) + dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n"); + else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)) + dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n"); + else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120)) + dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n"); +} + int mmc_host_set_uhs_voltage(struct mmc_host *host) { u32 clock; @@ -1646,13 +1657,7 @@ void mmc_power_up(struct mmc_host *host, u32 ocr) /* Set initial state and call mmc_set_ios */ mmc_set_initial_state(host); - /* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */ - if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330)) - dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n"); - else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)) - dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n"); - else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120)) - dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n"); + mmc_set_initial_signal_voltage(host); /* * This delay should be sufficient to allow the power supply -- cgit v1.2.3 From 3ce7f76ff9033cbf966c1121ea59051b533f95ef Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 2 May 2018 15:13:06 +0200 Subject: mmc: core: Drop unused define for timeout MMC_CORE_TIMEOUT_MS isn't being used no more, let's drop it. Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/mmc/core/core.c') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 2c1a220531c4..42cfcb64abe0 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -50,9 +50,6 @@ #include "sd_ops.h" #include "sdio_ops.h" -/* If the device is not responding */ -#define MMC_CORE_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */ - /* The max erase timeout, used when host->max_busy_timeout isn't specified */ #define MMC_ERASE_TIMEOUT_MS (60 * 1000) /* 60 s */ -- cgit v1.2.3 From 6d796c68cd15234a33a4bd2ef7231125fea2dc6c Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Tue, 8 May 2018 09:04:20 +0800 Subject: mmc: core: add tunable delay waiting for power to be stable The hard-coded 10ms delay in mmc_power_up came from commit 79bccc5aefb4 ("mmc: increase power up delay"), which said "The TI controller on Toshiba Tecra M5 needs more time to power up or the cards will init incorrectly or not at all." But it's too engineering solution for a special board but force all platforms to wait for that long time, especially painful for mmc_power_up for eMMC when booting. However, it's added since 2009, and we can't tell if other platforms benefit from it. But in practise, the modern hardware are most likely to have a stable power supply with 1ms after setting it for no matter PMIC or discrete power. And more importnatly, most regulators implement the callback of ->set_voltage_time_sel() for regulator core to wait for specific period of time for the power supply to be stable, which means once regulator_set_voltage_* return, the power should reach the the minimum voltage that works for initialization. Of course, if there are some other ways for host to power the card, we should allow them to argue a suitable delay as well. With this patch, we could assign the delay from firmware, or we could assigne it via ->set_ios() callback from host drivers. Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/core/core.c') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 42cfcb64abe0..9a769edbabe0 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1660,7 +1660,7 @@ void mmc_power_up(struct mmc_host *host, u32 ocr) * This delay should be sufficient to allow the power supply * to reach the minimum voltage. */ - mmc_delay(10); + mmc_delay(host->ios.power_delay_ms); mmc_pwrseq_post_power_on(host); @@ -1673,7 +1673,7 @@ void mmc_power_up(struct mmc_host *host, u32 ocr) * This delay must be at least 74 clock sizes, or 1 ms, or the * time required to reach a stable voltage. */ - mmc_delay(10); + mmc_delay(host->ios.power_delay_ms); } void mmc_power_off(struct mmc_host *host) -- cgit v1.2.3 From 833b51170feeee1718990480f792bb05cb0ca17c Mon Sep 17 00:00:00 2001 From: Martin Hicks Date: Mon, 28 May 2018 13:23:04 +0200 Subject: mmc: Throttle calls to MMC_SEND_STATUS during mmc_do_erase() This drastically reduces the rate at which the MMC_SEND_STATUS cmd polls for completion of the MMC Erase operation. The patch does this by adding a backoff sleep that starts by sleeping for short intervals (128-256us), and ramps up to sleeping for 32-64ms. Even on very quickly completing erase operations, the loop iterates a few times, so not too much extra latency is added to these commands. For long running discard operarations, like a full-device secure discard, this change drops the interrupt rates on my single-core NXP I.MX6UL from 45000/s to about 20/s, and greatly improves system responsiveness. Signed-off-by: Martin Hicks Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/core/core.c') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 9a769edbabe0..281826d1fcca 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1969,6 +1969,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, unsigned int qty = 0, busy_timeout = 0; bool use_r1b_resp = false; unsigned long timeout; + int loop_udelay=64, udelay_max=32768; int err; mmc_retune_hold(card->host); @@ -2093,9 +2094,15 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, err = -EIO; goto out; } + if ((cmd.resp[0] & R1_READY_FOR_DATA) && + R1_CURRENT_STATE(cmd.resp[0]) != R1_STATE_PRG) + break; + + usleep_range(loop_udelay, loop_udelay*2); + if (loop_udelay < udelay_max) + loop_udelay *= 2; + } while (1); - } while (!(cmd.resp[0] & R1_READY_FOR_DATA) || - (R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG)); out: mmc_retune_release(card->host); return err; -- cgit v1.2.3