linux-block.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/11] Initital support for new power/perf features for SD cards
@ 2021-05-04 16:12 Ulf Hansson
  2021-05-04 16:12 ` [PATCH 01/11] mmc: core: Drop open coding when preparing commands with busy signaling Ulf Hansson
                   ` (12 more replies)
  0 siblings, 13 replies; 40+ messages in thread
From: Ulf Hansson @ 2021-05-04 16:12 UTC (permalink / raw)
  To: linux-mmc, Ulf Hansson, Adrian Hunter
  Cc: Linus Walleij, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

In the SD spec v4.x the SD function extension registers were introduced,
together with a new set of commands (CMD48/49 and CMD58/59) to read and write
to them.

Moreover, in v4.x a new standard function for power management features were
added, while in v6.x a new standard function for performance enhancements
features were added.

This series implement the basics to add support for these new features (and
includes some additional preparations in patch 1->7), by adding support for
reading and parsing these new SD registers. In the final patch we add support
for the SD poweroff notification feature, which also add a function to write to
these registers.

Note that, there are no HW updates need for the host to support reading/parsing
of the these new SD registers. This has been tested with a 64GB Sandisk Extreme
PRO UHS-I A2 card.

Tests and reviews are of course greatly appreciated!

Kind regards
Ulf Hansson

Ulf Hansson (11):
  mmc: core: Drop open coding when preparing commands with busy
    signaling
  mmc: core: Take into account MMC_CAP_NEED_RSP_BUSY for eMMC HPI
    commands
  mmc: core: Re-structure some code in __mmc_poll_for_busy()
  mmc: core: Extend re-use of __mmc_poll_for_busy()
  mmc: core: Enable eMMC sleep commands to use HW busy polling
  mmc: core: Prepare mmc_send_cxd_data() to be re-used for additional
    cmds
  mmc: core: Drop open coding in mmc_sd_switch()
  mmc: core: Parse the SD SCR register for support of CMD48/49 and
    CMD58/59
  mmc: core: Read the SD function extension registers for power
    management
  mmc: core: Read performance enhancements registers for SD cards
  mmc: core: Add support for Power Off Notification for SD cards

 drivers/mmc/core/core.c    |  22 +--
 drivers/mmc/core/mmc.c     |  43 ++---
 drivers/mmc/core/mmc_ops.c | 137 +++++++-------
 drivers/mmc/core/mmc_ops.h |  10 +-
 drivers/mmc/core/sd.c      | 371 ++++++++++++++++++++++++++++++++++++-
 drivers/mmc/core/sd_ops.c  |  38 +---
 include/linux/mmc/card.h   |  22 +++
 include/linux/mmc/sd.h     |   4 +
 8 files changed, 504 insertions(+), 143 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 01/11] mmc: core: Drop open coding when preparing commands with busy signaling
  2021-05-04 16:12 [PATCH 00/11] Initital support for new power/perf features for SD cards Ulf Hansson
@ 2021-05-04 16:12 ` Ulf Hansson
  2021-05-06 12:50   ` Linus Walleij
  2021-05-07  1:42   ` Shawn Lin
  2021-05-04 16:12 ` [PATCH 02/11] mmc: core: Take into account MMC_CAP_NEED_RSP_BUSY for eMMC HPI commands Ulf Hansson
                   ` (11 subsequent siblings)
  12 siblings, 2 replies; 40+ messages in thread
From: Ulf Hansson @ 2021-05-04 16:12 UTC (permalink / raw)
  To: linux-mmc, Ulf Hansson, Adrian Hunter
  Cc: Linus Walleij, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

Similar code for validating the host->max_busy_timeout towards the current
command's busy timeout, exists in mmc_do_erase(), mmc_sleep() and
__mmc_switch(). Let's move the common code into a helper function.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/core/core.c    | 20 ++----------------
 drivers/mmc/core/mmc.c     | 20 +++---------------
 drivers/mmc/core/mmc_ops.c | 42 +++++++++++++++++++++-----------------
 drivers/mmc/core/mmc_ops.h |  3 +++
 4 files changed, 31 insertions(+), 54 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index f194940c5974..b00c84ea8441 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1582,7 +1582,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
 {
 	struct mmc_command cmd = {};
 	unsigned int qty = 0, busy_timeout = 0;
-	bool use_r1b_resp = false;
+	bool use_r1b_resp;
 	int err;
 
 	mmc_retune_hold(card->host);
@@ -1650,23 +1650,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
 	cmd.opcode = MMC_ERASE;
 	cmd.arg = arg;
 	busy_timeout = mmc_erase_timeout(card, arg, qty);
-	/*
-	 * If the host controller supports busy signalling and the timeout for
-	 * the erase operation does not exceed the max_busy_timeout, we should
-	 * use R1B response. Or we need to prevent the host from doing hw busy
-	 * detection, which is done by converting to a R1 response instead.
-	 * Note, some hosts requires R1B, which also means they are on their own
-	 * when it comes to deal with the busy timeout.
-	 */
-	if (!(card->host->caps & MMC_CAP_NEED_RSP_BUSY) &&
-	    card->host->max_busy_timeout &&
-	    busy_timeout > card->host->max_busy_timeout) {
-		cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
-	} else {
-		cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
-		cmd.busy_timeout = busy_timeout;
-		use_r1b_resp = true;
-	}
+	use_r1b_resp = mmc_prepare_busy_cmd(card->host, &cmd, busy_timeout);
 
 	err = mmc_wait_for_cmd(card->host, &cmd, 0);
 	if (err) {
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 8674c3e0c02c..63a7bd0b239c 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1910,6 +1910,7 @@ static int mmc_sleep(struct mmc_host *host)
 	struct mmc_command cmd = {};
 	struct mmc_card *card = host->card;
 	unsigned int timeout_ms = DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000);
+	bool use_r1b_resp;
 	int err;
 
 	/* Re-tuning can't be done once the card is deselected */
@@ -1922,22 +1923,7 @@ static int mmc_sleep(struct mmc_host *host)
 	cmd.opcode = MMC_SLEEP_AWAKE;
 	cmd.arg = card->rca << 16;
 	cmd.arg |= 1 << 15;
-
-	/*
-	 * If the max_busy_timeout of the host is specified, validate it against
-	 * the sleep cmd timeout. A failure means we need to prevent the host
-	 * from doing hw busy detection, which is done by converting to a R1
-	 * response instead of a R1B. Note, some hosts requires R1B, which also
-	 * means they are on their own when it comes to deal with the busy
-	 * timeout.
-	 */
-	if (!(host->caps & MMC_CAP_NEED_RSP_BUSY) && host->max_busy_timeout &&
-	    (timeout_ms > host->max_busy_timeout)) {
-		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-	} else {
-		cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
-		cmd.busy_timeout = timeout_ms;
-	}
+	use_r1b_resp = mmc_prepare_busy_cmd(host, &cmd, timeout_ms);
 
 	err = mmc_wait_for_cmd(host, &cmd, 0);
 	if (err)
@@ -1949,7 +1935,7 @@ static int mmc_sleep(struct mmc_host *host)
 	 * SEND_STATUS command to poll the status because that command (and most
 	 * others) is invalid while the card sleeps.
 	 */
-	if (!cmd.busy_timeout || !(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
+	if (!use_r1b_resp || !(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
 		mmc_delay(timeout_ms);
 
 out_release:
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 5756781fef37..025a4134d5c7 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -521,6 +521,27 @@ int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
 	return __mmc_poll_for_busy(card, timeout_ms, true, false, busy_cmd);
 }
 
+bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd,
+			  unsigned int timeout_ms)
+{
+	/*
+	 * If the max_busy_timeout of the host is specified, make sure it's
+	 * enough to fit the used timeout_ms. In case it's not, let's instruct
+	 * the host to avoid HW busy detection, by converting to a R1 response
+	 * instead of a R1B. Note, some hosts requires R1B, which also means
+	 * they are on their own when it comes to deal with the busy timeout.
+	 */
+	if (!(host->caps & MMC_CAP_NEED_RSP_BUSY) && host->max_busy_timeout &&
+	    (timeout_ms > host->max_busy_timeout)) {
+		cmd->flags = MMC_CMD_AC | MMC_RSP_SPI_R1 | MMC_RSP_R1;
+		return false;
+	}
+
+	cmd->flags = MMC_CMD_AC | MMC_RSP_SPI_R1B | MMC_RSP_R1B;
+	cmd->busy_timeout = timeout_ms;
+	return true;
+}
+
 /**
  *	__mmc_switch - modify EXT_CSD register
  *	@card: the MMC card associated with the data transfer
@@ -543,7 +564,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
 	struct mmc_host *host = card->host;
 	int err;
 	struct mmc_command cmd = {};
-	bool use_r1b_resp = true;
+	bool use_r1b_resp;
 	unsigned char old_timing = host->ios.timing;
 
 	mmc_retune_hold(host);
@@ -554,29 +575,12 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
 		timeout_ms = card->ext_csd.generic_cmd6_time;
 	}
 
-	/*
-	 * If the max_busy_timeout of the host is specified, make sure it's
-	 * enough to fit the used timeout_ms. In case it's not, let's instruct
-	 * the host to avoid HW busy detection, by converting to a R1 response
-	 * instead of a R1B. Note, some hosts requires R1B, which also means
-	 * they are on their own when it comes to deal with the busy timeout.
-	 */
-	if (!(host->caps & MMC_CAP_NEED_RSP_BUSY) && host->max_busy_timeout &&
-	    (timeout_ms > host->max_busy_timeout))
-		use_r1b_resp = false;
-
 	cmd.opcode = MMC_SWITCH;
 	cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
 		  (index << 16) |
 		  (value << 8) |
 		  set;
-	cmd.flags = MMC_CMD_AC;
-	if (use_r1b_resp) {
-		cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
-		cmd.busy_timeout = timeout_ms;
-	} else {
-		cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;
-	}
+	use_r1b_resp = mmc_prepare_busy_cmd(host, &cmd, timeout_ms);
 
 	err = mmc_wait_for_cmd(host, &cmd, retries);
 	if (err)
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 7bc1cfb0654c..ba898c435658 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -18,6 +18,7 @@ enum mmc_busy_cmd {
 
 struct mmc_host;
 struct mmc_card;
+struct mmc_command;
 
 int mmc_select_card(struct mmc_card *card);
 int mmc_deselect_cards(struct mmc_host *host);
@@ -35,6 +36,8 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width);
 int mmc_can_ext_csd(struct mmc_card *card);
 int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
 int mmc_switch_status(struct mmc_card *card, bool crc_err_fatal);
+bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd,
+			  unsigned int timeout_ms);
 int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
 		      enum mmc_busy_cmd busy_cmd);
 int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 02/11] mmc: core: Take into account MMC_CAP_NEED_RSP_BUSY for eMMC HPI commands
  2021-05-04 16:12 [PATCH 00/11] Initital support for new power/perf features for SD cards Ulf Hansson
  2021-05-04 16:12 ` [PATCH 01/11] mmc: core: Drop open coding when preparing commands with busy signaling Ulf Hansson
@ 2021-05-04 16:12 ` Ulf Hansson
  2021-05-06 12:51   ` Linus Walleij
  2021-05-07  1:44   ` Shawn Lin
  2021-05-04 16:12 ` [PATCH 03/11] mmc: core: Re-structure some code in __mmc_poll_for_busy() Ulf Hansson
                   ` (10 subsequent siblings)
  12 siblings, 2 replies; 40+ messages in thread
From: Ulf Hansson @ 2021-05-04 16:12 UTC (permalink / raw)
  To: linux-mmc, Ulf Hansson, Adrian Hunter
  Cc: Linus Walleij, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

In mmc_send_hpi_cmd() the host->max_busy_timeout is being validated towards
the timeout for the eMMC HPI command, as to decide whether an R1 or R1B
response should be used.

Although, it has turned out the some host can't cope with that conversion,
but needs R1B, which means MMC_CAP_NEED_RSP_BUSY is set for them. Let's
take this into account, via using the common mmc_prepare_busy_cmd() when
doing the validation, which also avoids some open coding.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/core/mmc_ops.c | 21 +++++----------------
 1 file changed, 5 insertions(+), 16 deletions(-)

diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 025a4134d5c7..66ae699a410f 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -817,28 +817,17 @@ 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;
+	bool use_r1b_resp = false;
 	struct mmc_command cmd = {};
 	int err;
 
 	cmd.opcode = card->ext_csd.hpi_cmd;
 	cmd.arg = card->rca << 16 | 1;
+	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
 
-	/*
-	 * 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;
-		cmd.busy_timeout = busy_timeout_ms;
-	} else {
-		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-		use_r1b_resp = false;
-	}
+	if (cmd.opcode == MMC_STOP_TRANSMISSION)
+		use_r1b_resp = mmc_prepare_busy_cmd(host, &cmd,
+						    busy_timeout_ms);
 
 	err = mmc_wait_for_cmd(host, &cmd, 0);
 	if (err) {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 03/11] mmc: core: Re-structure some code in __mmc_poll_for_busy()
  2021-05-04 16:12 [PATCH 00/11] Initital support for new power/perf features for SD cards Ulf Hansson
  2021-05-04 16:12 ` [PATCH 01/11] mmc: core: Drop open coding when preparing commands with busy signaling Ulf Hansson
  2021-05-04 16:12 ` [PATCH 02/11] mmc: core: Take into account MMC_CAP_NEED_RSP_BUSY for eMMC HPI commands Ulf Hansson
@ 2021-05-04 16:12 ` Ulf Hansson
  2021-05-06 12:52   ` Linus Walleij
  2021-05-07  1:48   ` Shawn Lin
  2021-05-04 16:12 ` [PATCH 04/11] mmc: core: Extend re-use of __mmc_poll_for_busy() Ulf Hansson
                   ` (9 subsequent siblings)
  12 siblings, 2 replies; 40+ messages in thread
From: Ulf Hansson @ 2021-05-04 16:12 UTC (permalink / raw)
  To: linux-mmc, Ulf Hansson, Adrian Hunter
  Cc: Linus Walleij, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

To make the code a bit more understandable, let's move the check about
whether polling is allowed or not, out to the caller instead. In this way,
we can also drop the send_status in-parameter, so let's do that.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/core/mmc_ops.c | 27 +++++++++++++--------------
 1 file changed, 13 insertions(+), 14 deletions(-)

diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 66ae699a410f..ccaee1cb7ff5 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -465,8 +465,7 @@ static int mmc_busy_status(struct mmc_card *card, bool retry_crc_err,
 }
 
 static int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
