* [PATCH V7 01/14] mmc: host: Add facility to support re-tuning
2015-05-07 10:10 [PATCH V7 00/14] mmc: host: Add facility to support re-tuning Adrian Hunter
@ 2015-05-07 10:10 ` Adrian Hunter
2015-05-07 10:10 ` [PATCH V7 02/14] mmc: core: Enable / disable re-tuning Adrian Hunter
` (13 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Adrian Hunter @ 2015-05-07 10:10 UTC (permalink / raw)
To: Ulf Hansson
Cc: linux-mmc, Aaron Lu, Philip Rakity, Al Cooper, Arend van Spriel
Currently, there is core support for tuning during
initialization. There can also be a need to re-tune
periodically (e.g. sdhci) or to re-tune after the
host controller is powered off (e.g. after PM
runtime suspend / resume) or to re-tune in response
to CRC errors.
The main requirements for re-tuning are:
- ability to enable / disable re-tuning
- ability to flag that re-tuning is needed
- ability to re-tune before any request
- ability to hold off re-tuning if the card is busy
- ability to hold off re-tuning if re-tuning is in
progress
- ability to run a re-tuning timer
To support those requirements 7 members are added to struct
mmc_host:
unsigned int can_retune:1; /* re-tuning can be used */
unsigned int doing_retune:1; /* re-tuning in progress */
unsigned int retune_now:1; /* do re-tuning at next req */
int need_retune; /* re-tuning is needed */
int hold_retune; /* hold off re-tuning */
unsigned int retune_period; /* re-tuning period in secs */
struct timer_list retune_timer; /* for periodic re-tuning */
need_retune is an integer so it can be set without needing
synchronization. hold_retune is a integer to allow nesting.
Various simple functions are provided to set / clear those
variables.
Subsequent patches take those functions into use.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
drivers/mmc/core/host.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++
drivers/mmc/core/host.h | 6 +++++
include/linux/mmc/host.h | 23 ++++++++++++++++
3 files changed, 97 insertions(+)
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 8be0df7..e90e02f 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -301,6 +301,73 @@ static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
#endif
+void mmc_retune_enable(struct mmc_host *host)
+{
+ host->can_retune = 1;
+ if (host->retune_period)
+ mod_timer(&host->retune_timer,
+ jiffies + host->retune_period * HZ);
+}
+
+void mmc_retune_disable(struct mmc_host *host)
+{
+ host->can_retune = 0;
+ del_timer_sync(&host->retune_timer);
+ host->retune_now = 0;
+ host->need_retune = 0;
+}
+
+void mmc_retune_timer_stop(struct mmc_host *host)
+{
+ del_timer_sync(&host->retune_timer);
+}
+EXPORT_SYMBOL(mmc_retune_timer_stop);
+
+void mmc_retune_hold(struct mmc_host *host)
+{
+ if (!host->hold_retune)
+ host->retune_now = 1;
+ host->hold_retune += 1;
+}
+
+void mmc_retune_release(struct mmc_host *host)
+{
+ if (host->hold_retune)
+ host->hold_retune -= 1;
+ else
+ WARN_ON(1);
+}
+
+int mmc_retune(struct mmc_host *host)
+{
+ int err;
+
+ if (host->retune_now)
+ host->retune_now = 0;
+ else
+ return 0;
+
+ if (!host->need_retune || host->doing_retune || !host->card)
+ return 0;
+
+ host->need_retune = 0;
+
+ host->doing_retune = 1;
+
+ err = mmc_execute_tuning(host->card);
+
+ host->doing_retune = 0;
+
+ return err;
+}
+
+static void mmc_retune_timer(unsigned long data)
+{
+ struct mmc_host *host = (struct mmc_host *)data;
+
+ mmc_retune_needed(host);
+}
+
/**
* mmc_of_parse() - parse host's device-tree node
* @host: host whose node should be parsed.
@@ -504,6 +571,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
#ifdef CONFIG_PM
host->pm_notify.notifier_call = mmc_pm_notify;
#endif
+ setup_timer(&host->retune_timer, mmc_retune_timer, (unsigned long)host);
/*
* By default, hosts do not support SGIO or large requests.
diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h
index f2ab9e5..992bf53 100644
--- a/drivers/mmc/core/host.h
+++ b/drivers/mmc/core/host.h
@@ -15,5 +15,11 @@
int mmc_register_host_class(void);
void mmc_unregister_host_class(void);
+void mmc_retune_enable(struct mmc_host *host);
+void mmc_retune_disable(struct mmc_host *host);
+void mmc_retune_hold(struct mmc_host *host);
+void mmc_retune_release(struct mmc_host *host);
+int mmc_retune(struct mmc_host *host);
+
#endif
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index b5bedae..f471193 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -12,6 +12,7 @@
#include <linux/leds.h>
#include <linux/mutex.h>
+#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/device.h>
#include <linux/fault-inject.h>
@@ -321,10 +322,18 @@ struct mmc_host {
#ifdef CONFIG_MMC_DEBUG
unsigned int removed:1; /* host is being removed */
#endif
+ unsigned int can_retune:1; /* re-tuning can be used */
+ unsigned int doing_retune:1; /* re-tuning in progress */
+ unsigned int retune_now:1; /* do re-tuning at next req */
int rescan_disable; /* disable card detection */
int rescan_entered; /* used with nonremovable devices */
+ int need_retune; /* re-tuning is needed */
+ int hold_retune; /* hold off re-tuning */
+ unsigned int retune_period; /* re-tuning period in secs */
+ struct timer_list retune_timer; /* for periodic re-tuning */
+
bool trigger_card_event; /* card_event necessary */
struct mmc_card *card; /* device attached to this host */
@@ -513,4 +522,18 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
return card->host->ios.timing == MMC_TIMING_MMC_HS400;
}
+void mmc_retune_timer_stop(struct mmc_host *host);
+
+static inline void mmc_retune_needed(struct mmc_host *host)
+{
+ if (host->can_retune)
+ host->need_retune = 1;
+}
+
+static inline void mmc_retune_recheck(struct mmc_host *host)
+{
+ if (host->hold_retune <= 1)
+ host->retune_now = 1;
+}
+
#endif /* LINUX_MMC_HOST_H */
--
1.9.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH V7 02/14] mmc: core: Enable / disable re-tuning
2015-05-07 10:10 [PATCH V7 00/14] mmc: host: Add facility to support re-tuning Adrian Hunter
2015-05-07 10:10 ` [PATCH V7 01/14] " Adrian Hunter
@ 2015-05-07 10:10 ` Adrian Hunter
2015-05-07 10:10 ` [PATCH V7 03/14] mmc: core: Add support for re-tuning before each request Adrian Hunter
` (12 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Adrian Hunter @ 2015-05-07 10:10 UTC (permalink / raw)
To: Ulf Hansson
Cc: linux-mmc, Aaron Lu, Philip Rakity, Al Cooper, Arend van Spriel
Enable re-tuning when tuning is executed and
disable re-tuning when card is no longer initialized.
In the case of SDIO suspend, the card can keep power.
In that case, re-tuning need not be disabled, but, if
a re-tuning timer is being used, ensure it is disabled
and assume that re-tuning will be needed upon resume
since it is not known how long the suspend will last.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
drivers/mmc/core/core.c | 4 ++++
drivers/mmc/core/sdio.c | 6 +++++-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 92e7671..007c444 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1109,6 +1109,8 @@ int mmc_execute_tuning(struct mmc_card *card)
if (err)
pr_err("%s: tuning execution failed\n", mmc_hostname(host));
+ else
+ mmc_retune_enable(host);
return err;
}
@@ -1140,6 +1142,8 @@ void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
*/
void mmc_set_initial_state(struct mmc_host *host)
{
+ mmc_retune_disable(host);
+
if (mmc_host_is_spi(host))
host->ios.chip_select = MMC_CS_HIGH;
else
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index f6c28a7..5c1423a3 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -934,8 +934,12 @@ static int mmc_sdio_suspend(struct mmc_host *host)
mmc_release_host(host);
}
- if (!mmc_card_keep_power(host))
+ if (!mmc_card_keep_power(host)) {
mmc_power_off(host);
+ } else if (host->retune_period) {
+ mmc_retune_timer_stop(host);
+ mmc_retune_needed(host);
+ }
return 0;
}
--
1.9.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH V7 03/14] mmc: core: Add support for re-tuning before each request
2015-05-07 10:10 [PATCH V7 00/14] mmc: host: Add facility to support re-tuning Adrian Hunter
2015-05-07 10:10 ` [PATCH V7 01/14] " Adrian Hunter
2015-05-07 10:10 ` [PATCH V7 02/14] mmc: core: Enable / disable re-tuning Adrian Hunter
@ 2015-05-07 10:10 ` Adrian Hunter
2015-05-07 10:10 ` [PATCH V7 04/14] mmc: core: Hold re-tuning during switch commands Adrian Hunter
` (11 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Adrian Hunter @ 2015-05-07 10:10 UTC (permalink / raw)
To: Ulf Hansson
Cc: linux-mmc, Aaron Lu, Philip Rakity, Al Cooper, Arend van Spriel
At the start of each request, re-tune if needed and
then hold off re-tuning again until the request is done.
Note that though there is one function that starts
requests (mmc_start_request) there are two that wait for
the request to be done (mmc_wait_for_req_done and
mmc_wait_for_data_req_done). Also note that
mmc_wait_for_data_req_done can return even when the
request is not done (which allows the block driver
to prepare a newly arrived request while still
waiting for the previous request).
This patch ensures re-tuning is held for the duration
of a request. Subsequent patches will also hold
re-tuning at other times when it might cause a
conflict.
In addition, possibly a command is failing because
re-tuning is needed. Use mmc_retune_recheck() to check
re-tuning. At that point re-tuning is held, at least by
the request, so mmc_retune_recheck() flags host->retune_now
if the hold count is 1.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
drivers/mmc/core/core.c | 35 ++++++++++++++++++++++++++++-------
1 file changed, 28 insertions(+), 7 deletions(-)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 007c444..ec3453f 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -186,12 +186,29 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
EXPORT_SYMBOL(mmc_request_done);
+static void __mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
+{
+ int err;
+
+ /* Assumes host controller has been runtime resumed by mmc_claim_host */
+ err = mmc_retune(host);
+ if (err) {
+ mrq->cmd->error = err;
+ mmc_request_done(host, mrq);
+ return;
+ }
+
+ host->ops->request(host, mrq);
+}
+
static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
{
#ifdef CONFIG_MMC_DEBUG
unsigned int i, sz;
struct scatterlist *sg;
#endif
+ mmc_retune_hold(host);
+
if (mmc_card_removed(host->card))
return -ENOMEDIUM;
@@ -252,7 +269,7 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
}
mmc_host_clk_hold(host);
led_trigger_event(host->led, LED_FULL);
- host->ops->request(host, mrq);
+ __mmc_start_request(host, mrq);
return 0;
}
@@ -417,22 +434,22 @@ static int mmc_wait_for_data_req_done(struct mmc_host *host,
host->areq);
break; /* return err */
} else {
+ mmc_retune_recheck(host);
pr_info("%s: req failed (CMD%u): %d, retrying...\n",
mmc_hostname(host),
cmd->opcode, cmd->error);
cmd->retries--;
cmd->error = 0;
- host->ops->request(host, mrq);
+ __mmc_start_request(host, mrq);
continue; /* wait for done/new event again */
}
} else if (context_info->is_new_req) {
context_info->is_new_req = false;
- if (!next_req) {
- err = MMC_BLK_NEW_REQUEST;
- break; /* return err */
- }
+ if (!next_req)
+ return MMC_BLK_NEW_REQUEST;
}
}
+ mmc_retune_release(host);
return err;
}
@@ -467,12 +484,16 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
mmc_card_removed(host->card))
break;
+ mmc_retune_recheck(host);
+
pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
mmc_hostname(host), cmd->opcode, cmd->error);
cmd->retries--;
cmd->error = 0;
- host->ops->request(host, mrq);
+ __mmc_start_request(host, mrq);
}
+
+ mmc_retune_release(host);
}
/**
--
1.9.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH V7 04/14] mmc: core: Hold re-tuning during switch commands
2015-05-07 10:10 [PATCH V7 00/14] mmc: host: Add facility to support re-tuning Adrian Hunter
` (2 preceding siblings ...)
2015-05-07 10:10 ` [PATCH V7 03/14] mmc: core: Add support for re-tuning before each request Adrian Hunter
@ 2015-05-07 10:10 ` Adrian Hunter
2015-05-07 10:10 ` [PATCH V7 05/14] mmc: core: Hold re-tuning during erase commands Adrian Hunter
` (10 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Adrian Hunter @ 2015-05-07 10:10 UTC (permalink / raw)
To: Ulf Hansson
Cc: linux-mmc, Aaron Lu, Philip Rakity, Al Cooper, Arend van Spriel
Hold re-tuning during switch commands to prevent
it from conflicting with the busy state or the CMD13
verification.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
drivers/mmc/core/mmc_ops.c | 30 ++++++++++++++++++++----------
1 file changed, 20 insertions(+), 10 deletions(-)
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 0ea042d..4cad5f0 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -19,6 +19,7 @@
#include <linux/mmc/mmc.h>
#include "core.h"
+#include "host.h"
#include "mmc_ops.h"
#define MMC_OPS_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
@@ -474,6 +475,8 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
u32 status = 0;
bool use_r1b_resp = use_busy_signal;
+ mmc_retune_hold(host);
+
/*
* If the cmd timeout and the max_busy_timeout of the host are both
* specified, let's validate them. A failure means we need to prevent
@@ -506,11 +509,11 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
if (err)
- return err;
+ goto out;
/* No need to check card status in case of unblocking command */
if (!use_busy_signal)
- return 0;
+ goto out;
/*
* CRC errors shall only be ignored in cases were CMD13 is used to poll
@@ -529,7 +532,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
if (send_status) {
err = __mmc_send_status(card, &status, ignore_crc);
if (err)
- return err;
+ goto out;
}
if ((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
break;
@@ -543,29 +546,36 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
*/
if (!send_status) {
mmc_delay(timeout_ms);
- return 0;
+ goto out;
}
/* Timeout if the device never leaves the program state. */
if (time_after(jiffies, timeout)) {
pr_err("%s: Card stuck in programming state! %s\n",
mmc_hostname(host), __func__);
- return -ETIMEDOUT;
+ err = -ETIMEDOUT;
+ goto out;
}
} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
if (mmc_host_is_spi(host)) {
- if (status & R1_SPI_ILLEGAL_COMMAND)
- return -EBADMSG;
+ if (status & R1_SPI_ILLEGAL_COMMAND) {
+ err = -EBADMSG;
+ goto out;
+ }
} else {
if (status & 0xFDFFA000)
pr_warn("%s: unexpected status %#x after switch\n",
mmc_hostname(host), status);
- if (status & R1_SWITCH_ERROR)
- return -EBADMSG;
+ if (status & R1_SWITCH_ERROR) {
+ err = -EBADMSG;
+ goto out;
+ }
}
+out:
+ mmc_retune_release(host);
- return 0;
+ return err;
}
EXPORT_SYMBOL_GPL(__mmc_switch);
--
1.9.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH V7 05/14] mmc: core: Hold re-tuning during erase commands
2015-05-07 10:10 [PATCH V7 00/14] mmc: host: Add facility to support re-tuning Adrian Hunter
` (3 preceding siblings ...)
2015-05-07 10:10 ` [PATCH V7 04/14] mmc: core: Hold re-tuning during switch commands Adrian Hunter
@ 2015-05-07 10:10 ` Adrian Hunter
2015-05-07 10:10 ` [PATCH V7 06/14] mmc: core: Hold re-tuning while bkops ongoing Adrian Hunter
` (9 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Adrian Hunter @ 2015-05-07 10:10 UTC (permalink / raw)
To: Ulf Hansson
Cc: linux-mmc, Aaron Lu, Philip Rakity, Al Cooper, Arend van Spriel
Hold re-tuning during erase commands to prevent
it from conflicting with the sequence of commands.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
drivers/mmc/core/core.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index ec3453f..ff1e384 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1995,6 +1995,8 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
unsigned long timeout;
int err;
+ mmc_retune_hold(card->host);
+
/*
* qty is used to calculate the erase timeout which depends on how many
* erase groups (or allocation units in SD terminology) are affected.
@@ -2098,6 +2100,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
} 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;
}
--
1.9.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH V7 06/14] mmc: core: Hold re-tuning while bkops ongoing
2015-05-07 10:10 [PATCH V7 00/14] mmc: host: Add facility to support re-tuning Adrian Hunter
` (4 preceding siblings ...)
2015-05-07 10:10 ` [PATCH V7 05/14] mmc: core: Hold re-tuning during erase commands Adrian Hunter
@ 2015-05-07 10:10 ` Adrian Hunter
2015-05-07 10:10 ` [PATCH V7 07/14] mmc: mmc: Hold re-tuning in mmc_sleep() Adrian Hunter
` (8 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Adrian Hunter @ 2015-05-07 10:10 UTC (permalink / raw)
To: Ulf Hansson
Cc: linux-mmc, Aaron Lu, Philip Rakity, Al Cooper, Arend van Spriel
Hold re-tuning during bkops to prevent
it from conflicting with the busy state.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
drivers/mmc/core/core.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index ff1e384..adb6408 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -318,12 +318,15 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
use_busy_signal = false;
}
+ mmc_retune_hold(card->host);
+
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BKOPS_START, 1, timeout,
use_busy_signal, true, false);
if (err) {
pr_warn("%s: Error %d starting bkops\n",
mmc_hostname(card->host), err);
+ mmc_retune_release(card->host);
goto out;
}
@@ -334,6 +337,8 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
*/
if (!use_busy_signal)
mmc_card_set_doing_bkops(card);
+ else
+ mmc_retune_release(card->host);
out:
mmc_release_host(card->host);
}
@@ -749,6 +754,7 @@ int mmc_stop_bkops(struct mmc_card *card)
*/
if (!err || (err == -EINVAL)) {
mmc_card_clr_doing_bkops(card);
+ mmc_retune_release(card->host);
err = 0;
}
--
1.9.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH V7 07/14] mmc: mmc: Hold re-tuning in mmc_sleep()
2015-05-07 10:10 [PATCH V7 00/14] mmc: host: Add facility to support re-tuning Adrian Hunter
` (5 preceding siblings ...)
2015-05-07 10:10 ` [PATCH V7 06/14] mmc: core: Hold re-tuning while bkops ongoing Adrian Hunter
@ 2015-05-07 10:10 ` Adrian Hunter
2015-05-07 10:10 ` [PATCH V7 08/14] mmc: core: Separate out the mmc_switch status check so it can be re-used Adrian Hunter
` (7 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Adrian Hunter @ 2015-05-07 10:10 UTC (permalink / raw)
To: Ulf Hansson
Cc: linux-mmc, Aaron Lu, Philip Rakity, Al Cooper, Arend van Spriel
The sleep command is issued after deselecting the
card, but re-tuning won't work on a deselected card
so re-tuning must be held.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
drivers/mmc/core/mmc.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index f36c76f..fd41b28 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -21,6 +21,7 @@
#include <linux/mmc/mmc.h>
#include "core.h"
+#include "host.h"
#include "bus.h"
#include "mmc_ops.h"
#include "sd_ops.h"
@@ -1511,9 +1512,12 @@ static int mmc_sleep(struct mmc_host *host)
unsigned int timeout_ms = DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000);
int err;
+ /* Re-tuning can't be done once the card is deselected */
+ mmc_retune_hold(host);
+
err = mmc_deselect_cards(host);
if (err)
- return err;
+ goto out_release;
cmd.opcode = MMC_SLEEP_AWAKE;
cmd.arg = card->rca << 16;
@@ -1534,7 +1538,7 @@ static int mmc_sleep(struct mmc_host *host)
err = mmc_wait_for_cmd(host, &cmd, 0);
if (err)
- return err;
+ goto out_release;
/*
* If the host does not wait while the card signals busy, then we will
@@ -1545,6 +1549,8 @@ static int mmc_sleep(struct mmc_host *host)
if (!cmd.busy_timeout || !(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
mmc_delay(timeout_ms);
+out_release:
+ mmc_retune_release(host);
return err;
}
--
1.9.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH V7 08/14] mmc: core: Separate out the mmc_switch status check so it can be re-used
2015-05-07 10:10 [PATCH V7 00/14] mmc: host: Add facility to support re-tuning Adrian Hunter
` (6 preceding siblings ...)
2015-05-07 10:10 ` [PATCH V7 07/14] mmc: mmc: Hold re-tuning in mmc_sleep() Adrian Hunter
@ 2015-05-07 10:10 ` Adrian Hunter
2015-05-07 10:10 ` [PATCH V7 09/14] mmc: core: Add support for HS400 re-tuning Adrian Hunter
` (6 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Adrian Hunter @ 2015-05-07 10:10 UTC (permalink / raw)
To: Ulf Hansson
Cc: linux-mmc, Aaron Lu, Philip Rakity, Al Cooper, Arend van Spriel
Make a separate function to do the mmc_switch status check
so it can be re-used. This is preparation for adding support
for HS400 re-tuning.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
drivers/mmc/core/mmc_ops.c | 30 ++++++++++++++++--------------
drivers/mmc/core/mmc_ops.h | 1 +
2 files changed, 17 insertions(+), 14 deletions(-)
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 4cad5f0..0e9ae1c 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -450,6 +450,21 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
return err;
}
+int mmc_switch_status_error(struct mmc_host *host, u32 status)
+{
+ if (mmc_host_is_spi(host)) {
+ if (status & R1_SPI_ILLEGAL_COMMAND)
+ return -EBADMSG;
+ } else {
+ if (status & 0xFDFFA000)
+ pr_warn("%s: unexpected status %#x after switch\n",
+ mmc_hostname(host), status);
+ if (status & R1_SWITCH_ERROR)
+ return -EBADMSG;
+ }
+ return 0;
+}
+
/**
* __mmc_switch - modify EXT_CSD register
* @card: the MMC card associated with the data transfer
@@ -558,20 +573,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
}
} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
- if (mmc_host_is_spi(host)) {
- if (status & R1_SPI_ILLEGAL_COMMAND) {
- err = -EBADMSG;
- goto out;
- }
- } else {
- if (status & 0xFDFFA000)
- pr_warn("%s: unexpected status %#x after switch\n",
- mmc_hostname(host), status);
- if (status & R1_SWITCH_ERROR) {
- err = -EBADMSG;
- goto out;
- }
- }
+ err = mmc_switch_status_error(host, status);
out:
mmc_retune_release(host);
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 6f4b00e..f498f9a 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -27,6 +27,7 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
int mmc_bus_test(struct mmc_card *card, u8 bus_width);
int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status);
int mmc_can_ext_csd(struct mmc_card *card);
+int mmc_switch_status_error(struct mmc_host *host, u32 status);
#endif
--
1.9.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH V7 09/14] mmc: core: Add support for HS400 re-tuning
2015-05-07 10:10 [PATCH V7 00/14] mmc: host: Add facility to support re-tuning Adrian Hunter
` (7 preceding siblings ...)
2015-05-07 10:10 ` [PATCH V7 08/14] mmc: core: Separate out the mmc_switch status check so it can be re-used Adrian Hunter
@ 2015-05-07 10:10 ` Adrian Hunter
2015-05-07 10:10 ` [PATCH V7 10/14] mmc: sdhci: Change to new way of doing re-tuning Adrian Hunter
` (5 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Adrian Hunter @ 2015-05-07 10:10 UTC (permalink / raw)
To: Ulf Hansson
Cc: linux-mmc, Aaron Lu, Philip Rakity, Al Cooper, Arend van Spriel
HS400 re-tuning must be done in HS200 mode. Add
the ability to switch from HS400 mode to HS200
mode before re-tuning and switch back to HS400
after re-tuning.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
drivers/mmc/core/core.h | 2 ++
drivers/mmc/core/host.c | 17 ++++++++++
drivers/mmc/core/mmc.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 107 insertions(+)
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index cfba3c0..e6f2de7 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -88,6 +88,8 @@ void mmc_remove_card_debugfs(struct mmc_card *card);
void mmc_init_context_info(struct mmc_host *host);
int mmc_execute_tuning(struct mmc_card *card);
+int mmc_hs200_to_hs400(struct mmc_card *card);
+int mmc_hs400_to_hs200(struct mmc_card *card);
#endif
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index e90e02f..86c495b 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -340,6 +340,7 @@ void mmc_retune_release(struct mmc_host *host)
int mmc_retune(struct mmc_host *host)
{
+ bool return_to_hs400 = false;
int err;
if (host->retune_now)
@@ -354,8 +355,24 @@ int mmc_retune(struct mmc_host *host)
host->doing_retune = 1;
+ if (host->ios.timing == MMC_TIMING_MMC_HS400) {
+ err = mmc_hs400_to_hs200(host->card);
+ if (err)
+ goto out;
+
+ return_to_hs400 = true;
+
+ if (host->ops->prepare_hs400_tuning)
+ host->ops->prepare_hs400_tuning(host, &host->ios);
+ }
+
err = mmc_execute_tuning(host->card);
+ if (err)
+ goto out;
+ if (return_to_hs400)
+ err = mmc_hs200_to_hs400(host->card);
+out:
host->doing_retune = 0;
return err;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index fd41b28..a802863 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1092,6 +1092,94 @@ static int mmc_select_hs400(struct mmc_card *card)
return 0;
}
+int mmc_hs200_to_hs400(struct mmc_card *card)
+{
+ return mmc_select_hs400(card);
+}
+
+/* Caller must hold re-tuning */
+static int mmc_switch_status(struct mmc_card *card)
+{
+ u32 status;
+ int err;
+
+ err = mmc_send_status(card, &status);
+ if (err)
+ return err;
+
+ return mmc_switch_status_error(card->host, status);
+}
+
+int mmc_hs400_to_hs200(struct mmc_card *card)
+{
+ struct mmc_host *host = card->host;
+ bool send_status = true;
+ unsigned int max_dtr;
+ int err;
+
+ if (host->caps & MMC_CAP_WAIT_WHILE_BUSY)
+ send_status = false;
+
+ /* Reduce frequency to HS */
+ max_dtr = card->ext_csd.hs_max_dtr;
+ mmc_set_clock(host, max_dtr);
+
+ /* Switch HS400 to HS DDR */
+ err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
+ EXT_CSD_TIMING_HS, card->ext_csd.generic_cmd6_time,
+ true, send_status, true);
+ if (err)
+ goto out_err;
+
+ mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
+
+ if (!send_status) {
+ err = mmc_switch_status(card);
+ if (err)
+ goto out_err;
+ }
+
+ /* Switch HS DDR to HS */
+ err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH,
+ EXT_CSD_BUS_WIDTH_8, card->ext_csd.generic_cmd6_time,
+ true, send_status, true);
+ if (err)
+ goto out_err;
+
+ mmc_set_timing(host, MMC_TIMING_MMC_HS);
+
+ if (!send_status) {
+ err = mmc_switch_status(card);
+ if (err)
+ goto out_err;
+ }
+
+ /* Switch HS to HS200 */
+ err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
+ EXT_CSD_TIMING_HS200,
+ card->ext_csd.generic_cmd6_time, true, send_status,
+ true);
+ if (err)
+ goto out_err;
+
+ mmc_set_timing(host, MMC_TIMING_MMC_HS200);
+
+ if (!send_status) {
+ err = mmc_switch_status(card);
+ if (err)
+ goto out_err;
+ }
+
+ mmc_set_bus_speed(card);
+
+ return 0;
+
+out_err:
+ pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
+ __func__, err);
+ return err;
+}
+
/*
* For device supporting HS200 mode, the following sequence
* should be done before executing the tuning process.
--
1.9.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH V7 10/14] mmc: sdhci: Change to new way of doing re-tuning
2015-05-07 10:10 [PATCH V7 00/14] mmc: host: Add facility to support re-tuning Adrian Hunter
` (8 preceding siblings ...)
2015-05-07 10:10 ` [PATCH V7 09/14] mmc: core: Add support for HS400 re-tuning Adrian Hunter
@ 2015-05-07 10:10 ` Adrian Hunter
2015-05-07 10:10 ` [PATCH V7 11/14] mmc: core: Flag re-tuning is needed on CRC errors Adrian Hunter
` (4 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Adrian Hunter @ 2015-05-07 10:10 UTC (permalink / raw)
To: Ulf Hansson
Cc: linux-mmc, Aaron Lu, Philip Rakity, Al Cooper, Arend van Spriel
Make use of mmc core support for re-tuning instead
of doing it all in the sdhci driver.
This patch also changes to flag the need for re-tuning
always after runtime suspend when tuning has been used
at initialization. Previously it was only done if
the re-tuning timer was in use.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
drivers/mmc/host/sdhci.c | 112 ++++++-----------------------------------------
drivers/mmc/host/sdhci.h | 3 --
2 files changed, 13 insertions(+), 102 deletions(-)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index c80287a..b345844 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -52,7 +52,6 @@ static void sdhci_finish_data(struct sdhci_host *);
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,
@@ -254,17 +253,6 @@ static void sdhci_init(struct sdhci_host *host, int soft)
static void sdhci_reinit(struct sdhci_host *host)
{
sdhci_init(host, 0);
- /*
- * Retuning stuffs are affected by different cards inserted and only
- * applicable to UHS-I cards. So reset these fields to their initial
- * value when card is removed.
- */
- if (host->flags & SDHCI_USING_RETUNING_TIMER) {
- host->flags &= ~SDHCI_USING_RETUNING_TIMER;
-
- del_timer_sync(&host->tuning_timer);
- host->flags &= ~SDHCI_NEEDS_RETUNING;
- }
sdhci_enable_card_detection(host);
}
@@ -1353,7 +1341,6 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
struct sdhci_host *host;
int present;
unsigned long flags;
- u32 tuning_opcode;
host = mmc_priv(mmc);
@@ -1387,39 +1374,6 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
host->mrq->cmd->error = -ENOMEDIUM;
tasklet_schedule(&host->finish_tasklet);
} else {
- u32 present_state;
-
- present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
- /*
- * Check if the re-tuning timer has already expired and there
- * is no on-going data transfer and DAT0 is not busy. If so,
- * we need to execute tuning procedure before sending command.
- */
- if ((host->flags & SDHCI_NEEDS_RETUNING) &&
- !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ)) &&
- (present_state & SDHCI_DATA_0_LVL_MASK)) {
- if (mmc->card) {
- /* eMMC uses cmd21 but sd and sdio use cmd19 */
- tuning_opcode =
- mmc->card->type == MMC_TYPE_MMC ?
- MMC_SEND_TUNING_BLOCK_HS200 :
- MMC_SEND_TUNING_BLOCK;
-
- /* Here we need to set the host->mrq to NULL,
- * in case the pending finish_tasklet
- * finishes it incorrectly.
- */
- host->mrq = NULL;
-
- spin_unlock_irqrestore(&host->lock, flags);
- sdhci_execute_tuning(mmc, tuning_opcode);
- spin_lock_irqsave(&host->lock, flags);
-
- /* Restore original mmc_request structure */
- host->mrq = mrq;
- }
- }
-
if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23))
sdhci_send_command(host, mrq->sbc);
else
@@ -2065,23 +2019,18 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
}
out:
- host->flags &= ~SDHCI_NEEDS_RETUNING;
-
if (tuning_count) {
- host->flags |= SDHCI_USING_RETUNING_TIMER;
- mod_timer(&host->tuning_timer, jiffies + tuning_count * HZ);
+ /*
+ * In case tuning fails, host controllers which support
+ * re-tuning can try tuning again at a later time, when the
+ * re-tuning timer expires. So for these controllers, we
+ * return 0. Since there might be other controllers who do not
+ * have this capability, we return error for them.
+ */
+ err = 0;
}
- /*
- * In case tuning fails, host controllers which support re-tuning can
- * try tuning again at a later time, when the re-tuning timer expires.
- * So for these controllers, we return 0. Since there might be other
- * controllers who do not have this capability, we return error for
- * them. SDHCI_USING_RETUNING_TIMER means the host is currently using
- * a retuning timer to do the retuning for the card.
- */
- if (err && (host->flags & SDHCI_USING_RETUNING_TIMER))
- err = 0;
+ host->mmc->retune_period = err ? 0 : tuning_count;
sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
@@ -2337,20 +2286,6 @@ static void sdhci_timeout_timer(unsigned long data)
spin_unlock_irqrestore(&host->lock, flags);
}
-static void sdhci_tuning_timer(unsigned long data)
-{
- struct sdhci_host *host;
- unsigned long flags;
-
- host = (struct sdhci_host *)data;
-
- spin_lock_irqsave(&host->lock, flags);
-
- host->flags |= SDHCI_NEEDS_RETUNING;
-
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
/*****************************************************************************\
* *
* Interrupt handling *
@@ -2728,11 +2663,8 @@ int sdhci_suspend_host(struct sdhci_host *host)
{
sdhci_disable_card_detection(host);
- /* Disable tuning since we are suspending */
- if (host->flags & SDHCI_USING_RETUNING_TIMER) {
- del_timer_sync(&host->tuning_timer);
- host->flags &= ~SDHCI_NEEDS_RETUNING;
- }
+ mmc_retune_timer_stop(host->mmc);
+ mmc_retune_needed(host->mmc);
if (!device_may_wakeup(mmc_dev(host->mmc))) {
host->ier = 0;
@@ -2782,10 +2714,6 @@ int sdhci_resume_host(struct sdhci_host *host)
sdhci_enable_card_detection(host);
- /* Set the re-tuning expiration flag */
- if (host->flags & SDHCI_USING_RETUNING_TIMER)
- host->flags |= SDHCI_NEEDS_RETUNING;
-
return ret;
}
@@ -2822,11 +2750,8 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
{
unsigned long flags;
- /* Disable tuning since we are suspending */
- if (host->flags & SDHCI_USING_RETUNING_TIMER) {
- del_timer_sync(&host->tuning_timer);
- host->flags &= ~SDHCI_NEEDS_RETUNING;
- }
+ mmc_retune_timer_stop(host->mmc);
+ mmc_retune_needed(host->mmc);
spin_lock_irqsave(&host->lock, flags);
host->ier &= SDHCI_INT_CARD_INT;
@@ -2869,10 +2794,6 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
spin_unlock_irqrestore(&host->lock, flags);
}
- /* Set the re-tuning expiration flag */
- if (host->flags & SDHCI_USING_RETUNING_TIMER)
- host->flags |= SDHCI_NEEDS_RETUNING;
-
spin_lock_irqsave(&host->lock, flags);
host->runtime_suspended = false;
@@ -3408,13 +3329,6 @@ int sdhci_add_host(struct sdhci_host *host)
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;
- host->tuning_timer.function = sdhci_tuning_timer;
- }
-
sdhci_init(host, 0);
ret = request_threaded_irq(host->irq, sdhci_irq, sdhci_thread_irq,
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index e639b7f..923ff22 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -432,13 +432,11 @@ struct sdhci_host {
#define SDHCI_REQ_USE_DMA (1<<2) /* Use DMA for this req. */
#define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */
#define SDHCI_SDR50_NEEDS_TUNING (1<<4) /* SDR50 needs tuning */
-#define SDHCI_NEEDS_RETUNING (1<<5) /* Host needs retuning */
#define SDHCI_AUTO_CMD12 (1<<6) /* Auto CMD12 support */
#define SDHCI_AUTO_CMD23 (1<<7) /* Auto CMD23 support */
#define SDHCI_PV_ENABLED (1<<8) /* Preset value enabled */
#define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */
#define SDHCI_SDR104_NEEDS_TUNING (1<<10) /* SDR104/HS200 needs tuning */
-#define SDHCI_USING_RETUNING_TIMER (1<<11) /* Host is using a retuning timer for the card */
#define SDHCI_USE_64_BIT_DMA (1<<12) /* Use 64-bit DMA */
#define SDHCI_HS400_TUNING (1<<13) /* Tuning for HS400 */
@@ -504,7 +502,6 @@ struct sdhci_host {
unsigned int tuning_count; /* Timer count for re-tuning */
unsigned int tuning_mode; /* Re-tuning mode supported by host */
#define SDHCI_TUNING_MODE_1 0
- struct timer_list tuning_timer; /* Timer for tuning */
struct sdhci_host_next next_data;
unsigned long private[0] ____cacheline_aligned;
--
1.9.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH V7 11/14] mmc: core: Flag re-tuning is needed on CRC errors
2015-05-07 10:10 [PATCH V7 00/14] mmc: host: Add facility to support re-tuning Adrian Hunter
` (9 preceding siblings ...)
2015-05-07 10:10 ` [PATCH V7 10/14] mmc: sdhci: Change to new way of doing re-tuning Adrian Hunter
@ 2015-05-07 10:10 ` Adrian Hunter
2015-05-07 10:10 ` [PATCH V7 12/14] mmc: block: Check re-tuning in the recovery path Adrian Hunter
` (3 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Adrian Hunter @ 2015-05-07 10:10 UTC (permalink / raw)
To: Ulf Hansson
Cc: linux-mmc, Aaron Lu, Philip Rakity, Al Cooper, Arend van Spriel
CRC errors could possibly be alleviated by
re-tuning so flag re-tuning needed in those cases.
Note this has no effect if re-tuning has not been
enabled.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
drivers/mmc/core/core.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index adb6408..c93062b 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -133,6 +133,12 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
struct mmc_command *cmd = mrq->cmd;
int err = cmd->error;
+ /* Flag re-tuning needed on CRC errors */
+ if (err == -EILSEQ || (mrq->sbc && mrq->sbc->error == -EILSEQ) ||
+ (mrq->data && mrq->data->error == -EILSEQ) ||
+ (mrq->stop && mrq->stop->error == -EILSEQ))
+ mmc_retune_needed(host);
+
if (err && cmd->retries && mmc_host_is_spi(host)) {
if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
cmd->retries = 0;
--
1.9.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH V7 12/14] mmc: block: Check re-tuning in the recovery path
2015-05-07 10:10 [PATCH V7 00/14] mmc: host: Add facility to support re-tuning Adrian Hunter
` (10 preceding siblings ...)
2015-05-07 10:10 ` [PATCH V7 11/14] mmc: core: Flag re-tuning is needed on CRC errors Adrian Hunter
@ 2015-05-07 10:10 ` Adrian Hunter
2015-05-07 10:10 ` [PATCH V7 13/14] mmc: block: Retry errored data requests when re-tuning is needed Adrian Hunter
` (2 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Adrian Hunter @ 2015-05-07 10:10 UTC (permalink / raw)
To: Ulf Hansson
Cc: linux-mmc, Aaron Lu, Philip Rakity, Al Cooper, Arend van Spriel
If re-tuning is needed, do it in the recovery path to
give recovery commands a better chance of success.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
drivers/mmc/card/block.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 2c25271..325ae1e 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -913,6 +913,9 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
if (!err)
break;
+ /* Re-tune if needed */
+ mmc_retune_recheck(card->host);
+
prev_cmd_status_valid = false;
pr_err("%s: error %d sending status command, %sing\n",
req->rq_disk->disk_name, err, retry ? "retry" : "abort");
--
1.9.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH V7 13/14] mmc: block: Retry errored data requests when re-tuning is needed
2015-05-07 10:10 [PATCH V7 00/14] mmc: host: Add facility to support re-tuning Adrian Hunter
` (11 preceding siblings ...)
2015-05-07 10:10 ` [PATCH V7 12/14] mmc: block: Check re-tuning in the recovery path Adrian Hunter
@ 2015-05-07 10:10 ` Adrian Hunter
2015-05-07 10:10 ` [PATCH V7 14/14] mmc: core: Don't print reset warning if reset is not supported Adrian Hunter
2015-05-08 11:28 ` [PATCH V7 00/14] mmc: host: Add facility to support re-tuning Ulf Hansson
14 siblings, 0 replies; 17+ messages in thread
From: Adrian Hunter @ 2015-05-07 10:10 UTC (permalink / raw)
To: Ulf Hansson
Cc: linux-mmc, Aaron Lu, Philip Rakity, Al Cooper, Arend van Spriel
Retry errored data requests when re-tuning is needed and
add a flag to struct mmc_blk_request so that the retry
is only done once.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
drivers/mmc/card/block.c | 11 ++++++++++-
drivers/mmc/card/queue.h | 1 +
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 325ae1e..509fcca 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1195,6 +1195,7 @@ static int mmc_blk_err_check(struct mmc_card *card,
mmc_active);
struct mmc_blk_request *brq = &mq_mrq->brq;
struct request *req = mq_mrq->req;
+ int need_retune = card->host->need_retune;
int ecc_err = 0, gen_err = 0;
/*
@@ -1262,6 +1263,12 @@ static int mmc_blk_err_check(struct mmc_card *card,
}
if (brq->data.error) {
+ if (need_retune && !brq->retune_retry_done) {
+ pr_info("%s: retrying because a re-tune was needed\n",
+ req->rq_disk->disk_name);
+ brq->retune_retry_done = 1;
+ return MMC_BLK_RETRY;
+ }
pr_err("%s: error %d transferring data, sector %u, nr %u, cmd response %#x, card status %#x\n",
req->rq_disk->disk_name, brq->data.error,
(unsigned)blk_rq_pos(req),
@@ -1821,7 +1828,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
struct mmc_blk_data *md = mq->data;
struct mmc_card *card = md->queue.card;
struct mmc_blk_request *brq = &mq->mqrq_cur->brq;
- int ret = 1, disable_multi = 0, retry = 0, type;
+ int ret = 1, disable_multi = 0, retry = 0, type, retune_retry_done = 0;
enum mmc_blk_status status;
struct mmc_queue_req *mq_rq;
struct request *req = rqc;
@@ -1905,6 +1912,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
break;
goto cmd_abort;
case MMC_BLK_RETRY:
+ retune_retry_done = brq->retune_retry_done;
if (retry++ < 5)
break;
/* Fall through */
@@ -1967,6 +1975,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
mmc_start_req(card->host,
&mq_rq->mmc_active, NULL);
}
+ mq_rq->brq.retune_retry_done = retune_retry_done;
}
} while (ret);
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index 5752d50..7e27915 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -12,6 +12,7 @@ struct mmc_blk_request {
struct mmc_command cmd;
struct mmc_command stop;
struct mmc_data data;
+ int retune_retry_done;
};
enum mmc_packed_type {
--
1.9.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH V7 14/14] mmc: core: Don't print reset warning if reset is not supported
2015-05-07 10:10 [PATCH V7 00/14] mmc: host: Add facility to support re-tuning Adrian Hunter
` (12 preceding siblings ...)
2015-05-07 10:10 ` [PATCH V7 13/14] mmc: block: Retry errored data requests when re-tuning is needed Adrian Hunter
@ 2015-05-07 10:10 ` Adrian Hunter
2015-05-08 11:28 ` [PATCH V7 00/14] mmc: host: Add facility to support re-tuning Ulf Hansson
14 siblings, 0 replies; 17+ messages in thread
From: Adrian Hunter @ 2015-05-07 10:10 UTC (permalink / raw)
To: Ulf Hansson
Cc: linux-mmc, Aaron Lu, Philip Rakity, Al Cooper, Arend van Spriel
Check the error code for EOPNOTSUPP and do not print
reset warning in that case.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
drivers/mmc/core/core.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index c93062b..8c61ddd 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2371,7 +2371,8 @@ int mmc_hw_reset(struct mmc_host *host)
ret = host->bus_ops->reset(host);
mmc_bus_put(host);
- pr_warn("%s: tried to reset card\n", mmc_hostname(host));
+ if (ret != -EOPNOTSUPP)
+ pr_warn("%s: tried to reset card\n", mmc_hostname(host));
return ret;
}
--
1.9.1
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH V7 00/14] mmc: host: Add facility to support re-tuning
2015-05-07 10:10 [PATCH V7 00/14] mmc: host: Add facility to support re-tuning Adrian Hunter
` (13 preceding siblings ...)
2015-05-07 10:10 ` [PATCH V7 14/14] mmc: core: Don't print reset warning if reset is not supported Adrian Hunter
@ 2015-05-08 11:28 ` Ulf Hansson
2015-05-08 13:09 ` Adrian Hunter
14 siblings, 1 reply; 17+ messages in thread
From: Ulf Hansson @ 2015-05-08 11:28 UTC (permalink / raw)
To: Adrian Hunter
Cc: linux-mmc, Aaron Lu, Philip Rakity, Al Cooper, Arend van Spriel
On 7 May 2015 at 12:10, Adrian Hunter <adrian.hunter@intel.com> wrote:
> Hi
>
> Here is V7 of some patches to move re-tuning support
> out of sdhci and into the core, and add support for HS400
> re-tuning.
>
> Currently sdhci does re-tuning transparently by
> calling sdhci_execute_tuning() from its ->request()
> function.
>
> The problem with HS400 re-tuning is that it must be
> done in HS200 mode. That means using switch commands
> and making ios changes. That means it potentially
> conflicts with other command sequences. The new
> re-tuning support accomodates that.
>
> Changes in V7:
>
> mmc: host: Add facility to support re-tuning
> Remove unused mmc_retune_not_needed()
>
> mmc: core: Enable / disable re-tuning
> As already sent separately as V7:
> Also flag re-tune needed in SDIO 'keep_power'
> case, when a re-tuning timer is being used.
>
> mmc: core: Add support for re-tuning before each request
> Fold in next patch
>
> mmc: core: Check re-tuning before retrying
> Folded into previous patch
>
> mmc: mmc: Hold re-tuning if the card is put to sleep
> Change title to:
> mmc: mmc: Hold re-tuning in mmc_sleep()
> Remove changes from V6
> Hold re-tuning while card is deselected
>
> mmc: core: Flag re-tuning is needed on CRC errors
> Do it from core rather than the host
>
> Changes in V6:
>
> mmc: host: Add facility to support re-tuning
> Don't export functions only used in core
>
> mmc: core: Enable / disable re-tuning
> Ensure re-tuning timer is disabled in SDIO suspend
>
> mmc: core: Hold re-tuning while bkops ongoing
> Hold re-tuning always and release only if
> bkops is not ongoing.
>
> mmc: mmc: Hold re-tuning if the card is put to sleep
> Hold re-tuning for mmc_sleep even if card is
> immediately powered off, disabling re-tuning.
>
> Changes in V5:
>
> mmc: host: Add facility to support re-tuning
> Make mmc_retune_enable() / mmc_retune_disable()
> only called from core.
>
> mmc: core: Enable / disable re-tuning
> Replaces mmc: core: Disable re-tuning when card is no longer initialized
> Enables re-tuning when tuning is executed
>
> mmc: sdhci: Change to new way of doing re-tuning
> Set host->retune_period instead of enabling re-tuning.
>
> Changes in V4:
>
> These patches now depend on Ulf's patch:
> mmc: core: Enable runtime PM management of host devices
>
> mmc: host: Add facility to support re-tuning
>
> Assume mmc_claim_host() runtime resumes the host
> controller so there are no races with runtime pm.
> Consequently remove now un-needed re-tuning host
> operations.
>
> mmc: core: Add support for re-tuning before each request
>
> Call mmc_retune() prior to ->request()
>
> mmc: sdhci: Change to new way of doing re-tuning
>
> Updated to reflect the changes above.
>
> Changes in V3:
>
> mmc: host: Add facility to support re-tuning
>
> Add host->retune_now flag so re-tuning can be
> started in the host drivers ->request()
> function to avoid racing with Runtime PM.
>
> Add host operations to let the host know when
> re-tuning is held, for eaxmple, to enable
> synchronization with runtime suspend / resume.
>
> Ensure functions are exported.
>
> mmc: core: Add support for re-tuning before each request
> Updated to reflect the change above.
>
> mmc: core: Check re-tuning before retrying
> Updated to reflect the change above.
>
> mmc: core: Hold re-tuning during switch commands
> Updated to reflect the change above.
>
> mmc: core: Hold re-tuning during erase commands
> Updated to reflect the change above.
>
> mmc: core: Hold re-tuning while bkops ongoing
> Updated to reflect the change above.
>
> mmc: core: Add support for HS400 re-tuning
> Updated and as already sent separately as V3:
> Remember to mmc_set_bus_speed(card) in mmc_hs400_to_hs200()
>
> mmc: sdhci: Change to new way of doing re-tuning
> Call mmc_retune() from ->request() function to
> avoid racing with Runtime PM. And implement
> hold_tuning / release_tuning operations to prevent
> runtime suspend while re-tuning is held.
>
> mmc: block: Retry errored data requests when re-tuning is needed
> Updated and as already sent separately as V3:
> Only retry when there is an error
>
> Changes in V2:
>
> Added support to the block driver for re-tuning
> and retrying after a CRC error. The host driver
> is left to decide when an error indicates re-tuning
> is needed. The block driver will retry a data request
> once if re-tuning is flagged as needed.
>
> SDIO drivers need not be aware of re-tuning because
> retrying will anyway cause re-tuning when re-tuning
> is flagged as needed. Nevertheless SDIO drivers could
> use the need_retune flag to instigate a retry when
> otherwise they might not have.
>
> mmc: core: Simplify by adding mmc_execute_tuning()
> Dropped because it has been applied
>
> mmc: host: Add facility to support re-tuning
> Renamed mmc_retune_retry() to mmc_retune_recheck()
> to better reflect what it does.
>
> mmc: core: Move mmc_card_removed() into mmc_start_request()
> Dropped because it has been applied
>
> mmc: core: Add support for re-tuning before each request
> Fixed un-balanced re-tune hold / release
>
> mmc: sdhci: Always init buf_ready_int
> Dropped because it has been applied
>
> mmc: core: Separate out the mmc_switch status check so it can be re-used
> New patch
>
> mmc: core: Add support for HS400 re-tuning
> It was found that that the original code was not reliable
> after a CRC error. The problem was that the CMD13 after a
> switch was faiing. So the code was changed to check the
> switch status *after* changing the I/O state to match the
> switch i.e. the new I/O state is the correct one to use
> after a switch.
>
> mmc: sdhci: Flag re-tuning is needed on CRC or End-Bit errors
> New patch
>
> mmc: block: Check re-tuning in the recovery path
> New patch
>
> mmc: block: Retry data requests when re-tuning is needed
> New patch
>
> mmc: core: Don't print reset warning if reset is not supported
> New patch
>
>
> Adrian Hunter (14):
> mmc: host: Add facility to support re-tuning
> mmc: core: Enable / disable re-tuning
> mmc: core: Add support for re-tuning before each request
> mmc: core: Hold re-tuning during switch commands
> mmc: core: Hold re-tuning during erase commands
> mmc: core: Hold re-tuning while bkops ongoing
> mmc: mmc: Hold re-tuning in mmc_sleep()
> mmc: core: Separate out the mmc_switch status check so it can be re-used
> mmc: core: Add support for HS400 re-tuning
> mmc: sdhci: Change to new way of doing re-tuning
> mmc: core: Flag re-tuning is needed on CRC errors
> mmc: block: Check re-tuning in the recovery path
> mmc: block: Retry errored data requests when re-tuning is needed
> mmc: core: Don't print reset warning if reset is not supported
>
> drivers/mmc/card/block.c | 14 +++++-
> drivers/mmc/card/queue.h | 1 +
> drivers/mmc/core/core.c | 57 +++++++++++++++++++----
> drivers/mmc/core/core.h | 2 +
> drivers/mmc/core/host.c | 85 ++++++++++++++++++++++++++++++++++
> drivers/mmc/core/host.h | 6 +++
> drivers/mmc/core/mmc.c | 98 ++++++++++++++++++++++++++++++++++++++-
> drivers/mmc/core/mmc_ops.c | 44 +++++++++++-------
> drivers/mmc/core/mmc_ops.h | 1 +
> drivers/mmc/core/sdio.c | 6 ++-
> drivers/mmc/host/sdhci.c | 112 ++++++---------------------------------------
> drivers/mmc/host/sdhci.h | 3 --
> include/linux/mmc/host.h | 23 ++++++++++
> 13 files changed, 322 insertions(+), 130 deletions(-)
>
>
> Regards
> Adrian
>
Adrian, thanks for all your efforts around this patchset. I have now
applied for my next branch.
Kind regards
Uffe
^ permalink raw reply [flat|nested] 17+ messages in thread