* [PATCH V3 01/15] mmc: host: Add facility to support re-tuning
2015-03-10 12:42 [PATCH V3 00/15] mmc: host: Add facility to support re-tuning Adrian Hunter
@ 2015-03-10 12:42 ` Adrian Hunter
2015-03-10 12:42 ` [PATCH V3 02/15] mmc: core: Disable re-tuning when card is no longer initialized Adrian Hunter
` (14 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Adrian Hunter @ 2015-03-10 12:42 UTC (permalink / raw)
To: Ulf Hansson, Chris Ball
Cc: linux-mmc, Aaron Lu, Philip Rakity, Girish K S, 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 6 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 */
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. Also host operations are added to let the host
know when re-tuning is held, for example, to enable
synchronization with runtime suspend / resume.
Subsequent patches take those functions into use.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
drivers/mmc/core/host.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/mmc/host.h | 34 +++++++++++++++++++++
2 files changed, 112 insertions(+)
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 8be0df7..fe6aa57 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -301,6 +301,83 @@ static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
#endif
+void mmc_retune_enable(struct mmc_host *host, unsigned int period)
+{
+ host->can_retune = 1;
+ if (period)
+ mod_timer(&host->retune_timer, jiffies + period * HZ);
+}
+EXPORT_SYMBOL(mmc_retune_enable);
+
+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;
+}
+EXPORT_SYMBOL(mmc_retune_disable);
+
+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) {
+ if (host->ops->hold_tuning)
+ host->ops->hold_tuning(host);
+ host->retune_now = 1;
+ }
+ host->hold_retune += 1;
+}
+EXPORT_SYMBOL(mmc_retune_hold);
+
+void mmc_retune_release(struct mmc_host *host)
+{
+ if (host->hold_retune) {
+ host->hold_retune -= 1;
+ if (!host->hold_retune && host->ops->release_tuning)
+ host->ops->release_tuning(host);
+ } else {
+ WARN_ON(1);
+ }
+}
+EXPORT_SYMBOL(mmc_retune_release);
+
+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;
+}
+EXPORT_SYMBOL(mmc_retune);
+
+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 +581,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/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 0c8cbe5..bf08e3e 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>
@@ -134,6 +135,8 @@ struct mmc_host_ops {
/* The tuning command opcode value is different for SD and eMMC cards */
int (*execute_tuning)(struct mmc_host *host, u32 opcode);
+ void (*hold_tuning)(struct mmc_host *host);
+ void (*release_tuning)(struct mmc_host *host);
/* Prepare HS400 target operating frequency depending host driver */
int (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
@@ -327,10 +330,17 @@ 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 */
+ 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 */
@@ -519,4 +529,28 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
return card->host->ios.timing == MMC_TIMING_MMC_HS400;
}
+void mmc_retune_enable(struct mmc_host *host, unsigned int period);
+void mmc_retune_disable(struct mmc_host *host);
+void mmc_retune_timer_stop(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);
+
+static inline void mmc_retune_needed(struct mmc_host *host)
+{
+ if (host->can_retune)
+ host->need_retune = 1;
+}
+
+static inline void mmc_retune_not_needed(struct mmc_host *host)
+{
+ host->need_retune = 0;
+}
+
+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] 18+ messages in thread* [PATCH V3 02/15] mmc: core: Disable re-tuning when card is no longer initialized
2015-03-10 12:42 [PATCH V3 00/15] mmc: host: Add facility to support re-tuning Adrian Hunter
2015-03-10 12:42 ` [PATCH V3 01/15] " Adrian Hunter
@ 2015-03-10 12:42 ` Adrian Hunter
2015-03-10 12:42 ` [PATCH V3 03/15] mmc: core: Add support for re-tuning before each request Adrian Hunter
` (13 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Adrian Hunter @ 2015-03-10 12:42 UTC (permalink / raw)
To: Ulf Hansson, Chris Ball
Cc: linux-mmc, Aaron Lu, Philip Rakity, Girish K S, Al Cooper,
Arend van Spriel
Re-tuning is done before a request is sent to the card.
Host controller drivers can choose to enable re-tuning
when tuning is done during card initialization. To
ensure that re-tuning gets disabled, add disabling to
mmc_set_initial_state() which is called whenever the
card is powered on, off, or reset.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
drivers/mmc/core/core.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 23f10f7..aaca0e1 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1137,6 +1137,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
--
1.9.1
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH V3 03/15] mmc: core: Add support for re-tuning before each request
2015-03-10 12:42 [PATCH V3 00/15] mmc: host: Add facility to support re-tuning Adrian Hunter
2015-03-10 12:42 ` [PATCH V3 01/15] " Adrian Hunter
2015-03-10 12:42 ` [PATCH V3 02/15] mmc: core: Disable re-tuning when card is no longer initialized Adrian Hunter
@ 2015-03-10 12:42 ` Adrian Hunter
2015-03-10 12:42 ` [PATCH V3 04/15] mmc: core: Check re-tuning before retrying Adrian Hunter
` (12 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Adrian Hunter @ 2015-03-10 12:42 UTC (permalink / raw)
To: Ulf Hansson, Chris Ball
Cc: linux-mmc, Aaron Lu, Philip Rakity, Girish K S, 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.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
drivers/mmc/core/core.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index aaca0e1..12bddc9 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -192,6 +192,8 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
unsigned int i, sz;
struct scatterlist *sg;
#endif
+ mmc_retune_hold(host);
+
if (mmc_card_removed(host->card))
return -ENOMEDIUM;
@@ -427,12 +429,11 @@ static int mmc_wait_for_data_req_done(struct mmc_host *host,
}
} 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;
}
@@ -473,6 +474,8 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
cmd->error = 0;
host->ops->request(host, mrq);
}
+
+ mmc_retune_release(host);
}
/**
--
1.9.1
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH V3 04/15] mmc: core: Check re-tuning before retrying
2015-03-10 12:42 [PATCH V3 00/15] mmc: host: Add facility to support re-tuning Adrian Hunter
` (2 preceding siblings ...)
2015-03-10 12:42 ` [PATCH V3 03/15] mmc: core: Add support for re-tuning before each request Adrian Hunter
@ 2015-03-10 12:42 ` Adrian Hunter
2015-03-10 12:43 ` [PATCH V3 05/15] mmc: core: Hold re-tuning during switch commands Adrian Hunter
` (11 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Adrian Hunter @ 2015-03-10 12:42 UTC (permalink / raw)
To: Ulf Hansson, Chris Ball
Cc: linux-mmc, Aaron Lu, Philip Rakity, Girish K S, Al Cooper,
Arend van Spriel
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 | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 12bddc9..01b9edf 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -419,6 +419,7 @@ 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);
@@ -468,6 +469,8 @@ 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--;
--
1.9.1
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH V3 05/15] mmc: core: Hold re-tuning during switch commands
2015-03-10 12:42 [PATCH V3 00/15] mmc: host: Add facility to support re-tuning Adrian Hunter
` (3 preceding siblings ...)
2015-03-10 12:42 ` [PATCH V3 04/15] mmc: core: Check re-tuning before retrying Adrian Hunter
@ 2015-03-10 12:43 ` Adrian Hunter
2015-03-10 12:43 ` [PATCH V3 06/15] mmc: core: Hold re-tuning during erase commands Adrian Hunter
` (10 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Adrian Hunter @ 2015-03-10 12:43 UTC (permalink / raw)
To: Ulf Hansson, Chris Ball
Cc: linux-mmc, Aaron Lu, Philip Rakity, Girish K S, 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 | 29 +++++++++++++++++++----------
1 file changed, 19 insertions(+), 10 deletions(-)
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 0ea042d..f67b0fd 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -474,6 +474,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 +508,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 +531,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 +545,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] 18+ messages in thread* [PATCH V3 06/15] mmc: core: Hold re-tuning during erase commands
2015-03-10 12:42 [PATCH V3 00/15] mmc: host: Add facility to support re-tuning Adrian Hunter
` (4 preceding siblings ...)
2015-03-10 12:43 ` [PATCH V3 05/15] mmc: core: Hold re-tuning during switch commands Adrian Hunter
@ 2015-03-10 12:43 ` Adrian Hunter
2015-03-10 12:43 ` [PATCH V3 07/15] mmc: core: Hold re-tuning while bkops ongoing Adrian Hunter
` (9 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Adrian Hunter @ 2015-03-10 12:43 UTC (permalink / raw)
To: Ulf Hansson, Chris Ball
Cc: linux-mmc, Aaron Lu, Philip Rakity, Girish K S, 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 01b9edf..a73dc1b 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1975,6 +1975,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.
@@ -2078,6 +2080,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] 18+ messages in thread* [PATCH V3 07/15] mmc: core: Hold re-tuning while bkops ongoing
2015-03-10 12:42 [PATCH V3 00/15] mmc: host: Add facility to support re-tuning Adrian Hunter
` (5 preceding siblings ...)
2015-03-10 12:43 ` [PATCH V3 06/15] mmc: core: Hold re-tuning during erase commands Adrian Hunter
@ 2015-03-10 12:43 ` Adrian Hunter
2015-03-10 12:43 ` [PATCH V3 08/15] mmc: mmc: Comment that callers need to hold re-tuning if the card is put to sleep Adrian Hunter
` (8 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Adrian Hunter @ 2015-03-10 12:43 UTC (permalink / raw)
To: Ulf Hansson, Chris Ball
Cc: linux-mmc, Aaron Lu, Philip Rakity, Girish K S, 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 a73dc1b..212667b 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -301,6 +301,8 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
} else {
timeout = 0;
use_busy_signal = false;
+ /* Hold re-tuning for ongoing bkops */
+ mmc_retune_hold(card->host);
}
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
@@ -309,6 +311,9 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
if (err) {
pr_warn("%s: Error %d starting bkops\n",
mmc_hostname(card->host), err);
+ /* bkops not ongoing, so release re-tuning */
+ if (!use_busy_signal)
+ mmc_retune_release(card->host);
goto out;
}
@@ -734,6 +739,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] 18+ messages in thread* [PATCH V3 08/15] mmc: mmc: Comment that callers need to hold re-tuning if the card is put to sleep
2015-03-10 12:42 [PATCH V3 00/15] mmc: host: Add facility to support re-tuning Adrian Hunter
` (6 preceding siblings ...)
2015-03-10 12:43 ` [PATCH V3 07/15] mmc: core: Hold re-tuning while bkops ongoing Adrian Hunter
@ 2015-03-10 12:43 ` Adrian Hunter
2015-03-10 12:43 ` [PATCH V3 09/15] mmc: core: Separate out the mmc_switch status check so it can be re-used Adrian Hunter
` (7 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Adrian Hunter @ 2015-03-10 12:43 UTC (permalink / raw)
To: Ulf Hansson, Chris Ball
Cc: linux-mmc, Aaron Lu, Philip Rakity, Girish K S, Al Cooper,
Arend van Spriel
Currently "mmc sleep" is only used before power off and
is not paired with waking up. If that ever changed,
re-tuning might need to be held, so add a comment for that.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
drivers/mmc/core/mmc.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 1d41e85..813b02a 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1496,6 +1496,7 @@ static int mmc_can_sleep(struct mmc_card *card)
return (card && card->ext_csd.rev >= 3);
}
+/* If necessary, callers must hold re-tuning */
static int mmc_sleep(struct mmc_host *host)
{
struct mmc_command cmd = {0};
--
1.9.1
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH V3 09/15] mmc: core: Separate out the mmc_switch status check so it can be re-used
2015-03-10 12:42 [PATCH V3 00/15] mmc: host: Add facility to support re-tuning Adrian Hunter
` (7 preceding siblings ...)
2015-03-10 12:43 ` [PATCH V3 08/15] mmc: mmc: Comment that callers need to hold re-tuning if the card is put to sleep Adrian Hunter
@ 2015-03-10 12:43 ` Adrian Hunter
2015-03-10 12:43 ` [PATCH V3 10/15] mmc: core: Add support for HS400 re-tuning Adrian Hunter
` (6 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Adrian Hunter @ 2015-03-10 12:43 UTC (permalink / raw)
To: Ulf Hansson, Chris Ball
Cc: linux-mmc, Aaron Lu, Philip Rakity, Girish K S, 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 f67b0fd..02be77e 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -449,6 +449,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
@@ -557,20 +572,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] 18+ messages in thread* [PATCH V3 10/15] mmc: core: Add support for HS400 re-tuning
2015-03-10 12:42 [PATCH V3 00/15] mmc: host: Add facility to support re-tuning Adrian Hunter
` (8 preceding siblings ...)
2015-03-10 12:43 ` [PATCH V3 09/15] mmc: core: Separate out the mmc_switch status check so it can be re-used Adrian Hunter
@ 2015-03-10 12:43 ` Adrian Hunter
2015-03-10 12:43 ` [PATCH V3 11/15] mmc: sdhci: Change to new way of doing re-tuning Adrian Hunter
` (5 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Adrian Hunter @ 2015-03-10 12:43 UTC (permalink / raw)
To: Ulf Hansson, Chris Ball
Cc: linux-mmc, Aaron Lu, Philip Rakity, Girish K S, 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 fe6aa57..18022c3 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -349,6 +349,7 @@ EXPORT_SYMBOL(mmc_retune_release);
int mmc_retune(struct mmc_host *host)
{
+ bool return_to_hs400 = false;
int err;
if (host->retune_now)
@@ -363,8 +364,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 813b02a..03577be 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1083,6 +1083,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] 18+ messages in thread* [PATCH V3 11/15] mmc: sdhci: Change to new way of doing re-tuning
2015-03-10 12:42 [PATCH V3 00/15] mmc: host: Add facility to support re-tuning Adrian Hunter
` (9 preceding siblings ...)
2015-03-10 12:43 ` [PATCH V3 10/15] mmc: core: Add support for HS400 re-tuning Adrian Hunter
@ 2015-03-10 12:43 ` Adrian Hunter
2015-03-10 12:43 ` [PATCH V3 12/15] mmc: sdhci: Flag re-tuning is needed on CRC or End-Bit errors Adrian Hunter
` (4 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Adrian Hunter @ 2015-03-10 12:43 UTC (permalink / raw)
To: Ulf Hansson, Chris Ball
Cc: linux-mmc, Aaron Lu, Philip Rakity, Girish K S, 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 | 144 ++++++++++++++--------------------------------
include/linux/mmc/sdhci.h | 3 -
2 files changed, 42 insertions(+), 105 deletions(-)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 0ad412a..1d9b038 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -51,7 +51,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,
@@ -252,17 +251,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);
}
@@ -1348,14 +1336,15 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct sdhci_host *host;
- int present;
+ int present, err;
unsigned long flags;
- u32 tuning_opcode;
host = mmc_priv(mmc);
sdhci_runtime_pm_get(host);
+ err = mmc_retune(mmc);
+
present = mmc_gpio_get_cd(host->mmc);
spin_lock_irqsave(&host->lock, flags);
@@ -1395,43 +1384,13 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
SDHCI_CARD_PRESENT;
}
- if (!present || host->flags & SDHCI_DEVICE_DEAD) {
- host->mrq->cmd->error = -ENOMEDIUM;
+ if (!err && (!present || host->flags & SDHCI_DEVICE_DEAD))
+ err = -ENOMEDIUM;
+
+ if (err) {
+ host->mrq->cmd->error = err;
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
@@ -2077,23 +2036,19 @@ 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;
+ if (!err)
+ mmc_retune_enable(host->mmc, tuning_count);
sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
@@ -2104,6 +2059,24 @@ out_unlock:
return err;
}
+static void sdhci_hold_tuning(struct mmc_host *mmc)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+
+ /*
+ * Re-tuning can be required after runtime resume, so prevent that while
+ * re-tuning is held. Usually, this would be covered anyway by the
+ * autosuspend delay, but this makes certain.
+ */
+ sdhci_runtime_pm_get(host);
+}
+
+static void sdhci_release_tuning(struct mmc_host *mmc)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+
+ sdhci_runtime_pm_put(host);
+}
static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
{
@@ -2248,6 +2221,8 @@ static const struct mmc_host_ops sdhci_ops = {
.start_signal_voltage_switch = sdhci_start_signal_voltage_switch,
.prepare_hs400_tuning = sdhci_prepare_hs400_tuning,
.execute_tuning = sdhci_execute_tuning,
+ .hold_tuning = sdhci_hold_tuning,
+ .release_tuning = sdhci_release_tuning,
.card_event = sdhci_card_event,
.card_busy = sdhci_card_busy,
};
@@ -2349,20 +2324,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 *
@@ -2740,11 +2701,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;
@@ -2794,10 +2752,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;
}
@@ -2834,11 +2788,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;
@@ -2881,10 +2832,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;
@@ -3419,13 +3366,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/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index c3e3db1..c5b00be 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -138,13 +138,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 */
@@ -210,7 +208,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] 18+ messages in thread* [PATCH V3 12/15] mmc: sdhci: Flag re-tuning is needed on CRC or End-Bit errors
2015-03-10 12:42 [PATCH V3 00/15] mmc: host: Add facility to support re-tuning Adrian Hunter
` (10 preceding siblings ...)
2015-03-10 12:43 ` [PATCH V3 11/15] mmc: sdhci: Change to new way of doing re-tuning Adrian Hunter
@ 2015-03-10 12:43 ` Adrian Hunter
2015-03-10 12:43 ` [PATCH V3 13/15] mmc: block: Check re-tuning in the recovery path Adrian Hunter
` (3 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Adrian Hunter @ 2015-03-10 12:43 UTC (permalink / raw)
To: Ulf Hansson, Chris Ball
Cc: linux-mmc, Aaron Lu, Philip Rakity, Girish K S, Al Cooper,
Arend van Spriel
CRC or End-Bit 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/host/sdhci.c | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 1d9b038..25657ee 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2345,8 +2345,10 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask)
if (intmask & SDHCI_INT_TIMEOUT)
host->cmd->error = -ETIMEDOUT;
else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT |
- SDHCI_INT_INDEX))
+ SDHCI_INT_INDEX)) {
host->cmd->error = -EILSEQ;
+ mmc_retune_needed(host->mmc);
+ }
if (host->cmd->error) {
tasklet_schedule(&host->finish_tasklet);
@@ -2471,13 +2473,15 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
if (intmask & SDHCI_INT_DATA_TIMEOUT)
host->data->error = -ETIMEDOUT;
- else if (intmask & SDHCI_INT_DATA_END_BIT)
+ else if (intmask & SDHCI_INT_DATA_END_BIT) {
host->data->error = -EILSEQ;
- else if ((intmask & SDHCI_INT_DATA_CRC) &&
+ mmc_retune_needed(host->mmc);
+ } else if ((intmask & SDHCI_INT_DATA_CRC) &&
SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))
- != MMC_BUS_TEST_R)
+ != MMC_BUS_TEST_R) {
host->data->error = -EILSEQ;
- else if (intmask & SDHCI_INT_ADMA_ERROR) {
+ mmc_retune_needed(host->mmc);
+ } else if (intmask & SDHCI_INT_ADMA_ERROR) {
pr_err("%s: ADMA error\n", mmc_hostname(host->mmc));
sdhci_adma_show_error(host);
host->data->error = -EIO;
--
1.9.1
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH V3 13/15] mmc: block: Check re-tuning in the recovery path
2015-03-10 12:42 [PATCH V3 00/15] mmc: host: Add facility to support re-tuning Adrian Hunter
` (11 preceding siblings ...)
2015-03-10 12:43 ` [PATCH V3 12/15] mmc: sdhci: Flag re-tuning is needed on CRC or End-Bit errors Adrian Hunter
@ 2015-03-10 12:43 ` Adrian Hunter
2015-03-10 12:43 ` [PATCH V3 14/15] mmc: block: Retry errored data requests when re-tuning is needed Adrian Hunter
` (2 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Adrian Hunter @ 2015-03-10 12:43 UTC (permalink / raw)
To: Ulf Hansson, Chris Ball
Cc: linux-mmc, Aaron Lu, Philip Rakity, Girish K S, 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 c69afb5..293e938 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] 18+ messages in thread* [PATCH V3 14/15] mmc: block: Retry errored data requests when re-tuning is needed
2015-03-10 12:42 [PATCH V3 00/15] mmc: host: Add facility to support re-tuning Adrian Hunter
` (12 preceding siblings ...)
2015-03-10 12:43 ` [PATCH V3 13/15] mmc: block: Check re-tuning in the recovery path Adrian Hunter
@ 2015-03-10 12:43 ` Adrian Hunter
2015-03-10 12:43 ` [PATCH V3 15/15] mmc: core: Don't print reset warning if reset is not supported Adrian Hunter
2015-03-16 14:00 ` [PATCH V3 00/15] mmc: host: Add facility to support re-tuning Adrian Hunter
15 siblings, 0 replies; 18+ messages in thread
From: Adrian Hunter @ 2015-03-10 12:43 UTC (permalink / raw)
To: Ulf Hansson, Chris Ball
Cc: linux-mmc, Aaron Lu, Philip Rakity, Girish K S, 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 293e938..3baf7ea 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] 18+ messages in thread* [PATCH V3 15/15] mmc: core: Don't print reset warning if reset is not supported
2015-03-10 12:42 [PATCH V3 00/15] mmc: host: Add facility to support re-tuning Adrian Hunter
` (13 preceding siblings ...)
2015-03-10 12:43 ` [PATCH V3 14/15] mmc: block: Retry errored data requests when re-tuning is needed Adrian Hunter
@ 2015-03-10 12:43 ` Adrian Hunter
2015-03-16 14:00 ` [PATCH V3 00/15] mmc: host: Add facility to support re-tuning Adrian Hunter
15 siblings, 0 replies; 18+ messages in thread
From: Adrian Hunter @ 2015-03-10 12:43 UTC (permalink / raw)
To: Ulf Hansson, Chris Ball
Cc: linux-mmc, Aaron Lu, Philip Rakity, Girish K S, 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 212667b..3e61e56 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2345,7 +2345,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] 18+ messages in thread* Re: [PATCH V3 00/15] mmc: host: Add facility to support re-tuning
2015-03-10 12:42 [PATCH V3 00/15] mmc: host: Add facility to support re-tuning Adrian Hunter
` (14 preceding siblings ...)
2015-03-10 12:43 ` [PATCH V3 15/15] mmc: core: Don't print reset warning if reset is not supported Adrian Hunter
@ 2015-03-16 14:00 ` Adrian Hunter
2015-03-23 8:06 ` Adrian Hunter
15 siblings, 1 reply; 18+ messages in thread
From: Adrian Hunter @ 2015-03-16 14:00 UTC (permalink / raw)
To: Ulf Hansson
Cc: linux-mmc, Aaron Lu, Philip Rakity, Girish K S, Al Cooper,
Arend van Spriel
On 10/03/15 14:42, Adrian Hunter wrote:
> Hi
>
> Here is V3 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.
Ulf, ping?
^ permalink raw reply [flat|nested] 18+ messages in thread* Re: [PATCH V3 00/15] mmc: host: Add facility to support re-tuning
2015-03-16 14:00 ` [PATCH V3 00/15] mmc: host: Add facility to support re-tuning Adrian Hunter
@ 2015-03-23 8:06 ` Adrian Hunter
0 siblings, 0 replies; 18+ messages in thread
From: Adrian Hunter @ 2015-03-23 8:06 UTC (permalink / raw)
To: Ulf Hansson
Cc: linux-mmc, Aaron Lu, Philip Rakity, Girish K S, Al Cooper,
Arend van Spriel
On 16/03/15 16:00, Adrian Hunter wrote:
> On 10/03/15 14:42, Adrian Hunter wrote:
>> Hi
>>
>> Here is V3 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.
>
> Ulf, ping?
Ping
^ permalink raw reply [flat|nested] 18+ messages in thread