-			       bool send_status, bool retry_crc_err,
-			       enum mmc_busy_cmd busy_cmd)
+			       bool retry_crc_err, enum mmc_busy_cmd busy_cmd)
 {
 	struct mmc_host *host = card->host;
 	int err;
@@ -475,16 +474,6 @@ static int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
 	bool expired = false;
 	bool busy = false;
 
-	/*
-	 * In cases when not allowed to poll by using CMD13 or because we aren't
-	 * capable of polling by using ->card_busy(), then rely on waiting the
-	 * stated timeout to be sufficient.
-	 */
-	if (!send_status && !host->ops->card_busy) {
-		mmc_delay(timeout_ms);
-		return 0;
-	}
-
 	timeout = jiffies + msecs_to_jiffies(timeout_ms) + 1;
 	do {
 		/*
@@ -518,7 +507,7 @@ static int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
 int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
 		      enum mmc_busy_cmd busy_cmd)
 {
-	return __mmc_poll_for_busy(card, timeout_ms, true, false, busy_cmd);
+	return __mmc_poll_for_busy(card, timeout_ms, false, busy_cmd);
 }
 
 bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd,
@@ -591,8 +580,18 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
 		mmc_host_is_spi(host))
 		goto out_tim;
 
+	/*
+	 * If the host doesn't support HW polling via the ->card_busy() ops and
+	 * when it's not allowed to poll by using CMD13, then we need to rely on
+	 * waiting the stated timeout to be sufficient.
+	 */
+	if (!send_status && !host->ops->card_busy) {
+		mmc_delay(timeout_ms);
+		goto out_tim;
+	}
+
 	/* Let's try to poll to find out when the command is completed. */
-	err = __mmc_poll_for_busy(card, timeout_ms, send_status, retry_crc_err,
+	err = __mmc_poll_for_busy(card, timeout_ms, retry_crc_err,
 				  MMC_BUSY_CMD6);
 	if (err)
 		goto out;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 04/11] mmc: core: Extend re-use of __mmc_poll_for_busy()
  2021-05-04 16:12 [PATCH 00/11] Initital support for new power/perf features for SD cards Ulf Hansson
                   ` (2 preceding siblings ...)
  2021-05-04 16:12 ` [PATCH 03/11] mmc: core: Re-structure some code in __mmc_poll_for_busy() Ulf Hansson
@ 2021-05-04 16:12 ` Ulf Hansson
  2021-05-06 12:53   ` Linus Walleij
  2021-05-07  1:51   ` Shawn Lin
  2021-05-04 16:12 ` [PATCH 05/11] mmc: core: Enable eMMC sleep commands to use HW busy polling Ulf Hansson
                   ` (8 subsequent siblings)
  12 siblings, 2 replies; 40+ messages in thread
From: Ulf Hansson @ 2021-05-04 16:12 UTC (permalink / raw)
  To: linux-mmc, Ulf Hansson, Adrian Hunter
  Cc: Linus Walleij, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

Via __mmc_poll_for_busy() we end up polling with the ->card_busy() host ops
or by sending the CMD13. To allow polling of different types, which is
needed to support a few new SD card features, let's rework the code around
__mmc_poll_for_busy() to make it more generic.

More precisely, let __mmc_poll_for_busy() take a pointer to a callback
function as in-parameter, which it calls to poll for busy state completion.
Additionally, let's share __mmc_poll_for_busy() to allow it to be re-used
outside of mmc_ops.c. Subsequent changes will make use of it.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/core/core.c    |  2 +-
 drivers/mmc/core/mmc_ops.c | 42 ++++++++++++++++++++++++--------------
 drivers/mmc/core/mmc_ops.h |  5 ++++-
 3 files changed, 32 insertions(+), 17 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index b00c84ea8441..b039dcff17f8 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1671,7 +1671,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
 		goto out;
 
 	/* Let's poll to find out when the erase operation completes. */
-	err = mmc_poll_for_busy(card, busy_timeout, MMC_BUSY_ERASE);
+	err = mmc_poll_for_busy(card, busy_timeout, false, MMC_BUSY_ERASE);
 
 out:
 	mmc_retune_release(card->host);
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index ccaee1cb7ff5..653627fe02a3 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -53,6 +53,12 @@ static const u8 tuning_blk_pattern_8bit[] = {
 	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
 };
 
+struct mmc_busy_data {
+	struct mmc_card *card;
+	bool retry_crc_err;
+	enum mmc_busy_cmd busy_cmd;
+};
+
 int __mmc_send_status(struct mmc_card *card, u32 *status, unsigned int retries)
 {
 	int err;
@@ -424,10 +430,10 @@ int mmc_switch_status(struct mmc_card *card, bool crc_err_fatal)
 	return mmc_switch_status_error(card->host, status);
 }
 
-static int mmc_busy_status(struct mmc_card *card, bool retry_crc_err,
-			   enum mmc_busy_cmd busy_cmd, bool *busy)
+static int mmc_busy_cb(void *cb_data, bool *busy)
 {
-	struct mmc_host *host = card->host;
+	struct mmc_busy_data *data = cb_data;
+	struct mmc_host *host = data->card->host;
 	u32 status = 0;
 	int err;
 
@@ -436,17 +442,17 @@ static int mmc_busy_status(struct mmc_card *card, bool retry_crc_err,
 		return 0;
 	}
 
-	err = mmc_send_status(card, &status);
-	if (retry_crc_err && err == -EILSEQ) {
+	err = mmc_send_status(data->card, &status);
+	if (data->retry_crc_err && err == -EILSEQ) {
 		*busy = true;
 		return 0;
 	}
 	if (err)
 		return err;
 
-	switch (busy_cmd) {
+	switch (data->busy_cmd) {
 	case MMC_BUSY_CMD6:
-		err = mmc_switch_status_error(card->host, status);
+		err = mmc_switch_status_error(host, status);
 		break;
 	case MMC_BUSY_ERASE:
 		err = R1_STATUS(status) ? -EIO : 0;
@@ -464,8 +470,9 @@ static int mmc_busy_status(struct mmc_card *card, bool retry_crc_err,
 	return 0;
 }
 
-static int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
-			       bool retry_crc_err, enum mmc_busy_cmd busy_cmd)
+int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
+			int (*busy_cb)(void *cb_data, bool *busy),
+			void *cb_data)
 {
 	struct mmc_host *host = card->host;
 	int err;
@@ -482,7 +489,7 @@ static int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
 		 */
 		expired = time_after(jiffies, timeout);
 
-		err = mmc_busy_status(card, retry_crc_err, busy_cmd, &busy);
+		err = (*busy_cb)(cb_data, &busy);
 		if (err)
 			return err;
 
@@ -505,9 +512,15 @@ static int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
 }
 
 int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
-		      enum mmc_busy_cmd busy_cmd)
+		      bool retry_crc_err, enum mmc_busy_cmd busy_cmd)
 {
-	return __mmc_poll_for_busy(card, timeout_ms, false, busy_cmd);
+	struct mmc_busy_data cb_data;
+
+	cb_data.card = card;
+	cb_data.retry_crc_err = retry_crc_err;
+	cb_data.busy_cmd = busy_cmd;
+
+	return __mmc_poll_for_busy(card, timeout_ms, &mmc_busy_cb, &cb_data);
 }
 
 bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd,
@@ -591,8 +604,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
 	}
 
 	/* Let's try to poll to find out when the command is completed. */
-	err = __mmc_poll_for_busy(card, timeout_ms, retry_crc_err,
-				  MMC_BUSY_CMD6);
+	err = mmc_poll_for_busy(card, timeout_ms, retry_crc_err, MMC_BUSY_CMD6);
 	if (err)
 		goto out;
 
@@ -840,7 +852,7 @@ static int mmc_send_hpi_cmd(struct mmc_card *card)
 		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);
+	return mmc_poll_for_busy(card, busy_timeout_ms, false, MMC_BUSY_HPI);
 }
 
 /**
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index ba898c435658..aca66c128804 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -38,8 +38,11 @@ int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
 int mmc_switch_status(struct mmc_card *card, bool crc_err_fatal);
 bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd,
 			  unsigned int timeout_ms);
+int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
+			int (*busy_cb)(void *cb_data, bool *busy),
+			void *cb_data);
 int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
-		      enum mmc_busy_cmd busy_cmd);
+		      bool retry_crc_err, enum mmc_busy_cmd busy_cmd);
 int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
 		unsigned int timeout_ms, unsigned char timing,
 		bool send_status, bool retry_crc_err, unsigned int retries);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 05/11] mmc: core: Enable eMMC sleep commands to use HW busy polling
  2021-05-04 16:12 [PATCH 00/11] Initital support for new power/perf features for SD cards Ulf Hansson
                   ` (3 preceding siblings ...)
  2021-05-04 16:12 ` [PATCH 04/11] mmc: core: Extend re-use of __mmc_poll_for_busy() Ulf Hansson
@ 2021-05-04 16:12 ` Ulf Hansson
  2021-05-06 12:55   ` Linus Walleij
  2021-05-07  1:52   ` Shawn Lin
  2021-05-04 16:12 ` [PATCH 06/11] mmc: core: Prepare mmc_send_cxd_data() to be re-used for additional cmds Ulf Hansson
                   ` (7 subsequent siblings)
  12 siblings, 2 replies; 40+ messages in thread
From: Ulf Hansson @ 2021-05-04 16:12 UTC (permalink / raw)
  To: linux-mmc, Ulf Hansson, Adrian Hunter
  Cc: Linus Walleij, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

After the eMMC sleep command (CMD5) has been sent, the card start signals
busy on the DAT0 line, which can be monitored to understand when it's
allowed to proceed to power off the VCC regulator.

When MMC_CAP_WAIT_WHILE_BUSY isn't supported by the host the DAT0 line
isn't being monitored for busy completion, but instead we are waiting a
fixed period of time. The time corresponds to the sleep timeout that is
specified in the EXT_CSD register of the eMMC card. This is many cases
suboptimal, as the timeout corresponds to the worst case scenario.

To improve the situation add support for HW busy polling through the
->card_busy() host ops, when the host supports this.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/core/mmc.c | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 63a7bd0b239c..13074aa1f605 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1905,6 +1905,14 @@ static int mmc_can_sleep(struct mmc_card *card)
 	return card->ext_csd.rev >= 3;
 }
 
+static int mmc_sleep_busy_cb(void *cb_data, bool *busy)
+{
+	struct mmc_host *host = cb_data;
+
+	*busy = host->ops->card_busy(host);
+	return 0;
+}
+
 static int mmc_sleep(struct mmc_host *host)
 {
 	struct mmc_command cmd = {};
@@ -1930,13 +1938,20 @@ static int mmc_sleep(struct mmc_host *host)
 		goto out_release;
 
 	/*
-	 * If the host does not wait while the card signals busy, then we will
-	 * will have to wait the sleep/awake timeout.  Note, we cannot use the
-	 * SEND_STATUS command to poll the status because that command (and most
-	 * others) is invalid while the card sleeps.
+	 * If the host does not wait while the card signals busy, then we can
+	 * try to poll, but only if the host supports HW polling, as the
+	 * SEND_STATUS cmd is not allowed. If we can't poll, then we simply need
+	 * to wait the sleep/awake timeout.
 	 */
-	if (!use_r1b_resp || !(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
+	if (host->caps & MMC_CAP_WAIT_WHILE_BUSY && use_r1b_resp)
+		goto out_release;
+
+	if (!host->ops->card_busy) {
 		mmc_delay(timeout_ms);
+		goto out_release;
+	}
+
+	err = __mmc_poll_for_busy(card, timeout_ms, &mmc_sleep_busy_cb, host);
 
 out_release:
 	mmc_retune_release(host);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 06/11] mmc: core: Prepare mmc_send_cxd_data() to be re-used for additional cmds
  2021-05-04 16:12 [PATCH 00/11] Initital support for new power/perf features for SD cards Ulf Hansson
                   ` (4 preceding siblings ...)
  2021-05-04 16:12 ` [PATCH 05/11] mmc: core: Enable eMMC sleep commands to use HW busy polling Ulf Hansson
@ 2021-05-04 16:12 ` Ulf Hansson
  2021-05-06 12:56   ` Linus Walleij
                     ` (2 more replies)
  2021-05-04 16:12 ` [PATCH 07/11] mmc: core: Drop open coding in mmc_sd_switch() Ulf Hansson
                   ` (6 subsequent siblings)
  12 siblings, 3 replies; 40+ messages in thread
From: Ulf Hansson @ 2021-05-04 16:12 UTC (permalink / raw)
  To: linux-mmc, Ulf Hansson, Adrian Hunter
  Cc: Linus Walleij, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

The function mmc_send_cxd_data() sends a data read command of ADTC type and
prepares to receive an R1 response. To make it even more re-usable, let's
extend it with another in-parameter for the command argument. While at it,
let's also rename the function to mmc_send_adtc_data() as it better
describes its purpose.

Note that, this change doesn't add any new users of the function. Instead
that is done from subsequent changes.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/core/mmc_ops.c | 11 +++++------
 drivers/mmc/core/mmc_ops.h |  2 ++
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 653627fe02a3..b1da8f1950ee 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -252,9 +252,8 @@ mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode)
  * NOTE: void *buf, caller for the buf is required to use DMA-capable
  * buffer or on-stack buffer (with some overhead in callee).
  */
-static int
-mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
-		u32 opcode, void *buf, unsigned len)
+int mmc_send_adtc_data(struct mmc_card *card, struct mmc_host *host, u32 opcode,
+		       u32 args, void *buf, unsigned len)
 {
 	struct mmc_request mrq = {};
 	struct mmc_command cmd = {};
@@ -265,7 +264,7 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
 	mrq.data = &data;
 
 	cmd.opcode = opcode;
-	cmd.arg = 0;
+	cmd.arg = args;
 
 	/* NOTE HACK:  the MMC_RSP_SPI_R1 is always correct here, but we
 	 * rely on callers to never use this with "native" calls for reading
@@ -311,7 +310,7 @@ static int mmc_spi_send_cxd(struct mmc_host *host, u32 *cxd, u32 opcode)
 	if (!cxd_tmp)
 		return -ENOMEM;
 
-	ret = mmc_send_cxd_data(NULL, host, opcode, cxd_tmp, 16);
+	ret = mmc_send_adtc_data(NULL, host, opcode, 0, cxd_tmp, 16);
 	if (ret)
 		goto err;
 
@@ -359,7 +358,7 @@ int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
 	if (!ext_csd)
 		return -ENOMEM;
 
-	err = mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD, ext_csd,
+	err = mmc_send_adtc_data(card, card->host, MMC_SEND_EXT_CSD, 0, ext_csd,
 				512);
 	if (err)
 		kfree(ext_csd);
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index aca66c128804..2b1d730e56bf 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -26,6 +26,8 @@ int mmc_set_dsr(struct mmc_host *host);
 int mmc_go_idle(struct mmc_host *host);
 int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
 int mmc_set_relative_addr(struct mmc_card *card);
+int mmc_send_adtc_data(struct mmc_card *card, struct mmc_host *host, u32 opcode,
+		       u32 args, void *buf, unsigned len);
 int mmc_send_csd(struct mmc_card *card, u32 *csd);
 int __mmc_send_status(struct mmc_card *card, u32 *status, unsigned int retries);
 int mmc_send_status(struct mmc_card *card, u32 *status);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 07/11] mmc: core: Drop open coding in mmc_sd_switch()
  2021-05-04 16:12 [PATCH 00/11] Initital support for new power/perf features for SD cards Ulf Hansson
                   ` (5 preceding siblings ...)
  2021-05-04 16:12 ` [PATCH 06/11] mmc: core: Prepare mmc_send_cxd_data() to be re-used for additional cmds Ulf Hansson
@ 2021-05-04 16:12 ` Ulf Hansson
  2021-05-06 12:57   ` Linus Walleij
  2021-05-07  1:54   ` Shawn Lin
  2021-05-04 16:12 ` [PATCH 08/11] mmc: core: Parse the SD SCR register for support of CMD48/49 and CMD58/59 Ulf Hansson
                   ` (5 subsequent siblings)
  12 siblings, 2 replies; 40+ messages in thread
From: Ulf Hansson @ 2021-05-04 16:12 UTC (permalink / raw)
  To: linux-mmc, Ulf Hansson, Adrian Hunter
  Cc: Linus Walleij, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

The SD_SWITCH (CMD6) is an ADTC type of command with an R1 response, which
can be sent by using the mmc_send_adtc_data(). Let's do that and drop the
open coding in mmc_sd_switch().

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/core/sd_ops.c | 38 +++++++-------------------------------
 1 file changed, 7 insertions(+), 31 deletions(-)

diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index d61ff811218c..ef8d1dce5af1 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -17,6 +17,7 @@
 
 #include "core.h"
 #include "sd_ops.h"
+#include "mmc_ops.h"
 
 int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
 {
@@ -309,43 +310,18 @@ int mmc_app_send_scr(struct mmc_card *card)
 int mmc_sd_switch(struct mmc_card *card, int mode, int group,
 	u8 value, u8 *resp)
 {
-	struct mmc_request mrq = {};
-	struct mmc_command cmd = {};
-	struct mmc_data data = {};
-	struct scatterlist sg;
+	u32 cmd_args;
 
 	/* NOTE: caller guarantees resp is heap-allocated */
 
 	mode = !!mode;
 	value &= 0xF;
+	cmd_args = mode << 31 | 0x00FFFFFF;
+	cmd_args &= ~(0xF << (group * 4));
+	cmd_args |= value << (group * 4);
 
-	mrq.cmd = &cmd;
-	mrq.data = &data;
-
-	cmd.opcode = SD_SWITCH;
-	cmd.arg = mode << 31 | 0x00FFFFFF;
-	cmd.arg &= ~(0xF << (group * 4));
-	cmd.arg |= value << (group * 4);
-	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
-
-	data.blksz = 64;
-	data.blocks = 1;
-	data.flags = MMC_DATA_READ;
-	data.sg = &sg;
-	data.sg_len = 1;
-
-	sg_init_one(&sg, resp, 64);
-
-	mmc_set_data_timeout(&data, card);
-
-	mmc_wait_for_req(card->host, &mrq);
-
-	if (cmd.error)
-		return cmd.error;
-	if (data.error)
-		return data.error;
-
-	return 0;
+	return mmc_send_adtc_data(card, card->host, SD_SWITCH, cmd_args, resp,
+				  64);
 }
 
 int mmc_app_sd_status(struct mmc_card *card, void *ssr)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 08/11] mmc: core: Parse the SD SCR register for support of CMD48/49 and CMD58/59
  2021-05-04 16:12 [PATCH 00/11] Initital support for new power/perf features for SD cards Ulf Hansson
                   ` (6 preceding siblings ...)
  2021-05-04 16:12 ` [PATCH 07/11] mmc: core: Drop open coding in mmc_sd_switch() Ulf Hansson
@ 2021-05-04 16:12 ` Ulf Hansson
  2021-05-06 13:01   ` Linus Walleij
  2021-05-07  1:58   ` Shawn Lin
  2021-05-04 16:12 ` [PATCH 09/11] mmc: core: Read the SD function extension registers for power management Ulf Hansson
                   ` (4 subsequent siblings)
  12 siblings, 2 replies; 40+ messages in thread
From: Ulf Hansson @ 2021-05-04 16:12 UTC (permalink / raw)
  To: linux-mmc, Ulf Hansson, Adrian Hunter
  Cc: Linus Walleij, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

In SD spec v4.x the support for CMD48/49 and CMD58/59 were introduced as
optional features. To let the card announce whether it supports the
commands, the SCR register has been extended with corresponding support
bits. Let's parse and store this information for later use.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/core/sd.c    | 4 +++-
 include/linux/mmc/card.h | 2 ++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 2c48d6504101..de7b5f8df550 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -222,7 +222,9 @@ static int mmc_decode_scr(struct mmc_card *card)
 	else
 		card->erased_byte = 0x0;
 
-	if (scr->sda_spec3)
+	if (scr->sda_spec4)
+		scr->cmds = UNSTUFF_BITS(resp, 32, 4);
+	else if (scr->sda_spec3)
 		scr->cmds = UNSTUFF_BITS(resp, 32, 2);
 
 	/* SD Spec says: any SD Card shall set at least bits 0 and 2 */
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index f9ad35dd6012..858fc4d11240 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -139,6 +139,8 @@ struct sd_scr {
 	unsigned char		cmds;
 #define SD_SCR_CMD20_SUPPORT   (1<<0)
 #define SD_SCR_CMD23_SUPPORT   (1<<1)
+#define SD_SCR_CMD48_SUPPORT   (1<<2)
+#define SD_SCR_CMD58_SUPPORT   (1<<3)
 };
 
 struct sd_ssr {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 09/11] mmc: core: Read the SD function extension registers for power management
  2021-05-04 16:12 [PATCH 00/11] Initital support for new power/perf features for SD cards Ulf Hansson
                   ` (7 preceding siblings ...)
  2021-05-04 16:12 ` [PATCH 08/11] mmc: core: Parse the SD SCR register for support of CMD48/49 and CMD58/59 Ulf Hansson
@ 2021-05-04 16:12 ` Ulf Hansson
  2021-05-06 13:04   ` Linus Walleij
  2021-05-07  2:06   ` Shawn Lin
  2021-05-04 16:12 ` [PATCH 10/11] mmc: core: Read performance enhancements registers for SD cards Ulf Hansson
                   ` (3 subsequent siblings)
  12 siblings, 2 replies; 40+ messages in thread
From: Ulf Hansson @ 2021-05-04 16:12 UTC (permalink / raw)
  To: linux-mmc, Ulf Hansson, Adrian Hunter
  Cc: Linus Walleij, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

In SD spec v4.x the SD function extension registers were introduced. A
specific function register were added to let the card announce support for
optional features in regards to power management. The features that were
added are "Power Off Notification", "Power Down Mode" and "Power
Sustenance".

As a first step, let's read and parse this register for power management
during the SD card initialization and store the information about the
supported features in the struct mmc_card. In this way, we prepare for
subsequent changes to implement the complete support for the new features.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/core/sd.c    | 178 +++++++++++++++++++++++++++++++++++++++
 include/linux/mmc/card.h |  13 +++
 include/linux/mmc/sd.h   |   3 +
 3 files changed, 194 insertions(+)

diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index de7b5f8df550..cb5e8b2fc32f 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -996,6 +996,177 @@ static bool mmc_sd_card_using_v18(struct mmc_card *card)
 	       (SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR104 | SD_MODE_UHS_DDR50);
 }
 
+static int sd_read_ext_reg(struct mmc_card *card, u8 fno, u8 page,
+			   u16 offset, u16 len, u8 *reg_buf)
+{
+	u32 cmd_args;
+
+	/*
+	 * Command arguments of CMD48:
+	 * [31:31] MIO (0 = memory).
+	 * [30:27] FNO (function number).
+	 * [26:26] reserved (0).
+	 * [25:18] page number.
+	 * [17:9] offset address.
+	 * [8:0] length (0 = 1 byte, 1ff = 512 bytes).
+	 */
+	cmd_args = fno << 27 | page << 18 | offset << 9 | (len -1);
+
+	return mmc_send_adtc_data(card, card->host, SD_READ_EXTR_SINGLE,
+				  cmd_args, reg_buf, 512);
+}
+
+static int sd_parse_ext_reg_power(struct mmc_card *card, u8 fno, u8 page,
+				  u16 offset)
+{
+	int err;
+	u8 *reg_buf;
+
+	reg_buf = kzalloc(512, GFP_KERNEL);
+	if (!reg_buf)
+		return -ENOMEM;
+
+	/* Read the extension register for power management function. */
+	err = sd_read_ext_reg(card, fno, page, offset, 512, reg_buf);
+	if (err) {
+		pr_warn("%s: error %d reading PM func of ext reg\n",
+			mmc_hostname(card->host), err);
+		goto out;
+	}
+
+	/* PM revision consists of 4 bits. */
+	card->ext_power.rev = reg_buf[0] & 0xf;
+
+	/* Power Off Notification support at bit 4. */
+	if (reg_buf[1] & 0x10)
+		card->ext_power.feature_support |= SD_EXT_POWER_OFF_NOTIFY;
+
+	/* Power Sustenance support at bit 5. */
+	if (reg_buf[1] & 0x20)
+		card->ext_power.feature_support |= SD_EXT_POWER_SUSTENANCE;
+
+	/* Power Down Mode support at bit 6. */
+	if (reg_buf[1] & 0x40)
+		card->ext_power.feature_support |= SD_EXT_POWER_DOWN_MODE;
+
+	card->ext_power.fno = fno;
+	card->ext_power.page = page;
+	card->ext_power.offset = offset;
+
+out:
+	kfree(reg_buf);
+	return err;
+}
+
+static int sd_parse_ext_reg(struct mmc_card *card, u8 *gen_info_buf,
+			    u16 *next_ext_addr)
+{
+	u8 num_regs, fno, page;
+	u16 sfc, offset, ext = *next_ext_addr;
+	u32 reg_addr;
+
+	/*
+	 * Parse only one register set per extension, as that is sufficient to
+	 * support the standard functions. This means another 48 bytes in the
+	 * buffer must be available.
+	 */
+	if (ext + 48 > 512)
+		return -EFAULT;
+
+	/* Standard Function Code */
+	memcpy(&sfc, &gen_info_buf[ext], 2);
+
+	/* Address to the next extension. */
+	memcpy(next_ext_addr, &gen_info_buf[ext + 40], 2);
+
+	/* Number of registers for this extension. */
+	num_regs = gen_info_buf[ext + 42];
+
+	/* We support only one register per extension. */
+	if (num_regs != 1)
+		return 0;
+
+	/* Extension register address. */
+	memcpy(&reg_addr, &gen_info_buf[ext + 44], 4);
+
+	/* 9 bits (0 to 8) contains the offset address. */
+	offset = reg_addr & 0x1ff;
+
+	/* 8 bits (9 to 16) contains the page number. */
+	page = reg_addr >> 9 & 0xff ;
+
+	/* 4 bits (18 to 21) contains the function number. */
+	fno = reg_addr >> 18 & 0xf;
+
+	/* Standard Function Code for power management. */
+	if (sfc == 0x1)
+		return sd_parse_ext_reg_power(card, fno, page, offset);
+
+	return 0;
+}
+
+static int sd_read_ext_regs(struct mmc_card *card)
+{
+	int err, i;
+	u8 num_ext, *gen_info_buf;
+	u16 rev, len, next_ext_addr;
+
+	if (mmc_host_is_spi(card->host))
+		return 0;
+
+	if (!(card->scr.cmds & SD_SCR_CMD48_SUPPORT))
+		return 0;
+
+	gen_info_buf = kzalloc(512, GFP_KERNEL);
+	if (!gen_info_buf)
+		return -ENOMEM;
+
+	/*
+	 * Read 512 bytes of general info, which is found at function number 0,
+	 * at page 0 and with no offset.
+	 */
+	err = sd_read_ext_reg(card, 0, 0, 0, 512, gen_info_buf);
+	if (err) {
+		pr_warn("%s: error %d reading general info of SD ext reg\n",
+			mmc_hostname(card->host), err);
+		goto out;
+	}
+
+	/* General info structure revision. */
+	memcpy(&rev, &gen_info_buf[0], 2);
+
+	/* Length of general info in bytes. */
+	memcpy(&len, &gen_info_buf[2], 2);
+
+	/* Number of extensions to be find. */
+	num_ext = gen_info_buf[4];
+
+	/* We support revision 0, but limit it to 512 bytes for simplicity. */
+	if (rev != 0 || len > 512) {
+		pr_warn("%s: non-supported SD ext reg layout\n",
+			mmc_hostname(card->host));
+		goto out;
+	}
+
+	/*
+	 * Parse the extension registers. The first extension should start
+	 * immediately after the general info header (16 bytes).
+	 */
+	next_ext_addr = 16;
+	for (i = 0; i < num_ext; i++) {
+		err = sd_parse_ext_reg(card, gen_info_buf, &next_ext_addr);
+		if (err) {
+			pr_warn("%s: error %d parsing SD ext reg\n",
+				mmc_hostname(card->host), err);
+			goto out;
+		}
+	}
+
+out:
+	kfree(gen_info_buf);
+	return err;
+}
+
 /*
  * Handle the detection and initialisation of a card.
  *
@@ -1144,6 +1315,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
 		}
 	}
 
+	if (!oldcard) {
+		/* Read/parse the extension registers. */
+		err = sd_read_ext_regs(card);
+		if (err)
+			goto free_card;
+	}
+
 	if (host->cqe_ops && !host->cqe_enabled) {
 		err = host->cqe_ops->cqe_enable(host, card);
 		if (!err) {
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 858fc4d11240..03a862e93594 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -191,6 +191,18 @@ struct sd_switch_caps {
 #define SD_MAX_CURRENT_800	(1 << SD_SET_CURRENT_LIMIT_800)
 };
 
+struct sd_ext_reg {
+	u8			fno;
+	u8			page;
+	u16			offset;
+	u8			rev;
+	u8			feature_support;
+/* Power Management Function. */
+#define SD_EXT_POWER_OFF_NOTIFY	(1<<0)
+#define SD_EXT_POWER_SUSTENANCE	(1<<1)
+#define SD_EXT_POWER_DOWN_MODE	(1<<2)
+};
+
 struct sdio_cccr {
 	unsigned int		sdio_vsn;
 	unsigned int		sd_vsn;
@@ -292,6 +304,7 @@ struct mmc_card {
 	struct sd_scr		scr;		/* extra SD information */
 	struct sd_ssr		ssr;		/* yet more SD information */
 	struct sd_switch_caps	sw_caps;	/* switch (CMD6) caps */
+	struct sd_ext_reg	ext_power;	/* SD extension reg for PM */
 
 	unsigned int		sdio_funcs;	/* number of SDIO functions */
 	atomic_t		sdio_funcs_probed; /* number of probed SDIO funcs */
diff --git a/include/linux/mmc/sd.h b/include/linux/mmc/sd.h
index 2236aa540faa..43bfc5c39ad4 100644
--- a/include/linux/mmc/sd.h
+++ b/include/linux/mmc/sd.h
@@ -29,6 +29,9 @@
 #define SD_APP_OP_COND           41   /* bcr  [31:0] OCR         R3  */
 #define SD_APP_SEND_SCR          51   /* adtc                    R1  */
 
+  /* class 11 */
+#define SD_READ_EXTR_SINGLE      48   /* adtc [31:0]             R1  */
+
 /* OCR bit definitions */
 #define SD_OCR_S18R		(1 << 24)    /* 1.8V switching request */
 #define SD_ROCR_S18A		SD_OCR_S18R  /* 1.8V switching accepted by card */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 10/11] mmc: core: Read performance enhancements registers for SD cards
  2021-05-04 16:12 [PATCH 00/11] Initital support for new power/perf features for SD cards Ulf Hansson
                   ` (8 preceding siblings ...)
  2021-05-04 16:12 ` [PATCH 09/11] mmc: core: Read the SD function extension registers for power management Ulf Hansson
@ 2021-05-04 16:12 ` Ulf Hansson
  2021-05-06 13:05   ` Linus Walleij
  2021-05-04 16:12 ` [PATCH 11/11] mmc: core: Add support for Power Off Notification " Ulf Hansson
                   ` (2 subsequent siblings)
  12 siblings, 1 reply; 40+ messages in thread
From: Ulf Hansson @ 2021-05-04 16:12 UTC (permalink / raw)
  To: linux-mmc, Ulf Hansson, Adrian Hunter
  Cc: Linus Walleij, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

In SD spec v6.x the SD function extension registers for performance
enhancements were introduced. These registers let the SD card announce
supports for various performance related features, like "self-maintenance",
"cache" and "command queuing".

Let's extend the parsing of SD function extension registers and store the
information in the struct mmc_card. This prepares for subsequent changes to
implement the complete support for new the performance enhancement
features.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/core/sd.c    | 53 ++++++++++++++++++++++++++++++++++++++++
 include/linux/mmc/card.h |  7 ++++++
 2 files changed, 60 insertions(+)

diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index cb5e8b2fc32f..702d7c1a0aec 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1058,6 +1058,55 @@ static int sd_parse_ext_reg_power(struct mmc_card *card, u8 fno, u8 page,
 	return err;
 }
 
+static int sd_parse_ext_reg_perf(struct mmc_card *card, u8 fno, u8 page,
+				 u16 offset)
+{
+	int err;
+	u8 *reg_buf;
+
+	reg_buf = kzalloc(512, GFP_KERNEL);
+	if (!reg_buf)
+		return -ENOMEM;
+
+	err = sd_read_ext_reg(card, fno, page, offset, 512, reg_buf);
+	if (err) {
+		pr_warn("%s: error %d reading PERF func of ext reg\n",
+			mmc_hostname(card->host), err);
+		goto out;
+	}
+
+	/* PERF revision. */
+	card->ext_perf.rev = reg_buf[0];
+
+	/* FX_EVENT support at bit 0. */
+	if (reg_buf[1] & 0x1)
+		card->ext_perf.feature_support |= SD_EXT_PERF_FX_EVENT;
+
+	/* Card initiated self-maintenance support at bit 0. */
+	if (reg_buf[2] & 0x1)
+		card->ext_perf.feature_support |= SD_EXT_PERF_CARD_MAINT;
+
+	/* Host initiated self-maintenance support at bit 1. */
+	if (reg_buf[2] & 0x2)
+		card->ext_perf.feature_support |= SD_EXT_PERF_HOST_MAINT;
+
+	/* Cache support at bit 0. */
+	if (reg_buf[4] & 0x1)
+		card->ext_perf.feature_support |= SD_EXT_PERF_CACHE;
+
+	/* Command queue support indicated via queue depth bits (0 to 4). */
+	if (reg_buf[6] & 0x1f)
+		card->ext_perf.feature_support |= SD_EXT_PERF_CMD_QUEUE;
+
+	card->ext_perf.fno = fno;
+	card->ext_perf.page = page;
+	card->ext_perf.offset = offset;
+
+out:
+	kfree(reg_buf);
+	return err;
+}
+
 static int sd_parse_ext_reg(struct mmc_card *card, u8 *gen_info_buf,
 			    u16 *next_ext_addr)
 {
@@ -1102,6 +1151,10 @@ static int sd_parse_ext_reg(struct mmc_card *card, u8 *gen_info_buf,
 	if (sfc == 0x1)
 		return sd_parse_ext_reg_power(card, fno, page, offset);
 
+	/* Standard Function Code for performance enhancement. */
+	if (sfc == 0x2)
+		return sd_parse_ext_reg_perf(card, fno, page, offset);
+
 	return 0;
 }
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 03a862e93594..2867af0635f8 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -201,6 +201,12 @@ struct sd_ext_reg {
 #define SD_EXT_POWER_OFF_NOTIFY	(1<<0)
 #define SD_EXT_POWER_SUSTENANCE	(1<<1)
 #define SD_EXT_POWER_DOWN_MODE	(1<<2)
+/* Performance Enhancement Function. */
+#define SD_EXT_PERF_FX_EVENT	(1<<0)
+#define SD_EXT_PERF_CARD_MAINT	(1<<1)
+#define SD_EXT_PERF_HOST_MAINT	(1<<2)
+#define SD_EXT_PERF_CACHE	(1<<3)
+#define SD_EXT_PERF_CMD_QUEUE	(1<<4)
 };
 
 struct sdio_cccr {
@@ -305,6 +311,7 @@ struct mmc_card {
 	struct sd_ssr		ssr;		/* yet more SD information */
 	struct sd_switch_caps	sw_caps;	/* switch (CMD6) caps */
 	struct sd_ext_reg	ext_power;	/* SD extension reg for PM */
+	struct sd_ext_reg	ext_perf;	/* SD extension reg for PERF */
 
 	unsigned int		sdio_funcs;	/* number of SDIO functions */
 	atomic_t		sdio_funcs_probed; /* number of probed SDIO funcs */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 11/11] mmc: core: Add support for Power Off Notification for SD cards
  2021-05-04 16:12 [PATCH 00/11] Initital support for new power/perf features for SD cards Ulf Hansson
                   ` (9 preceding siblings ...)
  2021-05-04 16:12 ` [PATCH 10/11] mmc: core: Read performance enhancements registers for SD cards Ulf Hansson
@ 2021-05-04 16:12 ` Ulf Hansson
  2021-05-06 13:07   ` Linus Walleij
  2021-05-07  6:44 ` [PATCH 00/11] Initital support for new power/perf features " Avri Altman
  2021-05-11 10:56 ` Ulf Hansson
  12 siblings, 1 reply; 40+ messages in thread
From: Ulf Hansson @ 2021-05-04 16:12 UTC (permalink / raw)
  To: linux-mmc, Ulf Hansson, Adrian Hunter
  Cc: Linus Walleij, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

Rather than only deselecting the SD card via a CMD7, before we cut power to
it at system suspend, at runtime suspend or at shutdown, let's add support
for a graceful power off sequence via enabling the SD Power Off
Notification feature.

Note that, the Power Off Notification feature was added in the SD spec
v4.x, which is several years ago. However, it's still a bit unclear how
often the SD card vendors decides to implement support for it. To validate
these changes a Sandisk Extreme PRO A2 64GB has been used, which seems to
work nicely.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/core/sd.c  | 136 ++++++++++++++++++++++++++++++++++++++++-
 include/linux/mmc/sd.h |   1 +
 2 files changed, 134 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 702d7c1a0aec..760aa86bd54d 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -66,6 +66,13 @@ static const unsigned int sd_au_size[] = {
 		__res & __mask;						\
 	})
 
+#define SD_POWEROFF_NOTIFY_TIMEOUT_MS 2000
+
+struct sd_busy_data {
+	struct mmc_card *card;
+	u8 *reg_buf;
+};
+
 /*
  * Given the decoded CSD structure, decode the raw CID to our CID structure.
  */
@@ -996,6 +1003,66 @@ static bool mmc_sd_card_using_v18(struct mmc_card *card)
 	       (SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR104 | SD_MODE_UHS_DDR50);
 }
 
+static int sd_write_ext_reg(struct mmc_card *card, u8 fno, u8 page, u16 offset,
+			    u8 reg_data)
+{
+	struct mmc_host *host = card->host;
+	struct mmc_request mrq = {};
+	struct mmc_command cmd = {};
+	struct mmc_data data = {};
+	struct scatterlist sg;
+	u8 *reg_buf;
+
+	reg_buf = kzalloc(512, GFP_KERNEL);
+	if (!reg_buf)
+		return -ENOMEM;
+
+	mrq.cmd = &cmd;
+	mrq.data = &data;
+
+	/*
+	 * Arguments of CMD49:
+	 * [31:31] MIO (0 = memory).
+	 * [30:27] FNO (function number).
+	 * [26:26] MW - mask write mode (0 = disable).
+	 * [25:18] page number.
+	 * [17:9] offset address.
+	 * [8:0] length (0 = 1 byte).
+	 */
+	cmd.arg = fno << 27 | page << 18 | offset << 9;
+
+	/* The first byte in the buffer is the data to be written. */
+	reg_buf[0] = reg_data;
+
+	data.flags = MMC_DATA_WRITE;
+	data.blksz = 512;
+	data.blocks = 1;
+	data.sg = &sg;
+	data.sg_len = 1;
+	sg_init_one(&sg, reg_buf, 512);
+
+	cmd.opcode = SD_WRITE_EXTR_SINGLE;
+	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+	mmc_set_data_timeout(&data, card);
+	mmc_wait_for_req(host, &mrq);
+
+	kfree(reg_buf);
+
+	/*
+	 * Note that, the SD card is allowed to signal busy on DAT0 up to 1s
+	 * after the CMD49. Although, let's leave this to be managed by the
+	 * caller.
+	 */
+
+	if (cmd.error)
+		return cmd.error;
+	if (data.error)
+		return data.error;
+
+	return 0;
+}
+
 static int sd_read_ext_reg(struct mmc_card *card, u8 fno, u8 page,
 			   u16 offset, u16 len, u8 *reg_buf)
 {
@@ -1446,21 +1513,84 @@ static void mmc_sd_detect(struct mmc_host *host)
 	}
 }
 
+static int sd_can_poweroff_notify(struct mmc_card *card)
+{
+	return card->ext_power.feature_support & SD_EXT_POWER_OFF_NOTIFY;
+}
+
+static int sd_busy_poweroff_notify_cb(void *cb_data, bool *busy)
+{
+	struct sd_busy_data *data = cb_data;
+	struct mmc_card *card = data->card;
+	int err;
+
+	/*
+	 * Read the status register for the power management function. It's at
+	 * one byte offset and is one byte long. The Power Off Notification
+	 * Ready is bit 0.
+	 */
+	err = sd_read_ext_reg(card, card->ext_power.fno, card->ext_power.page,
+			      card->ext_power.offset + 1, 1, data->reg_buf);
+	if (err) {
+		pr_warn("%s: error %d reading status reg of PM func\n",
+			mmc_hostname(card->host), err);
+		return err;
+	}
+
+	*busy = !(data->reg_buf[0] & 0x1);
+	return 0;
+}
+
+static int sd_poweroff_notify(struct mmc_card *card)
+{
+	struct sd_busy_data cb_data;
+	u8 *reg_buf;
+	int err;
+
+	reg_buf = kzalloc(512, GFP_KERNEL);
+	if (!reg_buf)
+		return -ENOMEM;
+
+	/*
+	 * Set the Power Off Notification bit in the power management settings
+	 * register at 2 bytes offset.
+	 */
+	err = sd_write_ext_reg(card, card->ext_power.fno, card->ext_power.page,
+			       card->ext_power.offset + 2, 0x1);
+	if (err) {
+		pr_warn("%s: error %d writing Power Off Notify bit\n",
+			mmc_hostname(card->host), err);
+		goto out;
+	}
+
+	cb_data.card = card;
+	cb_data.reg_buf = reg_buf;
+	err = __mmc_poll_for_busy(card, SD_POWEROFF_NOTIFY_TIMEOUT_MS,
+				  &sd_busy_poweroff_notify_cb, &cb_data);
+
+out:
+	kfree(reg_buf);
+	return err;
+}
+
 static int _mmc_sd_suspend(struct mmc_host *host)
 {
+	struct mmc_card *card = host->card;
 	int err = 0;
 
 	mmc_claim_host(host);
 
-	if (mmc_card_suspended(host->card))
+	if (mmc_card_suspended(card))
 		goto out;
 
-	if (!mmc_host_is_spi(host))
+	if (sd_can_poweroff_notify(card))
+		err = sd_poweroff_notify(card);
+	else if (!mmc_host_is_spi(host))
 		err = mmc_deselect_cards(host);
 
 	if (!err) {
 		mmc_power_off(host);
-		mmc_card_set_suspended(host->card);
+		mmc_card_set_suspended(card);
 	}
 
 out:
diff --git a/include/linux/mmc/sd.h b/include/linux/mmc/sd.h
index 43bfc5c39ad4..6727576a8755 100644
--- a/include/linux/mmc/sd.h
+++ b/include/linux/mmc/sd.h
@@ -31,6 +31,7 @@
 
   /* class 11 */
 #define SD_READ_EXTR_SINGLE      48   /* adtc [31:0]             R1  */
+#define SD_WRITE_EXTR_SINGLE     49   /* adtc [31:0]             R1  */
 
 /* OCR bit definitions */
 #define SD_OCR_S18R		(1 << 24)    /* 1.8V switching request */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH 01/11] mmc: core: Drop open coding when preparing commands with busy signaling
  2021-05-04 16:12 ` [PATCH 01/11] mmc: core: Drop open coding when preparing commands with busy signaling Ulf Hansson
@ 2021-05-06 12:50   ` Linus Walleij
  2021-05-07  1:42   ` Shawn Lin
  1 sibling, 0 replies; 40+ messages in thread
From: Linus Walleij @ 2021-05-06 12:50 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Adrian Hunter, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

On Tue, May 4, 2021 at 6:12 PM Ulf Hansson <ulf.hansson@linaro.org> wrote:

> Similar code for validating the host->max_busy_timeout towards the current
> command's busy timeout, exists in mmc_do_erase(), mmc_sleep() and
> __mmc_switch(). Let's move the common code into a helper function.
>
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

This is a really nice refactoring in its own right.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 02/11] mmc: core: Take into account MMC_CAP_NEED_RSP_BUSY for eMMC HPI commands
  2021-05-04 16:12 ` [PATCH 02/11] mmc: core: Take into account MMC_CAP_NEED_RSP_BUSY for eMMC HPI commands Ulf Hansson
@ 2021-05-06 12:51   ` Linus Walleij
  2021-05-07  1:44   ` Shawn Lin
  1 sibling, 0 replies; 40+ messages in thread
From: Linus Walleij @ 2021-05-06 12:51 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Adrian Hunter, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

On Tue, May 4, 2021 at 6:12 PM Ulf Hansson <ulf.hansson@linaro.org> wrote:

> In mmc_send_hpi_cmd() the host->max_busy_timeout is being validated towards
> the timeout for the eMMC HPI command, as to decide whether an R1 or R1B
> response should be used.
>
> Although, it has turned out the some host can't cope with that conversion,
> but needs R1B, which means MMC_CAP_NEED_RSP_BUSY is set for them. Let's
> take this into account, via using the common mmc_prepare_busy_cmd() when
> doing the validation, which also avoids some open coding.
>
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 03/11] mmc: core: Re-structure some code in __mmc_poll_for_busy()
  2021-05-04 16:12 ` [PATCH 03/11] mmc: core: Re-structure some code in __mmc_poll_for_busy() Ulf Hansson
@ 2021-05-06 12:52   ` Linus Walleij
  2021-05-07  1:48   ` Shawn Lin
  1 sibling, 0 replies; 40+ messages in thread
From: Linus Walleij @ 2021-05-06 12:52 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Adrian Hunter, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

On Tue, May 4, 2021 at 6:12 PM Ulf Hansson <ulf.hansson@linaro.org> wrote:

> To make the code a bit more understandable, let's move the check about
> whether polling is allowed or not, out to the caller instead. In this way,
> we can also drop the send_status in-parameter, so let's do that.
>
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 04/11] mmc: core: Extend re-use of __mmc_poll_for_busy()
  2021-05-04 16:12 ` [PATCH 04/11] mmc: core: Extend re-use of __mmc_poll_for_busy() Ulf Hansson
@ 2021-05-06 12:53   ` Linus Walleij
  2021-05-07  1:51   ` Shawn Lin
  1 sibling, 0 replies; 40+ messages in thread
From: Linus Walleij @ 2021-05-06 12:53 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Adrian Hunter, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

On Tue, May 4, 2021 at 6:12 PM Ulf Hansson <ulf.hansson@linaro.org> wrote:

> Via __mmc_poll_for_busy() we end up polling with the ->card_busy() host ops
> or by sending the CMD13. To allow polling of different types, which is
> needed to support a few new SD card features, let's rework the code around
> __mmc_poll_for_busy() to make it more generic.
>
> More precisely, let __mmc_poll_for_busy() take a pointer to a callback
> function as in-parameter, which it calls to poll for busy state completion.
> Additionally, let's share __mmc_poll_for_busy() to allow it to be re-used
> outside of mmc_ops.c. Subsequent changes will make use of it.
>
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 05/11] mmc: core: Enable eMMC sleep commands to use HW busy polling
  2021-05-04 16:12 ` [PATCH 05/11] mmc: core: Enable eMMC sleep commands to use HW busy polling Ulf Hansson
@ 2021-05-06 12:55   ` Linus Walleij
  2021-05-07  1:52   ` Shawn Lin
  1 sibling, 0 replies; 40+ messages in thread
From: Linus Walleij @ 2021-05-06 12:55 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Adrian Hunter, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

On Tue, May 4, 2021 at 6:12 PM Ulf Hansson <ulf.hansson@linaro.org> wrote:

> After the eMMC sleep command (CMD5) has been sent, the card start signals
> busy on the DAT0 line, which can be monitored to understand when it's
> allowed to proceed to power off the VCC regulator.
>
> When MMC_CAP_WAIT_WHILE_BUSY isn't supported by the host the DAT0 line
> isn't being monitored for busy completion, but instead we are waiting a
> fixed period of time. The time corresponds to the sleep timeout that is
> specified in the EXT_CSD register of the eMMC card. This is many cases
> suboptimal, as the timeout corresponds to the worst case scenario.
>
> To improve the situation add support for HW busy polling through the
> ->card_busy() host ops, when the host supports this.
>
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 06/11] mmc: core: Prepare mmc_send_cxd_data() to be re-used for additional cmds
  2021-05-04 16:12 ` [PATCH 06/11] mmc: core: Prepare mmc_send_cxd_data() to be re-used for additional cmds Ulf Hansson
@ 2021-05-06 12:56   ` Linus Walleij
  2021-05-06 13:00   ` Linus Walleij
  2021-05-07  1:53   ` Shawn Lin
  2 siblings, 0 replies; 40+ messages in thread
From: Linus Walleij @ 2021-05-06 12:56 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Adrian Hunter, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

On Tue, May 4, 2021 at 6:12 PM Ulf Hansson <ulf.hansson@linaro.org> wrote:

> The function mmc_send_cxd_data() sends a data read command of ADTC type and
> prepares to receive an R1 response. To make it even more re-usable, let's
> extend it with another in-parameter for the command argument. While at it,
> let's also rename the function to mmc_send_adtc_data() as it better
> describes its purpose.
>
> Note that, this change doesn't add any new users of the function. Instead
> that is done from subsequent changes.
>
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 07/11] mmc: core: Drop open coding in mmc_sd_switch()
  2021-05-04 16:12 ` [PATCH 07/11] mmc: core: Drop open coding in mmc_sd_switch() Ulf Hansson
@ 2021-05-06 12:57   ` Linus Walleij
  2021-05-07  1:54   ` Shawn Lin
  1 sibling, 0 replies; 40+ messages in thread
From: Linus Walleij @ 2021-05-06 12:57 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Adrian Hunter, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

On Tue, May 4, 2021 at 6:12 PM Ulf Hansson <ulf.hansson@linaro.org> wrote:

> The SD_SWITCH (CMD6) is an ADTC type of command with an R1 response, which
> can be sent by using the mmc_send_adtc_data(). Let's do that and drop the
> open coding in mmc_sd_switch().
>
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 06/11] mmc: core: Prepare mmc_send_cxd_data() to be re-used for additional cmds
  2021-05-04 16:12 ` [PATCH 06/11] mmc: core: Prepare mmc_send_cxd_data() to be re-used for additional cmds Ulf Hansson
  2021-05-06 12:56   ` Linus Walleij
@ 2021-05-06 13:00   ` Linus Walleij
  2021-05-07  7:30     ` Ulf Hansson
  2021-05-07  1:53   ` Shawn Lin
  2 siblings, 1 reply; 40+ messages in thread
From: Linus Walleij @ 2021-05-06 13:00 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Adrian Hunter, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

On Tue, May 4, 2021 at 6:12 PM Ulf Hansson <ulf.hansson@linaro.org> wrote:

>   * NOTE: void *buf, caller for the buf is required to use DMA-capable
>   * buffer or on-stack buffer (with some overhead in callee).
>   */
> -static int
> -mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
> -               u32 opcode, void *buf, unsigned len)
> +int mmc_send_adtc_data(struct mmc_card *card, struct mmc_host *host, u32 opcode,
> +                      u32 args, void *buf, unsigned len)

Just a note here (the change is good)

When applying please add some kerneldoc above mmc_send_adtc_data()
and expand the ADTC acronym and add some info explaining what it
is maybe a small protocol ref or so, so readers of the code get an
intuitive feeling for what this function does and what ADTC is.

Yours,
Linus Walleijq

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 08/11] mmc: core: Parse the SD SCR register for support of CMD48/49 and CMD58/59
  2021-05-04 16:12 ` [PATCH 08/11] mmc: core: Parse the SD SCR register for support of CMD48/49 and CMD58/59 Ulf Hansson
@ 2021-05-06 13:01   ` Linus Walleij
  2021-05-07  1:58   ` Shawn Lin
  1 sibling, 0 replies; 40+ messages in thread
From: Linus Walleij @ 2021-05-06 13:01 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Adrian Hunter, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

On Tue, May 4, 2021 at 6:12 PM Ulf Hansson <ulf.hansson@linaro.org> wrote:

> In SD spec v4.x the support for CMD48/49 and CMD58/59 were introduced as
> optional features. To let the card announce whether it supports the
> commands, the SCR register has been extended with corresponding support
> bits. Let's parse and store this information for later use.
>
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 09/11] mmc: core: Read the SD function extension registers for power management
  2021-05-04 16:12 ` [PATCH 09/11] mmc: core: Read the SD function extension registers for power management Ulf Hansson
@ 2021-05-06 13:04   ` Linus Walleij
  2021-05-07  2:06   ` Shawn Lin
  1 sibling, 0 replies; 40+ messages in thread
From: Linus Walleij @ 2021-05-06 13:04 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Adrian Hunter, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

On Tue, May 4, 2021 at 6:12 PM Ulf Hansson <ulf.hansson@linaro.org> wrote:

> In SD spec v4.x the SD function extension registers were introduced. A
> specific function register were added to let the card announce support for
> optional features in regards to power management. The features that were
> added are "Power Off Notification", "Power Down Mode" and "Power
> Sustenance".
>
> As a first step, let's read and parse this register for power management
> during the SD card initialization and store the information about the
> supported features in the struct mmc_card. In this way, we prepare for
> subsequent changes to implement the complete support for the new features.
>
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

Looks to me like it will work just fine.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 10/11] mmc: core: Read performance enhancements registers for SD cards
  2021-05-04 16:12 ` [PATCH 10/11] mmc: core: Read performance enhancements registers for SD cards Ulf Hansson
@ 2021-05-06 13:05   ` Linus Walleij
  0 siblings, 0 replies; 40+ messages in thread
From: Linus Walleij @ 2021-05-06 13:05 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Adrian Hunter, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

On Tue, May 4, 2021 at 6:12 PM Ulf Hansson <ulf.hansson@linaro.org> wrote:

> In SD spec v6.x the SD function extension registers for performance
> enhancements were introduced. These registers let the SD card announce
> supports for various performance related features, like "self-maintenance",
> "cache" and "command queuing".
>
> Let's extend the parsing of SD function extension registers and store the
> information in the struct mmc_card. This prepares for subsequent changes to
> implement the complete support for new the performance enhancement
> features.
>
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 11/11] mmc: core: Add support for Power Off Notification for SD cards
  2021-05-04 16:12 ` [PATCH 11/11] mmc: core: Add support for Power Off Notification " Ulf Hansson
@ 2021-05-06 13:07   ` Linus Walleij
  0 siblings, 0 replies; 40+ messages in thread
From: Linus Walleij @ 2021-05-06 13:07 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, Adrian Hunter, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

On Tue, May 4, 2021 at 6:12 PM Ulf Hansson <ulf.hansson@linaro.org> wrote:

> Rather than only deselecting the SD card via a CMD7, before we cut power to
> it at system suspend, at runtime suspend or at shutdown, let's add support
> for a graceful power off sequence via enabling the SD Power Off
> Notification feature.
>
> Note that, the Power Off Notification feature was added in the SD spec
> v4.x, which is several years ago. However, it's still a bit unclear how
> often the SD card vendors decides to implement support for it. To validate
> these changes a Sandisk Extreme PRO A2 64GB has been used, which seems to
> work nicely.
>
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

Given how these things work in some quarters I would not be
surprised if some SD card vendors tend to start to implement
this when they see that Linux (Android) has started to support
it. So let's encourage them:
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 01/11] mmc: core: Drop open coding when preparing commands with busy signaling
  2021-05-04 16:12 ` [PATCH 01/11] mmc: core: Drop open coding when preparing commands with busy signaling Ulf Hansson
  2021-05-06 12:50   ` Linus Walleij
@ 2021-05-07  1:42   ` Shawn Lin
  1 sibling, 0 replies; 40+ messages in thread
From: Shawn Lin @ 2021-05-07  1:42 UTC (permalink / raw)
  To: Ulf Hansson, linux-mmc, Adrian Hunter
  Cc: shawn.lin, Linus Walleij, Wolfram Sang, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

On 2021/5/5 0:12, Ulf Hansson wrote:
> Similar code for validating the host->max_busy_timeout towards the current
> command's busy timeout, exists in mmc_do_erase(), mmc_sleep() and
> __mmc_switch(). Let's move the common code into a helper function.

Looks nice.

Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>

> 
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> ---
>   drivers/mmc/core/core.c    | 20 ++----------------
>   drivers/mmc/core/mmc.c     | 20 +++---------------
>   drivers/mmc/core/mmc_ops.c | 42 +++++++++++++++++++++-----------------
>   drivers/mmc/core/mmc_ops.h |  3 +++
>   4 files changed, 31 insertions(+), 54 deletions(-)
> 
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index f194940c5974..b00c84ea8441 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -1582,7 +1582,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
>   {
>   	struct mmc_command cmd = {};
>   	unsigned int qty = 0, busy_timeout = 0;
> -	bool use_r1b_resp = false;
> +	bool use_r1b_resp;
>   	int err;
>   
>   	mmc_retune_hold(card->host);
> @@ -1650,23 +1650,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
>   	cmd.opcode = MMC_ERASE;
>   	cmd.arg = arg;
>   	busy_timeout = mmc_erase_timeout(card, arg, qty);
> -	/*
> -	 * If the host controller supports busy signalling and the timeout for
> -	 * the erase operation does not exceed the max_busy_timeout, we should
> -	 * use R1B response. Or we need to prevent the host from doing hw busy
> -	 * detection, which is done by converting to a R1 response instead.
> -	 * Note, some hosts requires R1B, which also means they are on their own
> -	 * when it comes to deal with the busy timeout.
> -	 */
> -	if (!(card->host->caps & MMC_CAP_NEED_RSP_BUSY) &&
> -	    card->host->max_busy_timeout &&
> -	    busy_timeout > card->host->max_busy_timeout) {
> -		cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
> -	} else {
> -		cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
> -		cmd.busy_timeout = busy_timeout;
> -		use_r1b_resp = true;
> -	}
> +	use_r1b_resp = mmc_prepare_busy_cmd(card->host, &cmd, busy_timeout);
>   
>   	err = mmc_wait_for_cmd(card->host, &cmd, 0);
>   	if (err) {
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index 8674c3e0c02c..63a7bd0b239c 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -1910,6 +1910,7 @@ static int mmc_sleep(struct mmc_host *host)
>   	struct mmc_command cmd = {};
>   	struct mmc_card *card = host->card;
>   	unsigned int timeout_ms = DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000);
> +	bool use_r1b_resp;
>   	int err;
>   
>   	/* Re-tuning can't be done once the card is deselected */
> @@ -1922,22 +1923,7 @@ static int mmc_sleep(struct mmc_host *host)
>   	cmd.opcode = MMC_SLEEP_AWAKE;
>   	cmd.arg = card->rca << 16;
>   	cmd.arg |= 1 << 15;
> -
> -	/*
> -	 * If the max_busy_timeout of the host is specified, validate it against
> -	 * the sleep cmd timeout. A failure means we need to prevent the host
> -	 * from doing hw busy detection, which is done by converting to a R1
> -	 * response instead of a R1B. Note, some hosts requires R1B, which also
> -	 * means they are on their own when it comes to deal with the busy
> -	 * timeout.
> -	 */
> -	if (!(host->caps & MMC_CAP_NEED_RSP_BUSY) && host->max_busy_timeout &&
> -	    (timeout_ms > host->max_busy_timeout)) {
> -		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
> -	} else {
> -		cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
> -		cmd.busy_timeout = timeout_ms;
> -	}
> +	use_r1b_resp = mmc_prepare_busy_cmd(host, &cmd, timeout_ms);
>   
>   	err = mmc_wait_for_cmd(host, &cmd, 0);
>   	if (err)
> @@ -1949,7 +1935,7 @@ static int mmc_sleep(struct mmc_host *host)
>   	 * SEND_STATUS command to poll the status because that command (and most
>   	 * others) is invalid while the card sleeps.
>   	 */
> -	if (!cmd.busy_timeout || !(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
> +	if (!use_r1b_resp || !(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
>   		mmc_delay(timeout_ms);
>   
>   out_release:
> diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
> index 5756781fef37..025a4134d5c7 100644
> --- a/drivers/mmc/core/mmc_ops.c
> +++ b/drivers/mmc/core/mmc_ops.c
> @@ -521,6 +521,27 @@ int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
>   	return __mmc_poll_for_busy(card, timeout_ms, true, false, busy_cmd);
>   }
>   
> +bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd,
> +			  unsigned int timeout_ms)
> +{
> +	/*
> +	 * If the max_busy_timeout of the host is specified, make sure it's
> +	 * enough to fit the used timeout_ms. In case it's not, let's instruct
> +	 * the host to avoid HW busy detection, by converting to a R1 response
> +	 * instead of a R1B. Note, some hosts requires R1B, which also means
> +	 * they are on their own when it comes to deal with the busy timeout.
> +	 */
> +	if (!(host->caps & MMC_CAP_NEED_RSP_BUSY) && host->max_busy_timeout &&
> +	    (timeout_ms > host->max_busy_timeout)) {
> +		cmd->flags = MMC_CMD_AC | MMC_RSP_SPI_R1 | MMC_RSP_R1;
> +		return false;
> +	}
> +
> +	cmd->flags = MMC_CMD_AC | MMC_RSP_SPI_R1B | MMC_RSP_R1B;
> +	cmd->busy_timeout = timeout_ms;
> +	return true;
> +}
> +
>   /**
>    *	__mmc_switch - modify EXT_CSD register
>    *	@card: the MMC card associated with the data transfer
> @@ -543,7 +564,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
>   	struct mmc_host *host = card->host;
>   	int err;
>   	struct mmc_command cmd = {};
> -	bool use_r1b_resp = true;
> +	bool use_r1b_resp;
>   	unsigned char old_timing = host->ios.timing;
>   
>   	mmc_retune_hold(host);
> @@ -554,29 +575,12 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
>   		timeout_ms = card->ext_csd.generic_cmd6_time;
>   	}
>   
> -	/*
> -	 * If the max_busy_timeout of the host is specified, make sure it's
> -	 * enough to fit the used timeout_ms. In case it's not, let's instruct
> -	 * the host to avoid HW busy detection, by converting to a R1 response
> -	 * instead of a R1B. Note, some hosts requires R1B, which also means
> -	 * they are on their own when it comes to deal with the busy timeout.
> -	 */
> -	if (!(host->caps & MMC_CAP_NEED_RSP_BUSY) && host->max_busy_timeout &&
> -	    (timeout_ms > host->max_busy_timeout))
> -		use_r1b_resp = false;
> -
>   	cmd.opcode = MMC_SWITCH;
>   	cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
>   		  (index << 16) |
>   		  (value << 8) |
>   		  set;
> -	cmd.flags = MMC_CMD_AC;
> -	if (use_r1b_resp) {
> -		cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
> -		cmd.busy_timeout = timeout_ms;
> -	} else {
> -		cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;
> -	}
> +	use_r1b_resp = mmc_prepare_busy_cmd(host, &cmd, timeout_ms);
>   
>   	err = mmc_wait_for_cmd(host, &cmd, retries);
>   	if (err)
> diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
> index 7bc1cfb0654c..ba898c435658 100644
> --- a/drivers/mmc/core/mmc_ops.h
> +++ b/drivers/mmc/core/mmc_ops.h
> @@ -18,6 +18,7 @@ enum mmc_busy_cmd {
>   
>   struct mmc_host;
>   struct mmc_card;
> +struct mmc_command;
>   
>   int mmc_select_card(struct mmc_card *card);
>   int mmc_deselect_cards(struct mmc_host *host);
> @@ -35,6 +36,8 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width);
>   int mmc_can_ext_csd(struct mmc_card *card);
>   int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
>   int mmc_switch_status(struct mmc_card *card, bool crc_err_fatal);
> +bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd,
> +			  unsigned int timeout_ms);
>   int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
>   		      enum mmc_busy_cmd busy_cmd);
>   int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
> 



^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 02/11] mmc: core: Take into account MMC_CAP_NEED_RSP_BUSY for eMMC HPI commands
  2021-05-04 16:12 ` [PATCH 02/11] mmc: core: Take into account MMC_CAP_NEED_RSP_BUSY for eMMC HPI commands Ulf Hansson
  2021-05-06 12:51   ` Linus Walleij
@ 2021-05-07  1:44   ` Shawn Lin
  1 sibling, 0 replies; 40+ messages in thread
From: Shawn Lin @ 2021-05-07  1:44 UTC (permalink / raw)
  To: Ulf Hansson, linux-mmc, Adrian Hunter
  Cc: shawn.lin, Linus Walleij, Wolfram Sang, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

On 2021/5/5 0:12, Ulf Hansson wrote:
> In mmc_send_hpi_cmd() the host->max_busy_timeout is being validated towards
> the timeout for the eMMC HPI command, as to decide whether an R1 or R1B
> response should be used.
> 
> Although, it has turned out the some host can't cope with that conversion,
> but needs R1B, which means MMC_CAP_NEED_RSP_BUSY is set for them. Let's
> take this into account, via using the common mmc_prepare_busy_cmd() when
> doing the validation, which also avoids some open coding.

Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>

> 
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> ---
>   drivers/mmc/core/mmc_ops.c | 21 +++++----------------
>   1 file changed, 5 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
> index 025a4134d5c7..66ae699a410f 100644
> --- a/drivers/mmc/core/mmc_ops.c
> +++ b/drivers/mmc/core/mmc_ops.c
> @@ -817,28 +817,17 @@ 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;
> +	bool use_r1b_resp = false;
>   	struct mmc_command cmd = {};
>   	int err;
>   
>   	cmd.opcode = card->ext_csd.hpi_cmd;
>   	cmd.arg = card->rca << 16 | 1;
> +	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
>   
> -	/*
> -	 * 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;
> -		cmd.busy_timeout = busy_timeout_ms;
> -	} else {
> -		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
> -		use_r1b_resp = false;
> -	}
> +	if (cmd.opcode == MMC_STOP_TRANSMISSION)
> +		use_r1b_resp = mmc_prepare_busy_cmd(host, &cmd,
> +						    busy_timeout_ms);
>   
>   	err = mmc_wait_for_cmd(host, &cmd, 0);
>   	if (err) {
> 



^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 03/11] mmc: core: Re-structure some code in __mmc_poll_for_busy()
  2021-05-04 16:12 ` [PATCH 03/11] mmc: core: Re-structure some code in __mmc_poll_for_busy() Ulf Hansson
  2021-05-06 12:52   ` Linus Walleij
@ 2021-05-07  1:48   ` Shawn Lin
  1 sibling, 0 replies; 40+ messages in thread
From: Shawn Lin @ 2021-05-07  1:48 UTC (permalink / raw)
  To: Ulf Hansson, linux-mmc, Adrian Hunter
  Cc: shawn.lin, Linus Walleij, Wolfram Sang, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

On 2021/5/5 0:12, Ulf Hansson wrote:
> To make the code a bit more understandable, let's move the check about
> whether polling is allowed or not, out to the caller instead. In this way,
> we can also drop the send_status in-parameter, so let's do that.

Everytime I check the parameters for busy polling, I have to look very
closely to make sure what the true or false stands for. So reducing the
parameters here make sense.

Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>

> 
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> ---
>   drivers/mmc/core/mmc_ops.c | 27 +++++++++++++--------------
>   1 file changed, 13 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
> index 66ae699a410f..ccaee1cb7ff5 100644
> --- a/drivers/mmc/core/mmc_ops.c
> +++ b/drivers/mmc/core/mmc_ops.c
> @@ -465,8 +465,7 @@ static int mmc_busy_status(struct mmc_card *card, bool retry_crc_err,
>   }
>   
>   static int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
> -			       bool send_status, bool retry_crc_err,
> -			       enum mmc_busy_cmd busy_cmd)
> +			       bool retry_crc_err, enum mmc_busy_cmd busy_cmd)
>   {
>   	struct mmc_host *host = card->host;
>   	int err;
> @@ -475,16 +474,6 @@ static int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
>   	bool expired = false;
>   	bool busy = false;
>   
> -	/*
> -	 * In cases when not allowed to poll by using CMD13 or because we aren't
> -	 * capable of polling by using ->card_busy(), then rely on waiting the
> -	 * stated timeout to be sufficient.
> -	 */
> -	if (!send_status && !host->ops->card_busy) {
> -		mmc_delay(timeout_ms);
> -		return 0;
> -	}
> -
>   	timeout = jiffies + msecs_to_jiffies(timeout_ms) + 1;
>   	do {
>   		/*
> @@ -518,7 +507,7 @@ static int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
>   int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
>   		      enum mmc_busy_cmd busy_cmd)
>   {
> -	return __mmc_poll_for_busy(card, timeout_ms, true, false, busy_cmd);
> +	return __mmc_poll_for_busy(card, timeout_ms, false, busy_cmd);
>   }
>   
>   bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd,
> @@ -591,8 +580,18 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
>   		mmc_host_is_spi(host))
>   		goto out_tim;
>   
> +	/*
> +	 * If the host doesn't support HW polling via the ->card_busy() ops and
> +	 * when it's not allowed to poll by using CMD13, then we need to rely on
> +	 * waiting the stated timeout to be sufficient.
> +	 */
> +	if (!send_status && !host->ops->card_busy) {
> +		mmc_delay(timeout_ms);
> +		goto out_tim;
> +	}
> +
>   	/* Let's try to poll to find out when the command is completed. */
> -	err = __mmc_poll_for_busy(card, timeout_ms, send_status, retry_crc_err,
> +	err = __mmc_poll_for_busy(card, timeout_ms, retry_crc_err,
>   				  MMC_BUSY_CMD6);
>   	if (err)
>   		goto out;
> 



^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 04/11] mmc: core: Extend re-use of __mmc_poll_for_busy()
  2021-05-04 16:12 ` [PATCH 04/11] mmc: core: Extend re-use of __mmc_poll_for_busy() Ulf Hansson
  2021-05-06 12:53   ` Linus Walleij
@ 2021-05-07  1:51   ` Shawn Lin
  1 sibling, 0 replies; 40+ messages in thread
From: Shawn Lin @ 2021-05-07  1:51 UTC (permalink / raw)
  To: Ulf Hansson, linux-mmc, Adrian Hunter
  Cc: shawn.lin, Linus Walleij, Wolfram Sang, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

On 2021/5/5 0:12, Ulf Hansson wrote:
> Via __mmc_poll_for_busy() we end up polling with the ->card_busy() host ops
> or by sending the CMD13. To allow polling of different types, which is
> needed to support a few new SD card features, let's rework the code around
> __mmc_poll_for_busy() to make it more generic.
> 
> More precisely, let __mmc_poll_for_busy() take a pointer to a callback
> function as in-parameter, which it calls to poll for busy state completion.
> Additionally, let's share __mmc_poll_for_busy() to allow it to be re-used
> outside of mmc_ops.c. Subsequent changes will make use of it.
> 

Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>

> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> ---
>   drivers/mmc/core/core.c    |  2 +-
>   drivers/mmc/core/mmc_ops.c | 42 ++++++++++++++++++++++++--------------
>   drivers/mmc/core/mmc_ops.h |  5 ++++-
>   3 files changed, 32 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index b00c84ea8441..b039dcff17f8 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -1671,7 +1671,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
>   		goto out;
>   
>   	/* Let's poll to find out when the erase operation completes. */
> -	err = mmc_poll_for_busy(card, busy_timeout, MMC_BUSY_ERASE);
> +	err = mmc_poll_for_busy(card, busy_timeout, false, MMC_BUSY_ERASE);
>   
>   out:
>   	mmc_retune_release(card->host);
> diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
> index ccaee1cb7ff5..653627fe02a3 100644
> --- a/drivers/mmc/core/mmc_ops.c
> +++ b/drivers/mmc/core/mmc_ops.c
> @@ -53,6 +53,12 @@ static const u8 tuning_blk_pattern_8bit[] = {
>   	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
>   };
>   
> +struct mmc_busy_data {
> +	struct mmc_card *card;
> +	bool retry_crc_err;
> +	enum mmc_busy_cmd busy_cmd;
> +};
> +
>   int __mmc_send_status(struct mmc_card *card, u32 *status, unsigned int retries)
>   {
>   	int err;
> @@ -424,10 +430,10 @@ int mmc_switch_status(struct mmc_card *card, bool crc_err_fatal)
>   	return mmc_switch_status_error(card->host, status);
>   }
>   
> -static int mmc_busy_status(struct mmc_card *card, bool retry_crc_err,
> -			   enum mmc_busy_cmd busy_cmd, bool *busy)
> +static int mmc_busy_cb(void *cb_data, bool *busy)
>   {
> -	struct mmc_host *host = card->host;
> +	struct mmc_busy_data *data = cb_data;
> +	struct mmc_host *host = data->card->host;
>   	u32 status = 0;
>   	int err;
>   
> @@ -436,17 +442,17 @@ static int mmc_busy_status(struct mmc_card *card, bool retry_crc_err,
>   		return 0;
>   	}
>   
> -	err = mmc_send_status(card, &status);
> -	if (retry_crc_err && err == -EILSEQ) {
> +	err = mmc_send_status(data->card, &status);
> +	if (data->retry_crc_err && err == -EILSEQ) {
>   		*busy = true;
>   		return 0;
>   	}
>   	if (err)
>   		return err;
>   
> -	switch (busy_cmd) {
> +	switch (data->busy_cmd) {
>   	case MMC_BUSY_CMD6:
> -		err = mmc_switch_status_error(card->host, status);
> +		err = mmc_switch_status_error(host, status);
>   		break;
>   	case MMC_BUSY_ERASE:
>   		err = R1_STATUS(status) ? -EIO : 0;
> @@ -464,8 +470,9 @@ static int mmc_busy_status(struct mmc_card *card, bool retry_crc_err,
>   	return 0;
>   }
>   
> -static int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
> -			       bool retry_crc_err, enum mmc_busy_cmd busy_cmd)
> +int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
> +			int (*busy_cb)(void *cb_data, bool *busy),
> +			void *cb_data)
>   {
>   	struct mmc_host *host = card->host;
>   	int err;
> @@ -482,7 +489,7 @@ static int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
>   		 */
>   		expired = time_after(jiffies, timeout);
>   
> -		err = mmc_busy_status(card, retry_crc_err, busy_cmd, &busy);
> +		err = (*busy_cb)(cb_data, &busy);
>   		if (err)
>   			return err;
>   
> @@ -505,9 +512,15 @@ static int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
>   }
>   
>   int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
> -		      enum mmc_busy_cmd busy_cmd)
> +		      bool retry_crc_err, enum mmc_busy_cmd busy_cmd)
>   {
> -	return __mmc_poll_for_busy(card, timeout_ms, false, busy_cmd);
> +	struct mmc_busy_data cb_data;
> +
> +	cb_data.card = card;
> +	cb_data.retry_crc_err = retry_crc_err;
> +	cb_data.busy_cmd = busy_cmd;
> +
> +	return __mmc_poll_for_busy(card, timeout_ms, &mmc_busy_cb, &cb_data);
>   }
>   
>   bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd,
> @@ -591,8 +604,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
>   	}
>   
>   	/* Let's try to poll to find out when the command is completed. */
> -	err = __mmc_poll_for_busy(card, timeout_ms, retry_crc_err,
> -				  MMC_BUSY_CMD6);
> +	err = mmc_poll_for_busy(card, timeout_ms, retry_crc_err, MMC_BUSY_CMD6);
>   	if (err)
>   		goto out;
>   
> @@ -840,7 +852,7 @@ static int mmc_send_hpi_cmd(struct mmc_card *card)
>   		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);
> +	return mmc_poll_for_busy(card, busy_timeout_ms, false, MMC_BUSY_HPI);
>   }
>   
>   /**
> diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
> index ba898c435658..aca66c128804 100644
> --- a/drivers/mmc/core/mmc_ops.h
> +++ b/drivers/mmc/core/mmc_ops.h
> @@ -38,8 +38,11 @@ int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
>   int mmc_switch_status(struct mmc_card *card, bool crc_err_fatal);
>   bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd,
>   			  unsigned int timeout_ms);
> +int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
> +			int (*busy_cb)(void *cb_data, bool *busy),
> +			void *cb_data);
>   int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
> -		      enum mmc_busy_cmd busy_cmd);
> +		      bool retry_crc_err, enum mmc_busy_cmd busy_cmd);
>   int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
>   		unsigned int timeout_ms, unsigned char timing,
>   		bool send_status, bool retry_crc_err, unsigned int retries);
> 



^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 05/11] mmc: core: Enable eMMC sleep commands to use HW busy polling
  2021-05-04 16:12 ` [PATCH 05/11] mmc: core: Enable eMMC sleep commands to use HW busy polling Ulf Hansson
  2021-05-06 12:55   ` Linus Walleij
@ 2021-05-07  1:52   ` Shawn Lin
  1 sibling, 0 replies; 40+ messages in thread
From: Shawn Lin @ 2021-05-07  1:52 UTC (permalink / raw)
  To: Ulf Hansson, linux-mmc, Adrian Hunter
  Cc: shawn.lin, Linus Walleij, Wolfram Sang, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel


On 2021/5/5 0:12, Ulf Hansson wrote:
> After the eMMC sleep command (CMD5) has been sent, the card start signals
> busy on the DAT0 line, which can be monitored to understand when it's
> allowed to proceed to power off the VCC regulator.
> 
> When MMC_CAP_WAIT_WHILE_BUSY isn't supported by the host the DAT0 line
> isn't being monitored for busy completion, but instead we are waiting a
> fixed period of time. The time corresponds to the sleep timeout that is
> specified in the EXT_CSD register of the eMMC card. This is many cases
> suboptimal, as the timeout corresponds to the worst case scenario.
> 
> To improve the situation add support for HW busy polling through the
> ->card_busy() host ops, when the host supports this.

Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>

> 
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> ---
>   drivers/mmc/core/mmc.c | 25 ++++++++++++++++++++-----
>   1 file changed, 20 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index 63a7bd0b239c..13074aa1f605 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -1905,6 +1905,14 @@ static int mmc_can_sleep(struct mmc_card *card)
>   	return card->ext_csd.rev >= 3;
>   }
>   
> +static int mmc_sleep_busy_cb(void *cb_data, bool *busy)
> +{
> +	struct mmc_host *host = cb_data;
> +
> +	*busy = host->ops->card_busy(host);
> +	return 0;
> +}
> +
>   static int mmc_sleep(struct mmc_host *host)
>   {
>   	struct mmc_command cmd = {};
> @@ -1930,13 +1938,20 @@ static int mmc_sleep(struct mmc_host *host)
>   		goto out_release;
>   
>   	/*
> -	 * If the host does not wait while the card signals busy, then we will
> -	 * will have to wait the sleep/awake timeout.  Note, we cannot use the
> -	 * SEND_STATUS command to poll the status because that command (and most
> -	 * others) is invalid while the card sleeps.
> +	 * If the host does not wait while the card signals busy, then we can
> +	 * try to poll, but only if the host supports HW polling, as the
> +	 * SEND_STATUS cmd is not allowed. If we can't poll, then we simply need
> +	 * to wait the sleep/awake timeout.
>   	 */
> -	if (!use_r1b_resp || !(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
> +	if (host->caps & MMC_CAP_WAIT_WHILE_BUSY && use_r1b_resp)
> +		goto out_release;
> +
> +	if (!host->ops->card_busy) {
>   		mmc_delay(timeout_ms);
> +		goto out_release;
> +	}
> +
> +	err = __mmc_poll_for_busy(card, timeout_ms, &mmc_sleep_busy_cb, host);
>   
>   out_release:
>   	mmc_retune_release(host);
> 



^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 06/11] mmc: core: Prepare mmc_send_cxd_data() to be re-used for additional cmds
  2021-05-04 16:12 ` [PATCH 06/11] mmc: core: Prepare mmc_send_cxd_data() to be re-used for additional cmds Ulf Hansson
  2021-05-06 12:56   ` Linus Walleij
  2021-05-06 13:00   ` Linus Walleij
@ 2021-05-07  1:53   ` Shawn Lin
  2 siblings, 0 replies; 40+ messages in thread
From: Shawn Lin @ 2021-05-07  1:53 UTC (permalink / raw)
  To: Ulf Hansson, linux-mmc, Adrian Hunter
  Cc: shawn.lin, Linus Walleij, Wolfram Sang, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

On 2021/5/5 0:12, Ulf Hansson wrote:
> The function mmc_send_cxd_data() sends a data read command of ADTC type and
> prepares to receive an R1 response. To make it even more re-usable, let's
> extend it with another in-parameter for the command argument. While at it,
> let's also rename the function to mmc_send_adtc_data() as it better
> describes its purpose.
> 
> Note that, this change doesn't add any new users of the function. Instead
> that is done from subsequent changes.

Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>

> 
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> ---
>   drivers/mmc/core/mmc_ops.c | 11 +++++------
>   drivers/mmc/core/mmc_ops.h |  2 ++
>   2 files changed, 7 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
> index 653627fe02a3..b1da8f1950ee 100644
> --- a/drivers/mmc/core/mmc_ops.c
> +++ b/drivers/mmc/core/mmc_ops.c
> @@ -252,9 +252,8 @@ mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode)
>    * NOTE: void *buf, caller for the buf is required to use DMA-capable
>    * buffer or on-stack buffer (with some overhead in callee).
>    */
> -static int
> -mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
> -		u32 opcode, void *buf, unsigned len)
> +int mmc_send_adtc_data(struct mmc_card *card, struct mmc_host *host, u32 opcode,
> +		       u32 args, void *buf, unsigned len)
>   {
>   	struct mmc_request mrq = {};
>   	struct mmc_command cmd = {};
> @@ -265,7 +264,7 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
>   	mrq.data = &data;
>   
>   	cmd.opcode = opcode;
> -	cmd.arg = 0;
> +	cmd.arg = args;
>   
>   	/* NOTE HACK:  the MMC_RSP_SPI_R1 is always correct here, but we
>   	 * rely on callers to never use this with "native" calls for reading
> @@ -311,7 +310,7 @@ static int mmc_spi_send_cxd(struct mmc_host *host, u32 *cxd, u32 opcode)
>   	if (!cxd_tmp)
>   		return -ENOMEM;
>   
> -	ret = mmc_send_cxd_data(NULL, host, opcode, cxd_tmp, 16);
> +	ret = mmc_send_adtc_data(NULL, host, opcode, 0, cxd_tmp, 16);
>   	if (ret)
>   		goto err;
>   
> @@ -359,7 +358,7 @@ int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
>   	if (!ext_csd)
>   		return -ENOMEM;
>   
> -	err = mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD, ext_csd,
> +	err = mmc_send_adtc_data(card, card->host, MMC_SEND_EXT_CSD, 0, ext_csd,
>   				512);
>   	if (err)
>   		kfree(ext_csd);
> diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
> index aca66c128804..2b1d730e56bf 100644
> --- a/drivers/mmc/core/mmc_ops.h
> +++ b/drivers/mmc/core/mmc_ops.h
> @@ -26,6 +26,8 @@ int mmc_set_dsr(struct mmc_host *host);
>   int mmc_go_idle(struct mmc_host *host);
>   int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
>   int mmc_set_relative_addr(struct mmc_card *card);
> +int mmc_send_adtc_data(struct mmc_card *card, struct mmc_host *host, u32 opcode,
> +		       u32 args, void *buf, unsigned len);
>   int mmc_send_csd(struct mmc_card *card, u32 *csd);
>   int __mmc_send_status(struct mmc_card *card, u32 *status, unsigned int retries);
>   int mmc_send_status(struct mmc_card *card, u32 *status);
> 



^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 07/11] mmc: core: Drop open coding in mmc_sd_switch()
  2021-05-04 16:12 ` [PATCH 07/11] mmc: core: Drop open coding in mmc_sd_switch() Ulf Hansson
  2021-05-06 12:57   ` Linus Walleij
@ 2021-05-07  1:54   ` Shawn Lin
  1 sibling, 0 replies; 40+ messages in thread
From: Shawn Lin @ 2021-05-07  1:54 UTC (permalink / raw)
  To: Ulf Hansson, linux-mmc, Adrian Hunter
  Cc: shawn.lin, Linus Walleij, Wolfram Sang, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

On 2021/5/5 0:12, Ulf Hansson wrote:
> The SD_SWITCH (CMD6) is an ADTC type of command with an R1 response, which
> can be sent by using the mmc_send_adtc_data(). Let's do that and drop the
> open coding in mmc_sd_switch().

Nice cleanup.

Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>

> 
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> ---
>   drivers/mmc/core/sd_ops.c | 38 +++++++-------------------------------
>   1 file changed, 7 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
> index d61ff811218c..ef8d1dce5af1 100644
> --- a/drivers/mmc/core/sd_ops.c
> +++ b/drivers/mmc/core/sd_ops.c
> @@ -17,6 +17,7 @@
>   
>   #include "core.h"
>   #include "sd_ops.h"
> +#include "mmc_ops.h"
>   
>   int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
>   {
> @@ -309,43 +310,18 @@ int mmc_app_send_scr(struct mmc_card *card)
>   int mmc_sd_switch(struct mmc_card *card, int mode, int group,
>   	u8 value, u8 *resp)
>   {
> -	struct mmc_request mrq = {};
> -	struct mmc_command cmd = {};
> -	struct mmc_data data = {};
> -	struct scatterlist sg;
> +	u32 cmd_args;
>   
>   	/* NOTE: caller guarantees resp is heap-allocated */
>   
>   	mode = !!mode;
>   	value &= 0xF;
> +	cmd_args = mode << 31 | 0x00FFFFFF;
> +	cmd_args &= ~(0xF << (group * 4));
> +	cmd_args |= value << (group * 4);
>   
> -	mrq.cmd = &cmd;
> -	mrq.data = &data;
> -
> -	cmd.opcode = SD_SWITCH;
> -	cmd.arg = mode << 31 | 0x00FFFFFF;
> -	cmd.arg &= ~(0xF << (group * 4));
> -	cmd.arg |= value << (group * 4);
> -	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
> -
> -	data.blksz = 64;
> -	data.blocks = 1;
> -	data.flags = MMC_DATA_READ;
> -	data.sg = &sg;
> -	data.sg_len = 1;
> -
> -	sg_init_one(&sg, resp, 64);
> -
> -	mmc_set_data_timeout(&data, card);
> -
> -	mmc_wait_for_req(card->host, &mrq);
> -
> -	if (cmd.error)
> -		return cmd.error;
> -	if (data.error)
> -		return data.error;
> -
> -	return 0;
> +	return mmc_send_adtc_data(card, card->host, SD_SWITCH, cmd_args, resp,
> +				  64);
>   }
>   
>   int mmc_app_sd_status(struct mmc_card *card, void *ssr)
> 



^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 08/11] mmc: core: Parse the SD SCR register for support of CMD48/49 and CMD58/59
  2021-05-04 16:12 ` [PATCH 08/11] mmc: core: Parse the SD SCR register for support of CMD48/49 and CMD58/59 Ulf Hansson
  2021-05-06 13:01   ` Linus Walleij
