All of lore.kernel.org
 help / color / mirror / Atom feed
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: stable@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	patches@lists.linux.dev, Adrian Hunter <adrian.hunter@intel.com>,
	Ulf Hansson <ulf.hansson@linaro.org>
Subject: [PATCH 4.9 11/31] mmc: sdhci: Fix voltage switch delay
Date: Mon, 12 Dec 2022 14:19:29 +0100	[thread overview]
Message-ID: <20221212130910.580294118@linuxfoundation.org> (raw)
In-Reply-To: <20221212130909.943483205@linuxfoundation.org>

From: Adrian Hunter <adrian.hunter@intel.com>

commit c981cdfb9925f64a364f13c2b4f98f877308a408 upstream.

Commit 20b92a30b561 ("mmc: sdhci: update signal voltage switch code")
removed voltage switch delays from sdhci because mmc core had been
enhanced to support them. However that assumed that sdhci_set_ios()
did a single clock change, which it did not, and so the delays in mmc
core, which should have come after the first clock change, were not
effective.

Fix by avoiding re-configuring UHS and preset settings when the clock
is turning on and the settings have not changed. That then also avoids
the associated clock changes, so that then sdhci_set_ios() does a single
clock change when voltage switching, and the mmc core delays become
effective.

To do that has meant keeping track of driver strength (host->drv_type),
and cases of reinitialization (host->reinit_uhs).

Note also, the 'turning_on_clk' restriction should not be necessary
but is done to minimize the impact of the change on stable kernels.

Fixes: 20b92a30b561 ("mmc: sdhci: update signal voltage switch code")
Cc: stable@vger.kernel.org
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Link: https://lore.kernel.org/r/20221128133259.38305-2-adrian.hunter@intel.com
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/mmc/host/sdhci.c |   63 +++++++++++++++++++++++++++++++++++++++++------
 drivers/mmc/host/sdhci.h |    2 +
 2 files changed, 57 insertions(+), 8 deletions(-)

--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -240,6 +240,7 @@ static void sdhci_init(struct sdhci_host
 	if (soft) {
 		/* force clock reconfiguration */
 		host->clock = 0;
+		host->reinit_uhs = true;
 		mmc->ops->set_ios(mmc, &mmc->ios);
 	}
 }
@@ -1580,12 +1581,47 @@ void sdhci_set_uhs_signaling(struct sdhc
 }
 EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
 
+static bool sdhci_timing_has_preset(unsigned char timing)
+{
+	switch (timing) {
+	case MMC_TIMING_UHS_SDR12:
+	case MMC_TIMING_UHS_SDR25:
+	case MMC_TIMING_UHS_SDR50:
+	case MMC_TIMING_UHS_SDR104:
+	case MMC_TIMING_UHS_DDR50:
+	case MMC_TIMING_MMC_DDR52:
+		return true;
+	};
+	return false;
+}
+
+static bool sdhci_preset_needed(struct sdhci_host *host, unsigned char timing)
+{
+	return !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
+	       sdhci_timing_has_preset(timing);
+}
+
+static bool sdhci_presetable_values_change(struct sdhci_host *host, struct mmc_ios *ios)
+{
+	/*
+	 * Preset Values are: Driver Strength, Clock Generator and SDCLK/RCLK
+	 * Frequency. Check if preset values need to be enabled, or the Driver
+	 * Strength needs updating. Note, clock changes are handled separately.
+	 */
+	return !host->preset_enabled &&
+	       (sdhci_preset_needed(host, ios->timing) || host->drv_type != ios->drv_type);
+}
+
 static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
 	struct sdhci_host *host = mmc_priv(mmc);
+	bool reinit_uhs = host->reinit_uhs;
+	bool turning_on_clk = false;
 	unsigned long flags;
 	u8 ctrl;
 
