summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorUlf Hansson <ulf.hansson@linaro.org>2020-02-04 09:54:48 +0100
committerUlf Hansson <ulf.hansson@linaro.org>2020-03-24 14:35:40 +0100
commit892bf1001459fc38c7e9bc248633681ca628e614 (patch)
tree1d5840ec35378a22d19aa018da23c28e2771227b /drivers/mmc
parent490ff95f8e2c89d7541f187bae78d340b20d0ef0 (diff)
mmc: core: Fixup support for HW busy detection for HPI commands
In case the host specify a max_busy_timeout, we need to validate that the needed timeout for the HPI command conforms to that requirement. If that's not the case, let's convert from a R1B response to a R1 response, as to instruct the host to avoid HW busy detection. Additionally, when R1B is used we must also inform the host about the busy timeout for the command, so let's do that via updating cmd.busy_timeout. Finally, when R1B is used and in case the host supports HW busy detection, there should be no need for doing polling, so then skip that. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Tested-by: Baolin Wang <baolin.wang7@gmail.com> Tested-by: Ludovic Barre <ludovic.barre@st.com> Reviewed-by: Ludovic Barre <ludovic.barre@st.com> Link: https://lore.kernel.org/r/20200204085449.32585-12-ulf.hansson@linaro.org
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/core/mmc_ops.c36
1 files changed, 25 insertions, 11 deletions
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 0099f39a60a3..c75c00b5890d 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -834,27 +834,41 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width)
static int mmc_send_hpi_cmd(struct mmc_card *card)
{
unsigned int busy_timeout_ms = card->ext_csd.out_of_int_time;
+ struct mmc_host *host = card->host;
+ bool use_r1b_resp = true;
struct mmc_command cmd = {};
- unsigned int opcode;
int err;
- opcode = card->ext_csd.hpi_cmd;
- if (opcode == MMC_STOP_TRANSMISSION)
+ cmd.opcode = card->ext_csd.hpi_cmd;
+ cmd.arg = card->rca << 16 | 1;
+
+ /*
+ * Make sure the host's max_busy_timeout fit the needed timeout for HPI.
+ * In case it doesn't, let's instruct the host to avoid HW busy
+ * detection, by using a R1 response instead of R1B.
+ */
+ if (host->max_busy_timeout && busy_timeout_ms > host->max_busy_timeout)
+ use_r1b_resp = false;
+
+ if (cmd.opcode == MMC_STOP_TRANSMISSION && use_r1b_resp) {
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
- else if (opcode == MMC_SEND_STATUS)
+ cmd.busy_timeout = busy_timeout_ms;
+ } else {
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ use_r1b_resp = false;
+ }
- cmd.opcode = opcode;
- cmd.arg = card->rca << 16 | 1;
-
- err = mmc_wait_for_cmd(card->host, &cmd, 0);
+ err = mmc_wait_for_cmd(host, &cmd, 0);
if (err) {
- pr_warn("%s: error %d interrupting operation. "
- "HPI command response %#x\n", mmc_hostname(card->host),
- err, cmd.resp[0]);
+ pr_warn("%s: HPI error %d. Command response %#x\n",
+ mmc_hostname(host), err, cmd.resp[0]);
return err;
}
+ /* No need to poll when using HW busy detection. */
+ if (host->caps & MMC_CAP_WAIT_WHILE_BUSY && use_r1b_resp)
+ return 0;
+
/* Let's poll to find out when the HPI request completes. */
return mmc_poll_for_busy(card, busy_timeout_ms, MMC_BUSY_HPI);
}