@ 2021-05-07  1:58   ` Shawn Lin
  1 sibling, 0 replies; 40+ messages in thread
From: Shawn Lin @ 2021-05-07  1:58 UTC (permalink / raw)
  To: Ulf Hansson, linux-mmc, Adrian Hunter
  Cc: shawn.lin, Linus Walleij, Wolfram Sang, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel


On 2021/5/5 0:12, Ulf Hansson wrote:
> In SD spec v4.x the support for CMD48/49 and CMD58/59 were introduced as
> optional features. To let the card announce whether it supports the
> commands, the SCR register has been extended with corresponding support
> bits. Let's parse and store this information for later use.
> 

Just check v4.0 spec, and it says

"Table 4-32 is added in Version 4.00. These commands are reserved for
future extenstion". So,

Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>

> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> ---
>   drivers/mmc/core/sd.c    | 4 +++-
>   include/linux/mmc/card.h | 2 ++
>   2 files changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> index 2c48d6504101..de7b5f8df550 100644
> --- a/drivers/mmc/core/sd.c
> +++ b/drivers/mmc/core/sd.c
> @@ -222,7 +222,9 @@ static int mmc_decode_scr(struct mmc_card *card)
>   	else
>   		card->erased_byte = 0x0;
>   
> -	if (scr->sda_spec3)
> +	if (scr->sda_spec4)
> +		scr->cmds = UNSTUFF_BITS(resp, 32, 4);
> +	else if (scr->sda_spec3)
>   		scr->cmds = UNSTUFF_BITS(resp, 32, 2);
>   
>   	/* SD Spec says: any SD Card shall set at least bits 0 and 2 */
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index f9ad35dd6012..858fc4d11240 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -139,6 +139,8 @@ struct sd_scr {
>   	unsigned char		cmds;
>   #define SD_SCR_CMD20_SUPPORT   (1<<0)
>   #define SD_SCR_CMD23_SUPPORT   (1<<1)
> +#define SD_SCR_CMD48_SUPPORT   (1<<2)
> +#define SD_SCR_CMD58_SUPPORT   (1<<3)
>   };
>   
>   struct sd_ssr {
> 



^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 09/11] mmc: core: Read the SD function extension registers for power management
  2021-05-04 16:12 ` [PATCH 09/11] mmc: core: Read the SD function extension registers for power management Ulf Hansson
  2021-05-06 13:04   ` Linus Walleij
@ 2021-05-07  2:06   ` Shawn Lin
  2021-05-07  7:27     ` Ulf Hansson
  1 sibling, 1 reply; 40+ messages in thread
From: Shawn Lin @ 2021-05-07  2:06 UTC (permalink / raw)
  To: Ulf Hansson, linux-mmc, Adrian Hunter
  Cc: shawn.lin, Linus Walleij, Wolfram Sang, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel


On 2021/5/5 0:12, Ulf Hansson wrote:
> In SD spec v4.x the SD function extension registers were introduced. A

I have a v4.0 spec and it doesn't state that v4.0 suppports reading
extension registers but just says TBD instead.  So I guess v4.x doesn't
include v4.0 ?

> specific function register were added to let the card announce support for
> optional features in regards to power management. The features that were
> added are "Power Off Notification", "Power Down Mode" and "Power
> Sustenance".
> 
> As a first step, let's read and parse this register for power management
> during the SD card initialization and store the information about the
> supported features in the struct mmc_card. In this way, we prepare for
> subsequent changes to implement the complete support for the new features.
> 
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> ---
>   drivers/mmc/core/sd.c    | 178 +++++++++++++++++++++++++++++++++++++++
>   include/linux/mmc/card.h |  13 +++
>   include/linux/mmc/sd.h   |   3 +
>   3 files changed, 194 insertions(+)
> 
> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> index de7b5f8df550..cb5e8b2fc32f 100644
> --- a/drivers/mmc/core/sd.c
> +++ b/drivers/mmc/core/sd.c
> @@ -996,6 +996,177 @@ static bool mmc_sd_card_using_v18(struct mmc_card *card)
>   	       (SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR104 | SD_MODE_UHS_DDR50);
>   }
>   
> +static int sd_read_ext_reg(struct mmc_card *card, u8 fno, u8 page,
> +			   u16 offset, u16 len, u8 *reg_buf)
> +{
> +	u32 cmd_args;
> +
> +	/*
> +	 * Command arguments of CMD48:
> +	 * [31:31] MIO (0 = memory).
> +	 * [30:27] FNO (function number).
> +	 * [26:26] reserved (0).
> +	 * [25:18] page number.
> +	 * [17:9] offset address.
> +	 * [8:0] length (0 = 1 byte, 1ff = 512 bytes).
> +	 */
> +	cmd_args = fno << 27 | page << 18 | offset << 9 | (len -1);
> +
> +	return mmc_send_adtc_data(card, card->host, SD_READ_EXTR_SINGLE,
> +				  cmd_args, reg_buf, 512);
> +}
> +
> +static int sd_parse_ext_reg_power(struct mmc_card *card, u8 fno, u8 page,
> +				  u16 offset)
> +{
> +	int err;
> +	u8 *reg_buf;
> +
> +	reg_buf = kzalloc(512, GFP_KERNEL);
> +	if (!reg_buf)
> +		return -ENOMEM;
> +
> +	/* Read the extension register for power management function. */
> +	err = sd_read_ext_reg(card, fno, page, offset, 512, reg_buf);
> +	if (err) {
> +		pr_warn("%s: error %d reading PM func of ext reg\n",
> +			mmc_hostname(card->host), err);
> +		goto out;
> +	}
> +
> +	/* PM revision consists of 4 bits. */
> +	card->ext_power.rev = reg_buf[0] & 0xf;
> +
> +	/* Power Off Notification support at bit 4. */
> +	if (reg_buf[1] & 0x10)
> +		card->ext_power.feature_support |= SD_EXT_POWER_OFF_NOTIFY;
> +
> +	/* Power Sustenance support at bit 5. */
> +	if (reg_buf[1] & 0x20)
> +		card->ext_power.feature_support |= SD_EXT_POWER_SUSTENANCE;
> +
> +	/* Power Down Mode support at bit 6. */
> +	if (reg_buf[1] & 0x40)
> +		card->ext_power.feature_support |= SD_EXT_POWER_DOWN_MODE;
> +
> +	card->ext_power.fno = fno;
> +	card->ext_power.page = page;
> +	card->ext_power.offset = offset;
> +
> +out:
> +	kfree(reg_buf);
> +	return err;
> +}
> +
> +static int sd_parse_ext_reg(struct mmc_card *card, u8 *gen_info_buf,
> +			    u16 *next_ext_addr)
> +{
> +	u8 num_regs, fno, page;
> +	u16 sfc, offset, ext = *next_ext_addr;
> +	u32 reg_addr;
> +
> +	/*
> +	 * Parse only one register set per extension, as that is sufficient to
> +	 * support the standard functions. This means another 48 bytes in the
> +	 * buffer must be available.
> +	 */
> +	if (ext + 48 > 512)
> +		return -EFAULT;
> +
> +	/* Standard Function Code */
> +	memcpy(&sfc, &gen_info_buf[ext], 2);
> +
> +	/* Address to the next extension. */
> +	memcpy(next_ext_addr, &gen_info_buf[ext + 40], 2);
> +
> +	/* Number of registers for this extension. */
> +	num_regs = gen_info_buf[ext + 42];
> +
> +	/* We support only one register per extension. */
> +	if (num_regs != 1)
> +		return 0;
> +
> +	/* Extension register address. */
> +	memcpy(&reg_addr, &gen_info_buf[ext + 44], 4);
> +
> +	/* 9 bits (0 to 8) contains the offset address. */
> +	offset = reg_addr & 0x1ff;
> +
> +	/* 8 bits (9 to 16) contains the page number. */
> +	page = reg_addr >> 9 & 0xff ;
> +
> +	/* 4 bits (18 to 21) contains the function number. */
> +	fno = reg_addr >> 18 & 0xf;
> +
> +	/* Standard Function Code for power management. */
> +	if (sfc == 0x1)
> +		return sd_parse_ext_reg_power(card, fno, page, offset);
> +
> +	return 0;
> +}
> +
> +static int sd_read_ext_regs(struct mmc_card *card)
> +{
> +	int err, i;
> +	u8 num_ext, *gen_info_buf;
> +	u16 rev, len, next_ext_addr;
> +
> +	if (mmc_host_is_spi(card->host))
> +		return 0;
> +
> +	if (!(card->scr.cmds & SD_SCR_CMD48_SUPPORT))
> +		return 0;
> +
> +	gen_info_buf = kzalloc(512, GFP_KERNEL);
> +	if (!gen_info_buf)
> +		return -ENOMEM;
> +
> +	/*
> +	 * Read 512 bytes of general info, which is found at function number 0,
> +	 * at page 0 and with no offset.
> +	 */
> +	err = sd_read_ext_reg(card, 0, 0, 0, 512, gen_info_buf);
> +	if (err) {
> +		pr_warn("%s: error %d reading general info of SD ext reg\n",
> +			mmc_hostname(card->host), err);
> +		goto out;
> +	}
> +
> +	/* General info structure revision. */
> +	memcpy(&rev, &gen_info_buf[0], 2);
> +
> +	/* Length of general info in bytes. */
> +	memcpy(&len, &gen_info_buf[2], 2);
> +
> +	/* Number of extensions to be find. */
> +	num_ext = gen_info_buf[4];
> +
> +	/* We support revision 0, but limit it to 512 bytes for simplicity. */
> +	if (rev != 0 || len > 512) {
> +		pr_warn("%s: non-supported SD ext reg layout\n",
> +			mmc_hostname(card->host));
> +		goto out;
> +	}
> +
> +	/*
> +	 * Parse the extension registers. The first extension should start
> +	 * immediately after the general info header (16 bytes).
> +	 */
> +	next_ext_addr = 16;
> +	for (i = 0; i < num_ext; i++) {
> +		err = sd_parse_ext_reg(card, gen_info_buf, &next_ext_addr);
> +		if (err) {
> +			pr_warn("%s: error %d parsing SD ext reg\n",
> +				mmc_hostname(card->host), err);
> +			goto out;
> +		}
> +	}
> +
> +out:
> +	kfree(gen_info_buf);
> +	return err;
> +}
> +
>   /*
>    * Handle the detection and initialisation of a card.
>    *
> @@ -1144,6 +1315,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
>   		}
>   	}
>   
> +	if (!oldcard) {
> +		/* Read/parse the extension registers. */
> +		err = sd_read_ext_regs(card);
> +		if (err)
> +			goto free_card;
> +	}
> +
>   	if (host->cqe_ops && !host->cqe_enabled) {
>   		err = host->cqe_ops->cqe_enable(host, card);
>   		if (!err) {
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index 858fc4d11240..03a862e93594 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -191,6 +191,18 @@ struct sd_switch_caps {
>   #define SD_MAX_CURRENT_800	(1 << SD_SET_CURRENT_LIMIT_800)
>   };
>   
> +struct sd_ext_reg {
> +	u8			fno;
> +	u8			page;
> +	u16			offset;
> +	u8			rev;
> +	u8			feature_support;
> +/* Power Management Function. */
> +#define SD_EXT_POWER_OFF_NOTIFY	(1<<0)
> +#define SD_EXT_POWER_SUSTENANCE	(1<<1)
> +#define SD_EXT_POWER_DOWN_MODE	(1<<2)
> +};
> +
>   struct sdio_cccr {
>   	unsigned int		sdio_vsn;
>   	unsigned int		sd_vsn;
> @@ -292,6 +304,7 @@ struct mmc_card {
>   	struct sd_scr		scr;		/* extra SD information */
>   	struct sd_ssr		ssr;		/* yet more SD information */
>   	struct sd_switch_caps	sw_caps;	/* switch (CMD6) caps */
> +	struct sd_ext_reg	ext_power;	/* SD extension reg for PM */
>   
>   	unsigned int		sdio_funcs;	/* number of SDIO functions */
>   	atomic_t		sdio_funcs_probed; /* number of probed SDIO funcs */
> diff --git a/include/linux/mmc/sd.h b/include/linux/mmc/sd.h
> index 2236aa540faa..43bfc5c39ad4 100644
> --- a/include/linux/mmc/sd.h
> +++ b/include/linux/mmc/sd.h
> @@ -29,6 +29,9 @@
>   #define SD_APP_OP_COND           41   /* bcr  [31:0] OCR         R3  */
>   #define SD_APP_SEND_SCR          51   /* adtc                    R1  */
>   
> +  /* class 11 */
> +#define SD_READ_EXTR_SINGLE      48   /* adtc [31:0]             R1  */
> +
>   /* OCR bit definitions */
>   #define SD_OCR_S18R		(1 << 24)    /* 1.8V switching request */
>   #define SD_ROCR_S18A		SD_OCR_S18R  /* 1.8V switching accepted by card */
> 



^ permalink raw reply	[flat|nested] 40+ messages in thread

* RE: [PATCH 00/11] Initital support for new power/perf features for SD cards
  2021-05-04 16:12 [PATCH 00/11] Initital support for new power/perf features for SD cards Ulf Hansson
                   ` (10 preceding siblings ...)
  2021-05-04 16:12 ` [PATCH 11/11] mmc: core: Add support for Power Off Notification " Ulf Hansson
@ 2021-05-07  6:44 ` Avri Altman
  2021-05-07  7:31   ` Ulf Hansson
  2021-05-11 10:56 ` Ulf Hansson
  12 siblings, 1 reply; 40+ messages in thread