+	host->reinit_uhs = false;
+
 	spin_lock_irqsave(&host->lock, flags);
 
 	if (host->flags & SDHCI_DEVICE_DEAD) {
@@ -1611,6 +1647,8 @@ static void sdhci_set_ios(struct mmc_hos
 		sdhci_enable_preset_value(host, false);
 
 	if (!ios->clock || ios->clock != host->clock) {
+		turning_on_clk = ios->clock && !host->clock;
+
 		host->ops->set_clock(host, ios->clock);
 		host->clock = ios->clock;
 
@@ -1637,6 +1675,17 @@ static void sdhci_set_ios(struct mmc_hos
 
 	host->ops->set_bus_width(host, ios->bus_width);
 
+	/*
+	 * Special case to avoid multiple clock changes during voltage
+	 * switching.
+	 */
+	if (!reinit_uhs &&
+	    turning_on_clk &&
+	    host->timing == ios->timing &&
+	    host->version >= SDHCI_SPEC_300 &&
+	    !sdhci_presetable_values_change(host, ios))
+		goto out;
+
 	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
 
 	if ((ios->timing == MMC_TIMING_SD_HS ||
@@ -1682,6 +1731,7 @@ static void sdhci_set_ios(struct mmc_hos
 			}
 
 			sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+			host->drv_type = ios->drv_type;
 		} else {
 			/*
 			 * According to SDHC Spec v3.00, if the Preset Value
@@ -1709,26 +1759,21 @@ static void sdhci_set_ios(struct mmc_hos
 		host->ops->set_uhs_signaling(host, ios->timing);
 		host->timing = ios->timing;
 
-		if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
-				((ios->timing == MMC_TIMING_UHS_SDR12) ||
-				 (ios->timing == MMC_TIMING_UHS_SDR25) ||
-				 (ios->timing == MMC_TIMING_UHS_SDR50) ||
-				 (ios->timing == MMC_TIMING_UHS_SDR104) ||
-				 (ios->timing == MMC_TIMING_UHS_DDR50) ||
-				 (ios->timing == MMC_TIMING_MMC_DDR52))) {
+		if (sdhci_preset_needed(host, ios->timing)) {
 			u16 preset;
 
 			sdhci_enable_preset_value(host, true);
 			preset = sdhci_get_preset_value(host);
 			ios->drv_type = FIELD_GET(SDHCI_PRESET_DRV_MASK,
 						  preset);
+			host->drv_type = ios->drv_type;
 		}
 
 		/* Re-enable SD Clock */
 		host->ops->set_clock(host, host->clock);
 	} else
 		sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-
+out:
 	/*
 	 * Some (ENE) controllers go apeshit on some ios operation,
 	 * signalling timeout and CRC errors even on CMD0. Resetting
@@ -2882,6 +2927,7 @@ int sdhci_resume_host(struct sdhci_host
 		sdhci_init(host, 0);
 		host->pwr = 0;
 		host->clock = 0;
+		host->reinit_uhs = true;
 		mmc->ops->set_ios(mmc, &mmc->ios);
 	} else {
 		sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER));
@@ -2946,6 +2992,7 @@ int sdhci_runtime_resume_host(struct sdh
 	/* Force clock and power re-program */
 	host->pwr = 0;
 	host->clock = 0;
+	host->reinit_uhs = true;
 	mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios);
 	mmc->ops->set_ios(mmc, &mmc->ios);
 
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -466,6 +466,8 @@ struct sdhci_host {
 
 	unsigned int clock;	/* Current clock (MHz) */
 	u8 pwr;			/* Current voltage */
+	u8 drv_type;		/* Current UHS-I driver type */
+	bool reinit_uhs;	/* Force UHS-related re-initialization */
 
 	bool runtime_suspended;	/* Host is runtime suspended */
 	bool bus_on;		/* Bus power prevents runtime suspend */



  parent reply	other threads:[~2022-12-12 13:54 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-12-12 13:19 [PATCH 4.9 00/31] 4.9.336-rc1 review Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 01/31] arm: dts: rockchip: fix node name for hym8563 rtc Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 02/31] ARM: dts: rockchip: fix ir-receiver node names Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 03/31] ARM: 9251/1: perf: Fix stacktraces for tracepoint events in THUMB2 kernels Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 04/31] ALSA: seq: Fix function prototype mismatch in snd_seq_expand_var_event Greg Kroah-Hartman
2022-12-12 13:19   ` Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 05/31] ASoC: soc-pcm: Add NULL check in BE reparenting Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 06/31] xen/netback: Ensure protocol headers dont fall in the non-linear area Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 07/31] xen/netback: do some code cleanup Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 08/31] xen/netback: dont call kfree_skb() with interrupts disabled Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 09/31] rcutorture: Automatically create initrd directory Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 10/31] mmc: sdhci: use FIELD_GET for preset value bit masks Greg Kroah-Hartman
2022-12-12 13:19 ` Greg Kroah-Hartman [this message]
2022-12-12 13:19 ` [PATCH 4.9 12/31] media: v4l2-dv-timings.c: fix too strict blanking sanity checks Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 13/31] HID: hid-lg4ff: Add check for empty lbuf Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 14/31] HID: core: fix shift-out-of-bounds in hid_report_raw_event Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 15/31] ieee802154: cc2520: Fix error return code in cc2520_hw_init() Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 16/31] gpio: amd8111: Fix PCI device reference count leak Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 17/31] e1000e: Fix TX dispatch condition Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 18/31] igb: Allocate MSI-X vector when testing Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 19/31] Bluetooth: 6LoWPAN: add missing hci_dev_put() in get_l2cap_conn() Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 20/31] mac802154: fix missing INIT_LIST_HEAD in ieee802154_if_add() Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 21/31] net: encx24j600: Add parentheses to fix precedence Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 22/31] net: encx24j600: Fix invalid logic in reading of MISTAT register Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 23/31] net: mvneta: Prevent out of bounds read in mvneta_config_rss() Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 24/31] NFC: nci: Bounds check struct nfc_target arrays Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 25/31] net: hisilicon: Fix potential use-after-free in hisi_femac_rx() Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 26/31] net: hisilicon: Fix potential use-after-free in hix5hd2_rx() Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 27/31] tipc: Fix potential OOB in tipc_link_proto_rcv() Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 28/31] ethernet: aeroflex: fix potential skb leak in greth_init_rings() Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 29/31] xen/netback: fix build warning Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 30/31] net: plip: dont call kfree_skb/dev_kfree_skb() under spin_lock_irq() Greg Kroah-Hartman
2022-12-12 13:19 ` [PATCH 4.9 31/31] net: mvneta: Fix an out of bounds check Greg Kroah-Hartman
2022-12-12 18:14 ` [PATCH 4.9 00/31] 4.9.336-rc1 review Pavel Machek
2022-12-12 20:11 ` Jon Hunter
2022-12-12 20:21 ` Slade Watkins
2022-12-12 20:34   ` Slade Watkins
2022-12-12 22:10 ` Florian Fainelli
2022-12-13  0:06 ` Shuah Khan
2022-12-13  0:23 ` Guenter Roeck
2022-12-13 12:09 ` Naresh Kamboju

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20221212130910.580294118@linuxfoundation.org \
    --to=gregkh@linuxfoundation.org \
    --cc=adrian.hunter@intel.com \
    --cc=patches@lists.linux.dev \
    --cc=stable@vger.kernel.org \
    --cc=ulf.hansson@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.