From: Avri Altman @ 2021-05-07  6:44 UTC (permalink / raw)
  To: Ulf Hansson, linux-mmc, Adrian Hunter
  Cc: Linus Walleij, Wolfram Sang, Shawn Lin, Masami Hiramatsu,
	linux-block, linux-kernel

> 
> In the SD spec v4.x the SD function extension registers were introduced,
> together with a new set of commands (CMD48/49 and CMD58/59) to read
> and write
> to them.
> 
> Moreover, in v4.x a new standard function for power management features
> were
> added, while in v6.x a new standard function for performance
> enhancements
> features were added.
> 
> This series implement the basics to add support for these new features (and
> includes some additional preparations in patch 1->7), by adding support for
> reading and parsing these new SD registers. In the final patch we add
> support
> for the SD poweroff notification feature, which also add a function to write
> to
> these registers.
> 
> Note that, there are no HW updates need for the host to support
> reading/parsing
> of the these new SD registers. This has been tested with a 64GB Sandisk
> Extreme
> PRO UHS-I A2 card.
> 
> Tests and reviews are of course greatly appreciated!
Echoing an internal discussion about this series:
"... 
That is very good that there will be a support of the extension registers of SD spec .   It may allow existing and future features to be very easily supported by hosts (like existing power off control and future TCG/RPMB related spec which is currently under definition and is going to use those registers as well..).
..."
Therefore for entire series: Acked-by: Avri Altman <avri.altman@wdc.com>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 09/11] mmc: core: Read the SD function extension registers for power management
  2021-05-07  2:06   ` Shawn Lin
@ 2021-05-07  7:27     ` Ulf Hansson
  2021-05-07  7:48       ` Shawn Lin
  0 siblings, 1 reply; 40+ messages in thread
From: Ulf Hansson @ 2021-05-07  7:27 UTC (permalink / raw)
  To: Shawn Lin
  Cc: linux-mmc, Adrian Hunter, Linus Walleij, Wolfram Sang,
	Avri Altman, Masami Hiramatsu, linux-block,
	Linux Kernel Mailing List

On Fri, 7 May 2021 at 04:06, Shawn Lin <shawn.lin@rock-chips.com> wrote:
>
>
> On 2021/5/5 0:12, Ulf Hansson wrote:
> > In SD spec v4.x the SD function extension registers were introduced. A
>
> I have a v4.0 spec and it doesn't state that v4.0 suppports reading
> extension registers but just says TBD instead.  So I guess v4.x doesn't
> include v4.0 ?

Good question. The v4.0 spec introduces the CMD48/49 and CMD58/59,
while in v4.10 the spec adds the power management extensions.

I can update the commit message to better reflect this, if you prefer!?

Thanks a lot for reviewing!

Kind regards
Uffe

>
> > specific function register were added to let the card announce support for
> > optional features in regards to power management. The features that were
> > added are "Power Off Notification", "Power Down Mode" and "Power
> > Sustenance".
> >
> > As a first step, let's read and parse this register for power management
> > during the SD card initialization and store the information about the
> > supported features in the struct mmc_card. In this way, we prepare for
> > subsequent changes to implement the complete support for the new features.
> >
> > Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> > ---
> >   drivers/mmc/core/sd.c    | 178 +++++++++++++++++++++++++++++++++++++++
> >   include/linux/mmc/card.h |  13 +++
> >   include/linux/mmc/sd.h   |   3 +
> >   3 files changed, 194 insertions(+)
> >
> > diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> > index de7b5f8df550..cb5e8b2fc32f 100644
> > --- a/drivers/mmc/core/sd.c
> > +++ b/drivers/mmc/core/sd.c
> > @@ -996,6 +996,177 @@ static bool mmc_sd_card_using_v18(struct mmc_card *card)
> >              (SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR104 | SD_MODE_UHS_DDR50);
> >   }
> >
> > +static int sd_read_ext_reg(struct mmc_card *card, u8 fno, u8 page,
> > +                        u16 offset, u16 len, u8 *reg_buf)
> > +{
> > +     u32 cmd_args;
> > +
> > +     /*
> > +      * Command arguments of CMD48:
> > +      * [31:31] MIO (0 = memory).
> > +      * [30:27] FNO (function number).
> > +      * [26:26] reserved (0).
> > +      * [25:18] page number.
> > +      * [17:9] offset address.
> > +      * [8:0] length (0 = 1 byte, 1ff = 512 bytes).
> > +      */
> > +     cmd_args = fno << 27 | page << 18 | offset << 9 | (len -1);
> > +
> > +     return mmc_send_adtc_data(card, card->host, SD_READ_EXTR_SINGLE,
> > +                               cmd_args, reg_buf, 512);
> > +}
> > +
> > +static int sd_parse_ext_reg_power(struct mmc_card *card, u8 fno, u8 page,
> > +                               u16 offset)
> > +{
> > +     int err;
> > +     u8 *reg_buf;
> > +
> > +     reg_buf = kzalloc(512, GFP_KERNEL);
> > +     if (!reg_buf)
> > +             return -ENOMEM;
> > +
> > +     /* Read the extension register for power management function. */
> > +     err = sd_read_ext_reg(card, fno, page, offset, 512, reg_buf);
> > +     if (err) {
> > +             pr_warn("%s: error %d reading PM func of ext reg\n",
> > +                     mmc_hostname(card->host), err);
> > +             goto out;
> > +     }
> > +
> > +     /* PM revision consists of 4 bits. */
> > +     card->ext_power.rev = reg_buf[0] & 0xf;
> > +
> > +     /* Power Off Notification support at bit 4. */
> > +     if (reg_buf[1] & 0x10)
> > +             card->ext_power.feature_support |= SD_EXT_POWER_OFF_NOTIFY;
> > +
> > +     /* Power Sustenance support at bit 5. */
> > +     if (reg_buf[1] & 0x20)
> > +             card->ext_power.feature_support |= SD_EXT_POWER_SUSTENANCE;
> > +
> > +     /* Power Down Mode support at bit 6. */
> > +     if (reg_buf[1] & 0x40)
> > +             card->ext_power.feature_support |= SD_EXT_POWER_DOWN_MODE;
> > +
> > +     card->ext_power.fno = fno;
> > +     card->ext_power.page = page;
> > +     card->ext_power.offset = offset;
> > +
> > +out:
> > +     kfree(reg_buf);
> > +     return err;
> > +}
> > +
> > +static int sd_parse_ext_reg(struct mmc_card *card, u8 *gen_info_buf,
> > +                         u16 *next_ext_addr)
> > +{
> > +     u8 num_regs, fno, page;
> > +     u16 sfc, offset, ext = *next_ext_addr;
> > +     u32 reg_addr;
> > +
> > +     /*
> > +      * Parse only one register set per extension, as that is sufficient to
> > +      * support the standard functions. This means another 48 bytes in the
> > +      * buffer must be available.
> > +      */
> > +     if (ext + 48 > 512)
> > +             return -EFAULT;
> > +
> > +     /* Standard Function Code */
> > +     memcpy(&sfc, &gen_info_buf[ext], 2);
> > +
> > +     /* Address to the next extension. */
> > +     memcpy(next_ext_addr, &gen_info_buf[ext + 40], 2);
> > +
> > +     /* Number of registers for this extension. */
> > +     num_regs = gen_info_buf[ext + 42];
> > +
> > +     /* We support only one register per extension. */
> > +     if (num_regs != 1)
> > +             return 0;
> > +
> > +     /* Extension register address. */
> > +     memcpy(&reg_addr, &gen_info_buf[ext + 44], 4);
> > +
> > +     /* 9 bits (0 to 8) contains the offset address. */
> > +     offset = reg_addr & 0x1ff;
> > +
> > +     /* 8 bits (9 to 16) contains the page number. */
> > +     page = reg_addr >> 9 & 0xff ;
> > +
> > +     /* 4 bits (18 to 21) contains the function number. */
> > +     fno = reg_addr >> 18 & 0xf;
> > +
> > +     /* Standard Function Code for power management. */
> > +     if (sfc == 0x1)
> > +             return sd_parse_ext_reg_power(card, fno, page, offset);
> > +
> > +     return 0;
> > +}
> > +
> > +static int sd_read_ext_regs(struct mmc_card *card)
> > +{
> > +     int err, i;
> > +     u8 num_ext, *gen_info_buf;
> > +     u16 rev, len, next_ext_addr;
> > +
> > +     if (mmc_host_is_spi(card->host))
> > +             return 0;
> > +
> > +     if (!(card->scr.cmds & SD_SCR_CMD48_SUPPORT))
> > +             return 0;
> > +
> > +     gen_info_buf = kzalloc(512, GFP_KERNEL);
> > +     if (!gen_info_buf)
> > +             return -ENOMEM;
> > +
> > +     /*
> > +      * Read 512 bytes of general info, which is found at function number 0,
> > +      * at page 0 and with no offset.
> > +      */
> > +     err = sd_read_ext_reg(card, 0, 0, 0, 512, gen_info_buf);
> > +     if (err) {
> > +             pr_warn("%s: error %d reading general info of SD ext reg\n",
> > +                     mmc_hostname(card->host), err);
> > +             goto out;
> > +     }
> > +
> > +     /* General info structure revision. */
> > +     memcpy(&rev, &gen_info_buf[0], 2);
> > +
> > +     /* Length of general info in bytes. */
> > +     memcpy(&len, &gen_info_buf[2], 2);
> > +
> > +     /* Number of extensions to be find. */
> > +     num_ext = gen_info_buf[4];
> > +
> > +     /* We support revision 0, but limit it to 512 bytes for simplicity. */
> > +     if (rev != 0 || len > 512) {
> > +             pr_warn("%s: non-supported SD ext reg layout\n",
> > +                     mmc_hostname(card->host));
> > +             goto out;
> > +     }
> > +
> > +     /*
> > +      * Parse the extension registers. The first extension should start
> > +      * immediately after the general info header (16 bytes).
> > +      */
> > +     next_ext_addr = 16;
> > +     for (i = 0; i < num_ext; i++) {
> > +             err = sd_parse_ext_reg(card, gen_info_buf, &next_ext_addr);
> > +             if (err) {
> > +                     pr_warn("%s: error %d parsing SD ext reg\n",
> > +                             mmc_hostname(card->host), err);
> > +                     goto out;
> > +             }
> > +     }
> > +
> > +out:
> > +     kfree(gen_info_buf);
> > +     return err;
> > +}
> > +
> >   /*
> >    * Handle the detection and initialisation of a card.
> >    *
> > @@ -1144,6 +1315,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
> >               }
> >       }
> >
> > +     if (!oldcard) {
> > +             /* Read/parse the extension registers. */
> > +             err = sd_read_ext_regs(card);
> > +             if (err)
> > +                     goto free_card;
> > +     }
> > +
> >       if (host->cqe_ops && !host->cqe_enabled) {
> >               err = host->cqe_ops->cqe_enable(host, card);
> >               if (!err) {
> > diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> > index 858fc4d11240..03a862e93594 100644
> > --- a/include/linux/mmc/card.h
> > +++ b/include/linux/mmc/card.h
> > @@ -191,6 +191,18 @@ struct sd_switch_caps {
> >   #define SD_MAX_CURRENT_800  (1 << SD_SET_CURRENT_LIMIT_800)
> >   };
> >
> > +struct sd_ext_reg {
> > +     u8                      fno;
> > +     u8                      page;
> > +     u16                     offset;
> > +     u8                      rev;
> > +     u8                      feature_support;
> > +/* Power Management Function. */
> > +#define SD_EXT_POWER_OFF_NOTIFY      (1<<0)
> > +#define SD_EXT_POWER_SUSTENANCE      (1<<1)
> > +#define SD_EXT_POWER_DOWN_MODE       (1<<2)
> > +};
> > +
> >   struct sdio_cccr {
> >       unsigned int            sdio_vsn;
> >       unsigned int            sd_vsn;
> > @@ -292,6 +304,7 @@ struct mmc_card {
> >       struct sd_scr           scr;            /* extra SD information */
> >       struct sd_ssr           ssr;            /* yet more SD information */
> >       struct sd_switch_caps   sw_caps;        /* switch (CMD6) caps */
> > +     struct sd_ext_reg       ext_power;      /* SD extension reg for PM */
> >
> >       unsigned int            sdio_funcs;     /* number of SDIO functions */
> >       atomic_t                sdio_funcs_probed; /* number of probed SDIO funcs */
> > diff --git a/include/linux/mmc/sd.h b/include/linux/mmc/sd.h
> > index 2236aa540faa..43bfc5c39ad4 100644
> > --- a/include/linux/mmc/sd.h
> > +++ b/include/linux/mmc/sd.h
> > @@ -29,6 +29,9 @@
> >   #define SD_APP_OP_COND           41   /* bcr  [31:0] OCR         R3  */
> >   #define SD_APP_SEND_SCR          51   /* adtc                    R1  */
> >
> > +  /* class 11 */
> > +#define SD_READ_EXTR_SINGLE      48   /* adtc [31:0]             R1  */
> > +
> >   /* OCR bit definitions */
> >   #define SD_OCR_S18R         (1 << 24)    /* 1.8V switching request */
> >   #define SD_ROCR_S18A                SD_OCR_S18R  /* 1.8V switching accepted by card */
> >
>
>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 06/11] mmc: core: Prepare mmc_send_cxd_data() to be re-used for additional cmds
  2021-05-06 13:00   ` Linus Walleij
@ 2021-05-07  7:30     ` Ulf Hansson
  0 siblings, 0 replies; 40+ messages in thread
From: Ulf Hansson @ 2021-05-07  7:30 UTC (permalink / raw)
  To: Linus Walleij
  Cc: linux-mmc, Adrian Hunter, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, linux-kernel

On Thu, 6 May 2021 at 15:00, Linus Walleij <linus.walleij@linaro.org> wrote:
>
> On Tue, May 4, 2021 at 6:12 PM Ulf Hansson <ulf.hansson@linaro.org> wrote:
>
> >   * NOTE: void *buf, caller for the buf is required to use DMA-capable
> >   * buffer or on-stack buffer (with some overhead in callee).
> >   */
> > -static int
> > -mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
> > -               u32 opcode, void *buf, unsigned len)
> > +int mmc_send_adtc_data(struct mmc_card *card, struct mmc_host *host, u32 opcode,
> > +                      u32 args, void *buf, unsigned len)
>
> Just a note here (the change is good)
>
> When applying please add some kerneldoc above mmc_send_adtc_data()
> and expand the ADTC acronym and add some info explaining what it
> is maybe a small protocol ref or so, so readers of the code get an
> intuitive feeling for what this function does and what ADTC is.

Thanks for the suggestion and the reviews, I look into this!

Kind  regards
Uffe

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 00/11] Initital support for new power/perf features for SD cards
  2021-05-07  6:44 ` [PATCH 00/11] Initital support for new power/perf features " Avri Altman
@ 2021-05-07  7:31   ` Ulf Hansson
  0 siblings, 0 replies; 40+ messages in thread
From: Ulf Hansson @ 2021-05-07  7:31 UTC (permalink / raw)
  To: Avri Altman
  Cc: linux-mmc, Adrian Hunter, Linus Walleij, Wolfram Sang, Shawn Lin,
	Masami Hiramatsu, linux-block, linux-kernel

On Fri, 7 May 2021 at 08:44, Avri Altman <Avri.Altman@wdc.com> wrote:
>
> >
> > In the SD spec v4.x the SD function extension registers were introduced,
> > together with a new set of commands (CMD48/49 and CMD58/59) to read
> > and write
> > to them.
> >
> > Moreover, in v4.x a new standard function for power management features
> > were
> > added, while in v6.x a new standard function for performance
> > enhancements
> > features were added.
> >
> > This series implement the basics to add support for these new features (and
> > includes some additional preparations in patch 1->7), by adding support for
> > reading and parsing these new SD registers. In the final patch we add
> > support
> > for the SD poweroff notification feature, which also add a function to write
> > to
> > these registers.
> >
> > Note that, there are no HW updates need for the host to support
> > reading/parsing
> > of the these new SD registers. This has been tested with a 64GB Sandisk
> > Extreme
> > PRO UHS-I A2 card.
> >
> > Tests and reviews are of course greatly appreciated!
> Echoing an internal discussion about this series:
> "...
> That is very good that there will be a support of the extension registers of SD spec .   It may allow existing and future features to be very easily supported by hosts (like existing power off control and future TCG/RPMB related spec which is currently under definition and is going to use those registers as well..).

Thanks for sharing. I am happy to help!

> ..."
> Therefore for entire series: Acked-by: Avri Altman <avri.altman@wdc.com>

Thanks for reviewing!

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 09/11] mmc: core: Read the SD function extension registers for power management
  2021-05-07  7:27     ` Ulf Hansson
@ 2021-05-07  7:48       ` Shawn Lin
  2021-05-07 11:36         ` Ulf Hansson
  0 siblings, 1 reply; 40+ messages in thread
From: Shawn Lin @ 2021-05-07  7:48 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: shawn.lin, linux-mmc, Adrian Hunter, Linus Walleij, Wolfram Sang,
	Avri Altman, Masami Hiramatsu, linux-block,
	Linux Kernel Mailing List

On 2021/5/7 15:27, Ulf Hansson wrote:
> On Fri, 7 May 2021 at 04:06, Shawn Lin <shawn.lin@rock-chips.com> wrote:
>>
>>
>> On 2021/5/5 0:12, Ulf Hansson wrote:
>>> In SD spec v4.x the SD function extension registers were introduced. A
>>
>> I have a v4.0 spec and it doesn't state that v4.0 suppports reading
>> extension registers but just says TBD instead.  So I guess v4.x doesn't
>> include v4.0 ?
> 
> Good question. The v4.0 spec introduces the CMD48/49 and CMD58/59,
> while in v4.10 the spec adds the power management extensions.
> 
> I can update the commit message to better reflect this, if you prefer!?

It would be better.

And I downloaded the latest v8.00 spec, checked carefully with the new
features there to make sure we don't make any misinterpretations at
first.

For patch 9 -11 as well,

Reviewed-by: Shawn Lin <shawn.lin@rock-chips.con>

> 
> Thanks a lot for reviewing!
> 
> Kind regards
> Uffe
> 
>>
>>> specific function register were added to let the card announce support for
>>> optional features in regards to power management. The features that were
>>> added are "Power Off Notification", "Power Down Mode" and "Power
>>> Sustenance".
>>>
>>> As a first step, let's read and parse this register for power management
>>> during the SD card initialization and store the information about the
>>> supported features in the struct mmc_card. In this way, we prepare for
>>> subsequent changes to implement the complete support for the new features.
>>>
>>> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
>>> ---
>>>    drivers/mmc/core/sd.c    | 178 +++++++++++++++++++++++++++++++++++++++
>>>    include/linux/mmc/card.h |  13 +++
>>>    include/linux/mmc/sd.h   |   3 +
>>>    3 files changed, 194 insertions(+)
>>>
>>> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
>>> index de7b5f8df550..cb5e8b2fc32f 100644
>>> --- a/drivers/mmc/core/sd.c
>>> +++ b/drivers/mmc/core/sd.c
>>> @@ -996,6 +996,177 @@ static bool mmc_sd_card_using_v18(struct mmc_card *card)
>>>               (SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR104 | SD_MODE_UHS_DDR50);
>>>    }
>>>
>>> +static int sd_read_ext_reg(struct mmc_card *card, u8 fno, u8 page,
>>> +                        u16 offset, u16 len, u8 *reg_buf)
>>> +{
>>> +     u32 cmd_args;
>>> +
>>> +     /*
>>> +      * Command arguments of CMD48:
>>> +      * [31:31] MIO (0 = memory).
>>> +      * [30:27] FNO (function number).
>>> +      * [26:26] reserved (0).
>>> +      * [25:18] page number.
>>> +      * [17:9] offset address.
>>> +      * [8:0] length (0 = 1 byte, 1ff = 512 bytes).
>>> +      */
>>> +     cmd_args = fno << 27 | page << 18 | offset << 9 | (len -1);
>>> +
>>> +     return mmc_send_adtc_data(card, card->host, SD_READ_EXTR_SINGLE,
>>> +                               cmd_args, reg_buf, 512);
>>> +}
>>> +
>>> +static int sd_parse_ext_reg_power(struct mmc_card *card, u8 fno, u8 page,
>>> +                               u16 offset)
>>> +{
>>> +     int err;
>>> +     u8 *reg_buf;
>>> +
>>> +     reg_buf = kzalloc(512, GFP_KERNEL);
>>> +     if (!reg_buf)
>>> +             return -ENOMEM;
>>> +
>>> +     /* Read the extension register for power management function. */
>>> +     err = sd_read_ext_reg(card, fno, page, offset, 512, reg_buf);
>>> +     if (err) {
>>> +             pr_warn("%s: error %d reading PM func of ext reg\n",
>>> +                     mmc_hostname(card->host), err);
>>> +             goto out;
>>> +     }
>>> +
>>> +     /* PM revision consists of 4 bits. */
>>> +     card->ext_power.rev = reg_buf[0] & 0xf;
>>> +
>>> +     /* Power Off Notification support at bit 4. */
>>> +     if (reg_buf[1] & 0x10)
>>> +             card->ext_power.feature_support |= SD_EXT_POWER_OFF_NOTIFY;
>>> +
>>> +     /* Power Sustenance support at bit 5. */
>>> +     if (reg_buf[1] & 0x20)
>>> +             card->ext_power.feature_support |= SD_EXT_POWER_SUSTENANCE;
>>> +
>>> +     /* Power Down Mode support at bit 6. */
>>> +     if (reg_buf[1] & 0x40)
>>> +             card->ext_power.feature_support |= SD_EXT_POWER_DOWN_MODE;
>>> +
>>> +     card->ext_power.fno = fno;
>>> +     card->ext_power.page = page;
>>> +     card->ext_power.offset = offset;
>>> +
>>> +out:
>>> +     kfree(reg_buf);
>>> +     return err;
>>> +}
>>> +
>>> +static int sd_parse_ext_reg(struct mmc_card *card, u8 *gen_info_buf,
>>> +                         u16 *next_ext_addr)
>>> +{
>>> +     u8 num_regs, fno, page;
>>> +     u16 sfc, offset, ext = *next_ext_addr;
>>> +     u32 reg_addr;
>>> +
>>> +     /*
>>> +      * Parse only one register set per extension, as that is sufficient to
>>> +      * support the standard functions. This means another 48 bytes in the
>>> +      * buffer must be available.
>>> +      */
>>> +     if (ext + 48 > 512)
>>> +             return -EFAULT;
>>> +
>>> +     /* Standard Function Code */
>>> +     memcpy(&sfc, &gen_info_buf[ext], 2);
>>> +
>>> +     /* Address to the next extension. */
>>> +     memcpy(next_ext_addr, &gen_info_buf[ext + 40], 2);
>>> +
>>> +     /* Number of registers for this extension. */
>>> +     num_regs = gen_info_buf[ext + 42];
>>> +
>>> +     /* We support only one register per extension. */
>>> +     if (num_regs != 1)
>>> +             return 0;
>>> +
>>> +     /* Extension register address. */
>>> +     memcpy(&reg_addr, &gen_info_buf[ext + 44], 4);
>>> +
>>> +     /* 9 bits (0 to 8) contains the offset address. */
>>> +     offset = reg_addr & 0x1ff;
>>> +
>>> +     /* 8 bits (9 to 16) contains the page number. */
>>> +     page = reg_addr >> 9 & 0xff ;
>>> +
>>> +     /* 4 bits (18 to 21) contains the function number. */
>>> +     fno = reg_addr >> 18 & 0xf;
>>> +
>>> +     /* Standard Function Code for power management. */
>>> +     if (sfc == 0x1)
>>> +             return sd_parse_ext_reg_power(card, fno, page, offset);
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +static int sd_read_ext_regs(struct mmc_card *card)
>>> +{
>>> +     int err, i;
>>> +     u8 num_ext, *gen_info_buf;
>>> +     u16 rev, len, next_ext_addr;
>>> +
>>> +     if (mmc_host_is_spi(card->host))
>>> +             return 0;
>>> +
>>> +     if (!(card->scr.cmds & SD_SCR_CMD48_SUPPORT))
>>> +             return 0;
>>> +
>>> +     gen_info_buf = kzalloc(512, GFP_KERNEL);
>>> +     if (!gen_info_buf)
>>> +             return -ENOMEM;
>>> +
>>> +     /*
>>> +      * Read 512 bytes of general info, which is found at function number 0,
>>> +      * at page 0 and with no offset.
>>> +      */
>>> +     err = sd_read_ext_reg(card, 0, 0, 0, 512, gen_info_buf);
>>> +     if (err) {
>>> +             pr_warn("%s: error %d reading general info of SD ext reg\n",
>>> +                     mmc_hostname(card->host), err);
>>> +             goto out;
>>> +     }
>>> +
>>> +     /* General info structure revision. */
>>> +     memcpy(&rev, &gen_info_buf[0], 2);
>>> +
>>> +     /* Length of general info in bytes. */
>>> +     memcpy(&len, &gen_info_buf[2], 2);
>>> +
>>> +     /* Number of extensions to be find. */
>>> +     num_ext = gen_info_buf[4];
>>> +
>>> +     /* We support revision 0, but limit it to 512 bytes for simplicity. */
>>> +     if (rev != 0 || len > 512) {
>>> +             pr_warn("%s: non-supported SD ext reg layout\n",
>>> +                     mmc_hostname(card->host));
>>> +             goto out;
>>> +     }
>>> +
>>> +     /*
>>> +      * Parse the extension registers. The first extension should start
>>> +      * immediately after the general info header (16 bytes).
>>> +      */
>>> +     next_ext_addr = 16;
>>> +     for (i = 0; i < num_ext; i++) {
>>> +             err = sd_parse_ext_reg(card, gen_info_buf, &next_ext_addr);
>>> +             if (err) {
>>> +                     pr_warn("%s: error %d parsing SD ext reg\n",
>>> +                             mmc_hostname(card->host), err);
>>> +                     goto out;
>>> +             }
>>> +     }
>>> +
>>> +out:
>>> +     kfree(gen_info_buf);
>>> +     return err;
>>> +}
>>> +
>>>    /*
>>>     * Handle the detection and initialisation of a card.
>>>     *
>>> @@ -1144,6 +1315,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
>>>                }
>>>        }
>>>
>>> +     if (!oldcard) {
>>> +             /* Read/parse the extension registers. */
>>> +             err = sd_read_ext_regs(card);
>>> +             if (err)
>>> +                     goto free_card;
>>> +     }
>>> +
>>>        if (host->cqe_ops && !host->cqe_enabled) {
>>>                err = host->cqe_ops->cqe_enable(host, card);
>>>                if (!err) {
>>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>>> index 858fc4d11240..03a862e93594 100644
>>> --- a/include/linux/mmc/card.h
>>> +++ b/include/linux/mmc/card.h
>>> @@ -191,6 +191,18 @@ struct sd_switch_caps {
>>>    #define SD_MAX_CURRENT_800  (1 << SD_SET_CURRENT_LIMIT_800)
>>>    };
>>>
>>> +struct sd_ext_reg {
>>> +     u8                      fno;
>>> +     u8                      page;
>>> +     u16                     offset;
>>> +     u8                      rev;
>>> +     u8                      feature_support;
>>> +/* Power Management Function. */
>>> +#define SD_EXT_POWER_OFF_NOTIFY      (1<<0)
>>> +#define SD_EXT_POWER_SUSTENANCE      (1<<1)
>>> +#define SD_EXT_POWER_DOWN_MODE       (1<<2)
>>> +};
>>> +
>>>    struct sdio_cccr {
>>>        unsigned int            sdio_vsn;
>>>        unsigned int            sd_vsn;
>>> @@ -292,6 +304,7 @@ struct mmc_card {
>>>        struct sd_scr           scr;            /* extra SD information */
>>>        struct sd_ssr           ssr;            /* yet more SD information */
>>>        struct sd_switch_caps   sw_caps;        /* switch (CMD6) caps */
>>> +     struct sd_ext_reg       ext_power;      /* SD extension reg for PM */
>>>
>>>        unsigned int            sdio_funcs;     /* number of SDIO functions */
>>>        atomic_t                sdio_funcs_probed; /* number of probed SDIO funcs */
>>> diff --git a/include/linux/mmc/sd.h b/include/linux/mmc/sd.h
>>> index 2236aa540faa..43bfc5c39ad4 100644
>>> --- a/include/linux/mmc/sd.h
>>> +++ b/include/linux/mmc/sd.h
>>> @@ -29,6 +29,9 @@
>>>    #define SD_APP_OP_COND           41   /* bcr  [31:0] OCR         R3  */
>>>    #define SD_APP_SEND_SCR          51   /* adtc                    R1  */
>>>
>>> +  /* class 11 */
>>> +#define SD_READ_EXTR_SINGLE      48   /* adtc [31:0]             R1  */
>>> +
>>>    /* OCR bit definitions */
>>>    #define SD_OCR_S18R         (1 << 24)    /* 1.8V switching request */
>>>    #define SD_ROCR_S18A                SD_OCR_S18R  /* 1.8V switching accepted by card */
>>>
>>
>>
> 
> 
> 



^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 09/11] mmc: core: Read the SD function extension registers for power management
  2021-05-07  7:48       ` Shawn Lin
@ 2021-05-07 11:36         ` Ulf Hansson
  0 siblings, 0 replies; 40+ messages in thread
From: Ulf Hansson @ 2021-05-07 11:36 UTC (permalink / raw)
  To: Shawn Lin
  Cc: linux-mmc, Adrian Hunter, Linus Walleij, Wolfram Sang,
	Avri Altman, Masami Hiramatsu, linux-block,
	Linux Kernel Mailing List

On Fri, 7 May 2021 at 09:48, Shawn Lin <shawn.lin@rock-chips.com> wrote:
>
> On 2021/5/7 15:27, Ulf Hansson wrote:
> > On Fri, 7 May 2021 at 04:06, Shawn Lin <shawn.lin@rock-chips.com> wrote:
> >>
> >>
> >> On 2021/5/5 0:12, Ulf Hansson wrote:
> >>> In SD spec v4.x the SD function extension registers were introduced. A
> >>
> >> I have a v4.0 spec and it doesn't state that v4.0 suppports reading
> >> extension registers but just says TBD instead.  So I guess v4.x doesn't
> >> include v4.0 ?
> >
> > Good question. The v4.0 spec introduces the CMD48/49 and CMD58/59,
> > while in v4.10 the spec adds the power management extensions.
> >
> > I can update the commit message to better reflect this, if you prefer!?
>
> It would be better.

Sure, let me amend the change when applying.

>
> And I downloaded the latest v8.00 spec, checked carefully with the new
> features there to make sure we don't make any misinterpretations at
> first.
>
> For patch 9 -11 as well,
>
> Reviewed-by: Shawn Lin <shawn.lin@rock-chips.con>

Thanks!

[...]

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 00/11] Initital support for new power/perf features for SD cards
  2021-05-04 16:12 [PATCH 00/11] Initital support for new power/perf features for SD cards Ulf Hansson
                   ` (11 preceding siblings ...)
  2021-05-07  6:44 ` [PATCH 00/11] Initital support for new power/perf features " Avri Altman
@ 2021-05-11 10:56 ` Ulf Hansson
  12 siblings, 0 replies; 40+ messages in thread
From: Ulf Hansson @ 2021-05-11 10:56 UTC (permalink / raw)
  To: linux-mmc, Ulf Hansson, Adrian Hunter
  Cc: Linus Walleij, Wolfram Sang, Shawn Lin, Avri Altman,
	Masami Hiramatsu, linux-block, Linux Kernel Mailing List

On Tue, 4 May 2021 at 18:12, Ulf Hansson <ulf.hansson@linaro.org> wrote:
>
> In the SD spec v4.x the SD function extension registers were introduced,
> together with a new set of commands (CMD48/49 and CMD58/59) to read and write
> to them.
>
> Moreover, in v4.x a new standard function for power management features were
> added, while in v6.x a new standard function for performance enhancements
> features were added.
>
> This series implement the basics to add support for these new features (and
> includes some additional preparations in patch 1->7), by adding support for
> reading and parsing these new SD registers. In the final patch we add support
> for the SD poweroff notification feature, which also add a function to write to
> these registers.
>
> Note that, there are no HW updates need for the host to support reading/parsing
> of the these new SD registers. This has been tested with a 64GB Sandisk Extreme
> PRO UHS-I A2 card.
>
> Tests and reviews are of course greatly appreciated!
>
> Kind regards
> Ulf Hansson
>
> Ulf Hansson (11):
>   mmc: core: Drop open coding when preparing commands with busy
>     signaling
>   mmc: core: Take into account MMC_CAP_NEED_RSP_BUSY for eMMC HPI
>     commands
>   mmc: core: Re-structure some code in __mmc_poll_for_busy()
>   mmc: core: Extend re-use of __mmc_poll_for_busy()
>   mmc: core: Enable eMMC sleep commands to use HW busy polling
>   mmc: core: Prepare mmc_send_cxd_data() to be re-used for additional
>     cmds
>   mmc: core: Drop open coding in mmc_sd_switch()
>   mmc: core: Parse the SD SCR register for support of CMD48/49 and
>     CMD58/59
>   mmc: core: Read the SD function extension registers for power
>     management
>   mmc: core: Read performance enhancements registers for SD cards
>   mmc: core: Add support for Power Off Notification for SD cards
>
>  drivers/mmc/core/core.c    |  22 +--
>  drivers/mmc/core/mmc.c     |  43 ++---
>  drivers/mmc/core/mmc_ops.c | 137 +++++++-------
>  drivers/mmc/core/mmc_ops.h |  10 +-
>  drivers/mmc/core/sd.c      | 371 ++++++++++++++++++++++++++++++++++++-
>  drivers/mmc/core/sd_ops.c  |  38 +---
>  include/linux/mmc/card.h   |  22 +++
>  include/linux/mmc/sd.h     |   4 +
>  8 files changed, 504 insertions(+), 143 deletions(-)

FYI, this series has been applied for next, with some minor
modifications according to review comments. Thanks!

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2021-05-11 10:57 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-04 16:12 [PATCH 00/11] Initital support for new power/perf features for SD cards Ulf Hansson
2021-05-04 16:12 ` [PATCH 01/11] mmc: core: Drop open coding when preparing commands with busy signaling Ulf Hansson
2021-05-06 12:50   ` Linus Walleij
2021-05-07  1:42   ` Shawn Lin
2021-05-04 16:12 ` [PATCH 02/11] mmc: core: Take into account MMC_CAP_NEED_RSP_BUSY for eMMC HPI commands Ulf Hansson
2021-05-06 12:51   ` Linus Walleij
2021-05-07  1:44   ` Shawn Lin
2021-05-04 16:12 ` [PATCH 03/11] mmc: core: Re-structure some code in __mmc_poll_for_busy() Ulf Hansson
2021-05-06 12:52   ` Linus Walleij
2021-05-07  1:48   ` Shawn Lin
2021-05-04 16:12 ` [PATCH 04/11] mmc: core: Extend re-use of __mmc_poll_for_busy() Ulf Hansson
2021-05-06 12:53   ` Linus Walleij
2021-05-07  1:51   ` Shawn Lin
2021-05-04 16:12 ` [PATCH 05/11] mmc: core: Enable eMMC sleep commands to use HW busy polling Ulf Hansson
2021-05-06 12:55   ` Linus Walleij
2021-05-07  1:52   ` Shawn Lin
2021-05-04 16:12 ` [PATCH 06/11] mmc: core: Prepare mmc_send_cxd_data() to be re-used for additional cmds Ulf Hansson
2021-05-06 12:56   ` Linus Walleij
2021-05-06 13:00   ` Linus Walleij
2021-05-07  7:30     ` Ulf Hansson
2021-05-07  1:53   ` Shawn Lin
2021-05-04 16:12 ` [PATCH 07/11] mmc: core: Drop open coding in mmc_sd_switch() Ulf Hansson
2021-05-06 12:57   ` Linus Walleij
2021-05-07  1:54   ` Shawn Lin
2021-05-04 16:12 ` [PATCH 08/11] mmc: core: Parse the SD SCR register for support of CMD48/49 and CMD58/59 Ulf Hansson
2021-05-06 13:01   ` Linus Walleij
2021-05-07  1:58   ` Shawn Lin
2021-05-04 16:12 ` [PATCH 09/11] mmc: core: Read the SD function extension registers for power management Ulf Hansson
2021-05-06 13:04   ` Linus Walleij
2021-05-07  2:06   ` Shawn Lin
2021-05-07  7:27     ` Ulf Hansson
2021-05-07  7:48       ` Shawn Lin
2021-05-07 11:36         ` Ulf Hansson
2021-05-04 16:12 ` [PATCH 10/11] mmc: core: Read performance enhancements registers for SD cards Ulf Hansson
2021-05-06 13:05   ` Linus Walleij
2021-05-04 16:12 ` [PATCH 11/11] mmc: core: Add support for Power Off Notification " Ulf Hansson
2021-05-06 13:07   ` Linus Walleij
2021-05-07  6:44 ` [PATCH 00/11] Initital support for new power/perf features " Avri Altman
2021-05-07  7:31   ` Ulf Hansson
2021-05-11 10:56 ` Ulf Hansson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).