linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 00/11] mmc: sdhci-omap: Add UHS/HS200 mode support
@ 2018-03-07 13:20 Kishon Vijay Abraham I
  2018-03-07 13:20 ` [PATCH v3 01/11] mmc: sdhci-omap: Fix when capabilities are obtained from SDHCI_CAPABILITIES reg Kishon Vijay Abraham I
                   ` (12 more replies)
  0 siblings, 13 replies; 31+ messages in thread
From: Kishon Vijay Abraham I @ 2018-03-07 13:20 UTC (permalink / raw)
  To: Ulf Hansson, Tony Lindgren, Adrian Hunter
  Cc: Rob Herring, Mark Rutland, Russell King, kishon, linux-mmc,
	devicetree, linux-kernel, linux-omap, linux-arm-kernel

Add UHS/HS200 mode support in sdhci-omap. The programming sequence
for voltage switching, tuning is followed from AM572x TRM
http://www.ti.com/lit/ug/spruhz6i/spruhz6i.pdf
(Similar to all AM57x/DRA7x SoCs). The patch series also implements
workaround for errata published in
http://www.ti.com/lit/er/sprz429k/sprz429k.pdf

patches are created on top of
git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc.git next

Patches in v2 already applied to mmc -next are dropped from the
series.

Changes from v2:
*) Changed SW timeout logic as per Adrians's suggestion
*) Validated SDIO with the current patches (added a couple of fixes
   found while adding SDIO support).
*) Used soc_device_match() instead of pdata-quirks as per Tony's
   suggestions.

Changes from v1:
*) Only poll on DAT0 and DATI for card_busy status
*) Cleanup iodelay patch as suggested by Tony.
*) Added quirk to disable HW timeout
*) Use the existing data timer but program a relatively accurate
   SW timeout value (Impacts all platforms)
*) Fix a bug in sdhci which was using data_timer for non data line
   commands

Kishon Vijay Abraham I (11):
  mmc: sdhci-omap: Fix when capabilities are obtained from
    SDHCI_CAPABILITIES reg
  mmc: sdhci-omap: Remove setting ADMA capability in driver
  mmc: sdhci-omap: Workaround for Errata i843
  mmc: sdhci-omap: Invoke sdhci_get_of_property to read sdhci dt
    properties
  mmc: sdhci: Disable HS200 mode if controller can't support 1.8v
  mmc: sdhci: Add quirk to disable HW timeout
  mmc: sdhci: Program a relatively accurate SW timeout value
  mmc: sdhci-omap: Workaround for Errata i834
  dt-bindings: sdhci-omap: Add K2G specific binding
  mmc: sdhci-omap: Add support for MMC/SD controller in k2g SoC
  mmc: sdhci-omap: Add sdhci_omap specific ops for enable_sdio_irq

 .../devicetree/bindings/mmc/sdhci-omap.txt         |  2 +
 drivers/mmc/host/sdhci-omap.c                      | 78 +++++++++++++++++++---
 drivers/mmc/host/sdhci.c                           | 75 +++++++++++++++++----
 drivers/mmc/host/sdhci.h                           | 15 +++++
 4 files changed, 148 insertions(+), 22 deletions(-)

-- 
2.11.0

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

* [PATCH v3 01/11] mmc: sdhci-omap: Fix when capabilities are obtained from SDHCI_CAPABILITIES reg
  2018-03-07 13:20 [PATCH v3 00/11] mmc: sdhci-omap: Add UHS/HS200 mode support Kishon Vijay Abraham I
@ 2018-03-07 13:20 ` Kishon Vijay Abraham I
  2018-03-15 14:17   ` Adrian Hunter
  2018-03-07 13:20 ` [PATCH v3 02/11] mmc: sdhci-omap: Remove setting ADMA capability in driver Kishon Vijay Abraham I
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 31+ messages in thread
From: Kishon Vijay Abraham I @ 2018-03-07 13:20 UTC (permalink / raw)
  To: Ulf Hansson, Tony Lindgren, Adrian Hunter
  Cc: Rob Herring, Mark Rutland, Russell King, kishon, linux-mmc,
	devicetree, linux-kernel, linux-omap, linux-arm-kernel

sdhci_omap_config_iodelay_pinctrl_state() requires caps and caps2 to be
initialized (speed mode capabilities like UHS/HS200) before it is
invoked. While mmc_of_parse() initializes caps/caps2 if capabilities is
populated in device tree, it will remain uninitialized for capabilities
obtained from SDHCI_CAPABILITIES register.
Fix sdhci_omap_config_iodelay_pinctrl_state() to be used even while
getting the capabilities from SDHCI_CAPABILITIES register by invoking
sdhci_setup_host() before sdhci_omap_config_iodelay_pinctrl_state().

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/mmc/host/sdhci-omap.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c
index 1456abd5eeb9..3cce30584d2f 100644
--- a/drivers/mmc/host/sdhci-omap.c
+++ b/drivers/mmc/host/sdhci-omap.c
@@ -916,10 +916,6 @@ static int sdhci_omap_probe(struct platform_device *pdev)
 		goto err_put_sync;
 	}
 
-	ret = sdhci_omap_config_iodelay_pinctrl_state(omap_host);
-	if (ret)
-		goto err_put_sync;
-
 	host->mmc_host_ops.get_ro = mmc_gpio_get_ro;
 	host->mmc_host_ops.start_signal_voltage_switch =
 					sdhci_omap_start_signal_voltage_switch;
@@ -930,7 +926,15 @@ static int sdhci_omap_probe(struct platform_device *pdev)
 	sdhci_read_caps(host);
 	host->caps |= SDHCI_CAN_DO_ADMA2;
 
-	ret = sdhci_add_host(host);
+	ret = sdhci_setup_host(host);
+	if (ret)
+		goto err_put_sync;
+
+	ret = sdhci_omap_config_iodelay_pinctrl_state(omap_host);
+	if (ret)
+		goto err_put_sync;
+
+	ret = __sdhci_add_host(host);
 	if (ret)
 		goto err_put_sync;
 
-- 
2.11.0

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

* [PATCH v3 02/11] mmc: sdhci-omap: Remove setting ADMA capability in driver
  2018-03-07 13:20 [PATCH v3 00/11] mmc: sdhci-omap: Add UHS/HS200 mode support Kishon Vijay Abraham I
  2018-03-07 13:20 ` [PATCH v3 01/11] mmc: sdhci-omap: Fix when capabilities are obtained from SDHCI_CAPABILITIES reg Kishon Vijay Abraham I
@ 2018-03-07 13:20 ` Kishon Vijay Abraham I
  2018-03-15 14:18   ` Adrian Hunter
  2018-03-07 13:20 ` [PATCH v3 03/11] mmc: sdhci-omap: Workaround for Errata i843 Kishon Vijay Abraham I
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 31+ messages in thread
From: Kishon Vijay Abraham I @ 2018-03-07 13:20 UTC (permalink / raw)
  To: Ulf Hansson, Tony Lindgren, Adrian Hunter
  Cc: Rob Herring, Mark Rutland, Russell King, kishon, linux-mmc,
	devicetree, linux-kernel, linux-omap, linux-arm-kernel

sdhci can directly get ADMA capability from MMCHS_CAPA register.
Remove explicitly setting ADMA here as some instances might not have
ADMA enabled. (sdhci_read_caps() is also removed from here since
sdhci_setup_host() invokes it).

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/mmc/host/sdhci-omap.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c
index 3cce30584d2f..0c40b13fb67d 100644
--- a/drivers/mmc/host/sdhci-omap.c
+++ b/drivers/mmc/host/sdhci-omap.c
@@ -923,9 +923,6 @@ static int sdhci_omap_probe(struct platform_device *pdev)
 	host->mmc_host_ops.card_busy = sdhci_omap_card_busy;
 	host->mmc_host_ops.execute_tuning = sdhci_omap_execute_tuning;
 
-	sdhci_read_caps(host);
-	host->caps |= SDHCI_CAN_DO_ADMA2;
-
 	ret = sdhci_setup_host(host);
 	if (ret)
 		goto err_put_sync;
-- 
2.11.0

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

* [PATCH v3 03/11] mmc: sdhci-omap: Workaround for Errata i843
  2018-03-07 13:20 [PATCH v3 00/11] mmc: sdhci-omap: Add UHS/HS200 mode support Kishon Vijay Abraham I
  2018-03-07 13:20 ` [PATCH v3 01/11] mmc: sdhci-omap: Fix when capabilities are obtained from SDHCI_CAPABILITIES reg Kishon Vijay Abraham I
  2018-03-07 13:20 ` [PATCH v3 02/11] mmc: sdhci-omap: Remove setting ADMA capability in driver Kishon Vijay Abraham I
@ 2018-03-07 13:20 ` Kishon Vijay Abraham I
  2018-03-15 14:24   ` Adrian Hunter
  2018-03-07 13:20 ` [PATCH v3 04/11] mmc: sdhci-omap: Invoke sdhci_get_of_property to read sdhci dt properties Kishon Vijay Abraham I
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 31+ messages in thread
From: Kishon Vijay Abraham I @ 2018-03-07 13:20 UTC (permalink / raw)
  To: Ulf Hansson, Tony Lindgren, Adrian Hunter
  Cc: Rob Herring, Mark Rutland, Russell King, kishon, linux-mmc,
	devicetree, linux-kernel, linux-omap, linux-arm-kernel

Errata i843 in AM572x Sitara Processors Silicon Revision 2.0, 1.1
(SPRZ429K July 2014–Revised March 2017 [1]) mentions
PG 1.0/1.1 silicon has limitations w.r.t frequencies at which MMC1/2/3
can operate.

Use soc_device_match() to identify rev 1.0/1.1 silicon and
override mmc->f_max according to the errata workaround.
"max-frequency" dt property cannot be used since the device
tree is added for rev 2.0 silicon.

soc_device_match() is also used in order to get the IODelay values
for rev 1.0/1.1 silicon.

[1] -> http://www.ti.com/lit/er/sprz429k/sprz429k.pdf

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/mmc/host/sdhci-omap.c | 35 ++++++++++++++++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c
index 0c40b13fb67d..fbc20a4fbb23 100644
--- a/drivers/mmc/host/sdhci-omap.c
+++ b/drivers/mmc/host/sdhci-omap.c
@@ -26,6 +26,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 #include <linux/pinctrl/consumer.h>
+#include <linux/sys_soc.h>
 
 #include "sdhci-pltfm.h"
 
@@ -100,6 +101,7 @@ struct sdhci_omap_data {
 };
 
 struct sdhci_omap_host {
+	char			*version;
 	void __iomem		*base;
 	struct device		*dev;
 	struct	regulator	*pbias;
@@ -733,12 +735,21 @@ static struct pinctrl_state
 				  u32 *caps, u32 capmask)
 {
 	struct device *dev = omap_host->dev;
+	char *version = omap_host->version;
 	struct pinctrl_state *pinctrl_state = ERR_PTR(-ENODEV);
+	char str[20];
 
 	if (!(*caps & capmask))
 		goto ret;
 
-	pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, mode);
+	if (version) {
+		snprintf(str, 20, "%s-%s", mode, version);
+		pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, str);
+	}
+
+	if (IS_ERR(pinctrl_state))
+		pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, mode);
+
 	if (IS_ERR(pinctrl_state)) {
 		dev_err(dev, "no pinctrl state for %s mode", mode);
 		*caps &= ~capmask;
@@ -830,6 +841,16 @@ static int sdhci_omap_config_iodelay_pinctrl_state(struct sdhci_omap_host
 	return 0;
 }
 
+static const struct soc_device_attribute sdhci_omap_soc_devices[] = {
+	{
+		.machine = "DRA7[45]*",
+		.revision = "ES1.[01]",
+	},
+	{
+		/* sentinel */
+	}
+};
+
 static int sdhci_omap_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -841,6 +862,7 @@ static int sdhci_omap_probe(struct platform_device *pdev)
 	struct mmc_host *mmc;
 	const struct of_device_id *match;
 	struct sdhci_omap_data *data;
+	const struct soc_device_attribute *soc;
 
 	match = of_match_device(omap_sdhci_match, dev);
 	if (!match)
@@ -875,6 +897,17 @@ static int sdhci_omap_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_pltfm_free;
 
+	soc = soc_device_match(sdhci_omap_soc_devices);
+	if (soc) {
+		omap_host->version = "rev11";
+		if (!strcmp(dev_name(dev), "4809c000.mmc"))
+			mmc->f_max = 96000000;
+		if (!strcmp(dev_name(dev), "480b4000.mmc"))
+			mmc->f_max = 48000000;
+		if (!strcmp(dev_name(dev), "480ad000.mmc"))
+			mmc->f_max = 48000000;
+	}
+
 	pltfm_host->clk = devm_clk_get(dev, "fck");
 	if (IS_ERR(pltfm_host->clk)) {
 		ret = PTR_ERR(pltfm_host->clk);
-- 
2.11.0

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

* [PATCH v3 04/11] mmc: sdhci-omap: Invoke sdhci_get_of_property to read sdhci dt properties
  2018-03-07 13:20 [PATCH v3 00/11] mmc: sdhci-omap: Add UHS/HS200 mode support Kishon Vijay Abraham I
                   ` (2 preceding siblings ...)
  2018-03-07 13:20 ` [PATCH v3 03/11] mmc: sdhci-omap: Workaround for Errata i843 Kishon Vijay Abraham I
@ 2018-03-07 13:20 ` Kishon Vijay Abraham I
  2018-03-15 14:27   ` Adrian Hunter
  2018-03-07 13:20 ` [PATCH v3 05/11] mmc: sdhci: Disable HS200 mode if controller can't support 1.8v Kishon Vijay Abraham I
                   ` (8 subsequent siblings)
  12 siblings, 1 reply; 31+ messages in thread
From: Kishon Vijay Abraham I @ 2018-03-07 13:20 UTC (permalink / raw)
  To: Ulf Hansson, Tony Lindgren, Adrian Hunter
  Cc: Rob Herring, Mark Rutland, Russell King, kishon, linux-mmc,
	devicetree, linux-kernel, linux-omap, linux-arm-kernel

Invoke sdhci_get_of_property defined in sdhci-pltfm.c to read
sdhci specific properties from dt node.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/mmc/host/sdhci-omap.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c
index fbc20a4fbb23..314dbe4d7412 100644
--- a/drivers/mmc/host/sdhci-omap.c
+++ b/drivers/mmc/host/sdhci-omap.c
@@ -893,6 +893,7 @@ static int sdhci_omap_probe(struct platform_device *pdev)
 	host->ioaddr += offset;
 
 	mmc = host->mmc;
+	sdhci_get_of_property(pdev);
 	ret = mmc_of_parse(mmc);
 	if (ret)
 		goto err_pltfm_free;
-- 
2.11.0

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

* [PATCH v3 05/11] mmc: sdhci: Disable HS200 mode if controller can't support 1.8v
  2018-03-07 13:20 [PATCH v3 00/11] mmc: sdhci-omap: Add UHS/HS200 mode support Kishon Vijay Abraham I
                   ` (3 preceding siblings ...)
  2018-03-07 13:20 ` [PATCH v3 04/11] mmc: sdhci-omap: Invoke sdhci_get_of_property to read sdhci dt properties Kishon Vijay Abraham I
@ 2018-03-07 13:20 ` Kishon Vijay Abraham I
  2018-03-15 10:58   ` Adrian Hunter
  2018-03-07 13:20 ` [PATCH v3 06/11] mmc: sdhci: Add quirk to disable HW timeout Kishon Vijay Abraham I
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 31+ messages in thread
From: Kishon Vijay Abraham I @ 2018-03-07 13:20 UTC (permalink / raw)
  To: Ulf Hansson, Tony Lindgren, Adrian Hunter
  Cc: Rob Herring, Mark Rutland, Russell King, kishon, linux-mmc,
	devicetree, linux-kernel, linux-omap, linux-arm-kernel

Though MMC controller can indicate HS200 mode capability (by
using "mmc-hs200-1_8v" dt property), if the IO lines in the board
is connected to 3.3v supply, HS200 mode cannot be supported.
Such boards have "no-1-8-v" property in their dts file. Disable HS200
mode for boards which have "no-1-8-v" set.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/mmc/host/sdhci.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 2ededa7f43df..aa8b5ca0d1b0 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -3672,6 +3672,7 @@ int sdhci_setup_host(struct sdhci_host *host)
 	if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V) {
 		host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
 				 SDHCI_SUPPORT_DDR50);
+		mmc->caps2 &= ~MMC_CAP2_HS200;
 	}
 
 	/* Any UHS-I mode in caps implies SDR12 and SDR25 support. */
-- 
2.11.0

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

* [PATCH v3 06/11] mmc: sdhci: Add quirk to disable HW timeout
  2018-03-07 13:20 [PATCH v3 00/11] mmc: sdhci-omap: Add UHS/HS200 mode support Kishon Vijay Abraham I
                   ` (4 preceding siblings ...)
  2018-03-07 13:20 ` [PATCH v3 05/11] mmc: sdhci: Disable HS200 mode if controller can't support 1.8v Kishon Vijay Abraham I
@ 2018-03-07 13:20 ` Kishon Vijay Abraham I
  2018-03-15 11:26   ` Adrian Hunter
  2018-03-07 13:20 ` [PATCH v3 07/11] mmc: sdhci: Program a relatively accurate SW timeout value Kishon Vijay Abraham I
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 31+ messages in thread
From: Kishon Vijay Abraham I @ 2018-03-07 13:20 UTC (permalink / raw)
  To: Ulf Hansson, Tony Lindgren, Adrian Hunter
  Cc: Rob Herring, Mark Rutland, Russell King, kishon, linux-mmc,
	devicetree, linux-kernel, linux-omap, linux-arm-kernel

Add quirk to disable HW timeout if the requested timeout is more than
the maximum obtainable timeout.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/mmc/host/sdhci.c | 27 +++++++++++++++++++++------
 drivers/mmc/host/sdhci.h |  5 +++++
 2 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index aa8b5ca0d1b0..1dd117cbeb6e 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -767,12 +767,6 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
 			break;
 	}
 
-	if (count >= 0xF) {
-		DBG("Too large timeout 0x%x requested for CMD%d!\n",
-		    count, cmd->opcode);
-		count = 0xE;
-	}
-
 	return count;
 }
 
@@ -790,6 +784,16 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host)
 	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 }
 
+static void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable)
+{
+	if (enable)
+		host->ier |= SDHCI_INT_DATA_TIMEOUT;
+	else
+		host->ier &= ~SDHCI_INT_DATA_TIMEOUT;
+	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+}
+
 static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
 {
 	u8 count;
@@ -798,6 +802,17 @@ static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
 		host->ops->set_timeout(host, cmd);
 	} else {
 		count = sdhci_calc_timeout(host, cmd);
+		if (count >= 0xF &&
+		    host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT)
+			sdhci_set_data_timeout_irq(host, false);
+		else if (!(host->ier & SDHCI_INT_DATA_TIMEOUT))
+			sdhci_set_data_timeout_irq(host, true);
+
+		if (count >= 0xF) {
+			DBG("Too large timeout 0x%x requested for CMD%d!\n",
+			    count, cmd->opcode);
+			count = 0xE;
+		}
 		sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
 	}
 }
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index c95b0a4a7594..ff283ee08854 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -437,6 +437,11 @@ struct sdhci_host {
 #define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN		(1<<15)
 /* Controller has CRC in 136 bit Command Response */
 #define SDHCI_QUIRK2_RSP_136_HAS_CRC			(1<<16)
+/*
+ * Disable HW timeout if the requested timeout is more than the maximum
+ * obtainable timeout
+ */
+#define SDHCI_QUIRK2_DISABLE_HW_TIMEOUT			(1<<17)
 
 	int irq;		/* Device IRQ */
 	void __iomem *ioaddr;	/* Mapped address */
-- 
2.11.0

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

* [PATCH v3 07/11] mmc: sdhci: Program a relatively accurate SW timeout value
  2018-03-07 13:20 [PATCH v3 00/11] mmc: sdhci-omap: Add UHS/HS200 mode support Kishon Vijay Abraham I
                   ` (5 preceding siblings ...)
  2018-03-07 13:20 ` [PATCH v3 06/11] mmc: sdhci: Add quirk to disable HW timeout Kishon Vijay Abraham I
@ 2018-03-07 13:20 ` Kishon Vijay Abraham I
  2018-03-15 13:13   ` Adrian Hunter
  2018-03-07 13:20 ` [PATCH v3 08/11] mmc: sdhci-omap: Workaround for Errata i834 Kishon Vijay Abraham I
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 31+ messages in thread
From: Kishon Vijay Abraham I @ 2018-03-07 13:20 UTC (permalink / raw)
  To: Ulf Hansson, Tony Lindgren, Adrian Hunter
  Cc: Rob Herring, Mark Rutland, Russell King, kishon, linux-mmc,
	devicetree, linux-kernel, linux-omap, linux-arm-kernel

sdhci has a 10 second timeout to catch devices that stop responding.
Instead of programming 10 second arbitrary value, calculate the total time
it would take for the entire transfer to happen and program the timeout
value accordingly.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/mmc/host/sdhci.c | 47 ++++++++++++++++++++++++++++++++++++++++-------
 drivers/mmc/host/sdhci.h | 10 ++++++++++
 2 files changed, 50 insertions(+), 7 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 1dd117cbeb6e..baab67bfa39b 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -709,6 +709,36 @@ static u32 sdhci_sdma_address(struct sdhci_host *host)
 		return sg_dma_address(host->data->sg);
 }
 
+static void sdhci_calc_sw_timeout(struct sdhci_host *host,
+				  struct mmc_command *cmd,
+				  unsigned int target_timeout)
+{
+	struct mmc_data *data = cmd->data;
+	struct mmc_host *mmc = host->mmc;
+	u64 transfer_time;
+	struct mmc_ios *ios = &mmc->ios;
+	unsigned char bus_width = 1 << ios->bus_width;
+	unsigned int blksz;
+	unsigned int freq;
+
+	if (data) {
+		blksz = data->blksz;
+		freq = host->mmc->actual_clock ? : host->clock;
+		transfer_time = (u64)blksz * NSEC_PER_SEC * (8 / bus_width);
+		do_div(transfer_time, freq);
+		/* multiply by '2' to account for any unknowns */
+		transfer_time = transfer_time * 2;
+		/* calculate timeout for the entire data */
+		host->data_timeout = (data->blocks * ((target_timeout *
+						       NSEC_PER_USEC) +
+						       transfer_time));
+	} else {
+		host->data_timeout = (u64)target_timeout * NSEC_PER_USEC;
+	}
+
+	host->data_timeout += MMC_CMD_TRANSFER_TIME;
+}
+
 static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
 {
 	u8 count;
@@ -766,6 +796,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
 		if (count >= 0xF)
 			break;
 	}
+	sdhci_calc_sw_timeout(host, cmd, target_timeout);
 
 	return count;
 }
@@ -1175,13 +1206,6 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 		mdelay(1);
 	}
 
-	timeout = jiffies;
-	if (!cmd->data && cmd->busy_timeout > 9000)
-		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
-	else
-		timeout += 10 * HZ;
-	sdhci_mod_timer(host, cmd->mrq, timeout);
-
 	host->cmd = cmd;
 	if (sdhci_data_line_cmd(cmd)) {
 		WARN_ON(host->data_cmd);
@@ -1221,6 +1245,15 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 	    cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
 		flags |= SDHCI_CMD_DATA;
 
+	timeout = jiffies;
+	if (host->data_timeout > 0) {
+		timeout += nsecs_to_jiffies(host->data_timeout);
+		host->data_timeout = 0;
+	} else {
+		timeout += 10 * HZ;
+	}
+	sdhci_mod_timer(host, cmd->mrq, timeout);
+
 	sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
 }
 EXPORT_SYMBOL_GPL(sdhci_send_command);
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index ff283ee08854..29b242fd17de 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -332,6 +332,14 @@ struct sdhci_adma2_64_desc {
 /* Allow for a a command request and a data request at the same time */
 #define SDHCI_MAX_MRQS		2
 
+/*
+ * 48bit command and 136 bit response in 100KHz clock could take upto 2.48ms.
+ * However since the start time of the command, the time between
+ * command and response, and the time between response and start of data is
+ * not known, set the command transfer time to 10ms.
+ */
+#define MMC_CMD_TRANSFER_TIME	(10 * NSEC_PER_MSEC) /* max 10 ms */
+
 enum sdhci_cookie {
 	COOKIE_UNMAPPED,
 	COOKIE_PRE_MAPPED,	/* mapped by sdhci_pre_req() */
@@ -555,6 +563,8 @@ struct sdhci_host {
 	/* Host SDMA buffer boundary. */
 	u32			sdma_boundary;
 
+	u64			data_timeout;
+
 	unsigned long private[0] ____cacheline_aligned;
 };
 
-- 
2.11.0

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

* [PATCH v3 08/11] mmc: sdhci-omap: Workaround for Errata i834
  2018-03-07 13:20 [PATCH v3 00/11] mmc: sdhci-omap: Add UHS/HS200 mode support Kishon Vijay Abraham I
                   ` (6 preceding siblings ...)
  2018-03-07 13:20 ` [PATCH v3 07/11] mmc: sdhci: Program a relatively accurate SW timeout value Kishon Vijay Abraham I
@ 2018-03-07 13:20 ` Kishon Vijay Abraham I
  2018-03-07 13:20 ` [PATCH v3 09/11] dt-bindings: sdhci-omap: Add K2G specific binding Kishon Vijay Abraham I
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 31+ messages in thread
From: Kishon Vijay Abraham I @ 2018-03-07 13:20 UTC (permalink / raw)
  To: Ulf Hansson, Tony Lindgren, Adrian Hunter
  Cc: Rob Herring, Mark Rutland, Russell King, kishon, linux-mmc,
	devicetree, linux-kernel, linux-omap, linux-arm-kernel

Errata i834 in AM572x Sitara Processors Silicon Revision 2.0, 1.1
(SPRZ429K July 2014–Revised March 2017 [1]) mentions the maximum
obtainable timeout through MMC host controller is 700ms. And for
commands taking longer than 700ms, hardware timeout should be
disabled and software timeout should be used.

The workaround for Errata i834 can be achieved by adding
SDHCI_QUIRK2_DISABLE_HW_TIMEOUT quirk in sdhci-omap.

[1] -> http://www.ti.com/lit/er/sprz429k/sprz429k.pdf

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/mmc/host/sdhci-omap.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c
index 314dbe4d7412..87206d2aaa77 100644
--- a/drivers/mmc/host/sdhci-omap.c
+++ b/drivers/mmc/host/sdhci-omap.c
@@ -715,7 +715,8 @@ static const struct sdhci_pltfm_data sdhci_omap_pdata = {
 		  SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
 	.quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN |
 		   SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
-		   SDHCI_QUIRK2_RSP_136_HAS_CRC,
+		   SDHCI_QUIRK2_RSP_136_HAS_CRC |
+		   SDHCI_QUIRK2_DISABLE_HW_TIMEOUT,
 	.ops = &sdhci_omap_ops,
 };
 
-- 
2.11.0

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

* [PATCH v3 09/11] dt-bindings: sdhci-omap: Add K2G specific binding
  2018-03-07 13:20 [PATCH v3 00/11] mmc: sdhci-omap: Add UHS/HS200 mode support Kishon Vijay Abraham I
                   ` (7 preceding siblings ...)
  2018-03-07 13:20 ` [PATCH v3 08/11] mmc: sdhci-omap: Workaround for Errata i834 Kishon Vijay Abraham I
@ 2018-03-07 13:20 ` Kishon Vijay Abraham I
  2018-03-07 13:20 ` [PATCH v3 10/11] mmc: sdhci-omap: Add support for MMC/SD controller in k2g SoC Kishon Vijay Abraham I
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 31+ messages in thread
From: Kishon Vijay Abraham I @ 2018-03-07 13:20 UTC (permalink / raw)
  To: Ulf Hansson, Tony Lindgren, Adrian Hunter
  Cc: Rob Herring, Mark Rutland, Russell King, kishon, linux-mmc,
	devicetree, linux-kernel, linux-omap, linux-arm-kernel

Add binding for the TI's sdhci-omap controller present in K2G.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---
 Documentation/devicetree/bindings/mmc/sdhci-omap.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/mmc/sdhci-omap.txt b/Documentation/devicetree/bindings/mmc/sdhci-omap.txt
index 51775a372c06..8d09b837e350 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-omap.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-omap.txt
@@ -4,7 +4,9 @@ Refer to mmc.txt for standard MMC bindings.
 
 Required properties:
 - compatible: Should be "ti,dra7-sdhci" for DRA7 and DRA72 controllers
+	      Should be "ti,k2g-sdhci" for K2G
 - ti,hwmods: Must be "mmc<n>", <n> is controller instance starting 1
+	     (Not required for K2G).
 
 Example:
 	mmc1: mmc@4809c000 {
-- 
2.11.0

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

* [PATCH v3 10/11] mmc: sdhci-omap: Add support for MMC/SD controller in k2g SoC
  2018-03-07 13:20 [PATCH v3 00/11] mmc: sdhci-omap: Add UHS/HS200 mode support Kishon Vijay Abraham I
                   ` (8 preceding siblings ...)
  2018-03-07 13:20 ` [PATCH v3 09/11] dt-bindings: sdhci-omap: Add K2G specific binding Kishon Vijay Abraham I
@ 2018-03-07 13:20 ` Kishon Vijay Abraham I
  2018-03-07 13:20 ` [PATCH v3 11/11] mmc: sdhci-omap: Add sdhci_omap specific ops for enable_sdio_irq Kishon Vijay Abraham I
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 31+ messages in thread
From: Kishon Vijay Abraham I @ 2018-03-07 13:20 UTC (permalink / raw)
  To: Ulf Hansson, Tony Lindgren, Adrian Hunter
  Cc: Rob Herring, Mark Rutland, Russell King, kishon, linux-mmc,
	devicetree, linux-kernel, linux-omap, linux-arm-kernel

Add support for the new compatible added specifically to support
k2g's MMC/SD controller.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/host/sdhci-omap.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c
index 87206d2aaa77..14dd51b51b41 100644
--- a/drivers/mmc/host/sdhci-omap.c
+++ b/drivers/mmc/host/sdhci-omap.c
@@ -720,6 +720,10 @@ static const struct sdhci_pltfm_data sdhci_omap_pdata = {
 	.ops = &sdhci_omap_ops,
 };
 
+static const struct sdhci_omap_data k2g_data = {
+	.offset = 0x200,
+};
+
 static const struct sdhci_omap_data dra7_data = {
 	.offset = 0x200,
 	.flags	= SDHCI_OMAP_REQUIRE_IODELAY,
@@ -727,6 +731,7 @@ static const struct sdhci_omap_data dra7_data = {
 
 static const struct of_device_id omap_sdhci_match[] = {
 	{ .compatible = "ti,dra7-sdhci", .data = &dra7_data },
+	{ .compatible = "ti,k2g-sdhci", .data = &k2g_data },
 	{},
 };
 MODULE_DEVICE_TABLE(of, omap_sdhci_match);
-- 
2.11.0

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

* [PATCH v3 11/11] mmc: sdhci-omap: Add sdhci_omap specific ops for enable_sdio_irq
  2018-03-07 13:20 [PATCH v3 00/11] mmc: sdhci-omap: Add UHS/HS200 mode support Kishon Vijay Abraham I
                   ` (9 preceding siblings ...)
  2018-03-07 13:20 ` [PATCH v3 10/11] mmc: sdhci-omap: Add support for MMC/SD controller in k2g SoC Kishon Vijay Abraham I
@ 2018-03-07 13:20 ` Kishon Vijay Abraham I
  2018-03-15 14:34   ` Adrian Hunter
  2018-03-07 15:12 ` [PATCH v3 00/11] mmc: sdhci-omap: Add UHS/HS200 mode support Tony Lindgren
  2018-03-15  8:47 ` Ulf Hansson
  12 siblings, 1 reply; 31+ messages in thread
From: Kishon Vijay Abraham I @ 2018-03-07 13:20 UTC (permalink / raw)
  To: Ulf Hansson, Tony Lindgren, Adrian Hunter
  Cc: Rob Herring, Mark Rutland, Russell King, kishon, linux-mmc,
	devicetree, linux-kernel, linux-omap, linux-arm-kernel

Add sdhci_omap_enable_sdio_irq to set CTPL and CLKEXTFREE bits in
MMCHS_CON register required to detect asynchronous card interrupt
on DAT[1].

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/mmc/host/sdhci-omap.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c
index 14dd51b51b41..8ceb3956b211 100644
--- a/drivers/mmc/host/sdhci-omap.c
+++ b/drivers/mmc/host/sdhci-omap.c
@@ -36,6 +36,7 @@
 #define CON_DDR			BIT(19)
 #define CON_CLKEXTFREE		BIT(16)
 #define CON_PADEN		BIT(15)
+#define CON_CTPL		BIT(11)
 #define CON_INIT		BIT(1)
 #define CON_OD			BIT(0)
 
@@ -226,6 +227,23 @@ static void sdhci_omap_conf_bus_power(struct sdhci_omap_host *omap_host,
 	}
 }
 
+static void sdhci_omap_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
+	u32 reg;
+
+	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON);
+	if (enable)
+		reg |= (CON_CTPL | CON_CLKEXTFREE);
+	else
+		reg &= ~(CON_CTPL | CON_CLKEXTFREE);
+	sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg);
+
+	sdhci_enable_sdio_irq(mmc, enable);
+}
+
 static inline void sdhci_omap_set_dll(struct sdhci_omap_host *omap_host,
 				      int count)
 {
@@ -962,6 +980,7 @@ static int sdhci_omap_probe(struct platform_device *pdev)
 	host->mmc_host_ops.set_ios = sdhci_omap_set_ios;
 	host->mmc_host_ops.card_busy = sdhci_omap_card_busy;
 	host->mmc_host_ops.execute_tuning = sdhci_omap_execute_tuning;
+	host->mmc_host_ops.enable_sdio_irq = sdhci_omap_enable_sdio_irq;
 
 	ret = sdhci_setup_host(host);
 	if (ret)
-- 
2.11.0

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

* Re: [PATCH v3 00/11] mmc: sdhci-omap: Add UHS/HS200 mode support
  2018-03-07 13:20 [PATCH v3 00/11] mmc: sdhci-omap: Add UHS/HS200 mode support Kishon Vijay Abraham I
                   ` (10 preceding siblings ...)
  2018-03-07 13:20 ` [PATCH v3 11/11] mmc: sdhci-omap: Add sdhci_omap specific ops for enable_sdio_irq Kishon Vijay Abraham I
@ 2018-03-07 15:12 ` Tony Lindgren
  2018-03-15  8:47 ` Ulf Hansson
  12 siblings, 0 replies; 31+ messages in thread
From: Tony Lindgren @ 2018-03-07 15:12 UTC (permalink / raw)
  To: Kishon Vijay Abraham I
  Cc: Ulf Hansson, Adrian Hunter, Rob Herring, Mark Rutland,
	Russell King, linux-mmc, devicetree, linux-kernel, linux-omap,
	linux-arm-kernel

* Kishon Vijay Abraham I <kishon@ti.com> [180307 13:21]:
> Changes from v2:
> *) Used soc_device_match() instead of pdata-quirks as per Tony's
>    suggestions.

Looks good to me now thanks. For the whole series:

Acked-by: Tony Lindgren <tony@atomide.com>

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

* Re: [PATCH v3 00/11] mmc: sdhci-omap: Add UHS/HS200 mode support
  2018-03-07 13:20 [PATCH v3 00/11] mmc: sdhci-omap: Add UHS/HS200 mode support Kishon Vijay Abraham I
                   ` (11 preceding siblings ...)
  2018-03-07 15:12 ` [PATCH v3 00/11] mmc: sdhci-omap: Add UHS/HS200 mode support Tony Lindgren
@ 2018-03-15  8:47 ` Ulf Hansson
  2018-03-15  8:52   ` Adrian Hunter
  12 siblings, 1 reply; 31+ messages in thread
From: Ulf Hansson @ 2018-03-15  8:47 UTC (permalink / raw)
  To: Kishon Vijay Abraham I
  Cc: Tony Lindgren, Adrian Hunter, Rob Herring, Mark Rutland,
	Russell King, linux-mmc, devicetree, Linux Kernel Mailing List,
	linux-omap, Linux ARM

On 7 March 2018 at 14:20, Kishon Vijay Abraham I <kishon@ti.com> wrote:
> Add UHS/HS200 mode support in sdhci-omap. The programming sequence
> for voltage switching, tuning is followed from AM572x TRM
> http://www.ti.com/lit/ug/spruhz6i/spruhz6i.pdf
> (Similar to all AM57x/DRA7x SoCs). The patch series also implements
> workaround for errata published in
> http://www.ti.com/lit/er/sprz429k/sprz429k.pdf
>
> patches are created on top of
> git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc.git next
>
> Patches in v2 already applied to mmc -next are dropped from the
> series.
>
> Changes from v2:
> *) Changed SW timeout logic as per Adrians's suggestion
> *) Validated SDIO with the current patches (added a couple of fixes
>    found while adding SDIO support).
> *) Used soc_device_match() instead of pdata-quirks as per Tony's
>    suggestions.
>
> Changes from v1:
> *) Only poll on DAT0 and DATI for card_busy status
> *) Cleanup iodelay patch as suggested by Tony.
> *) Added quirk to disable HW timeout
> *) Use the existing data timer but program a relatively accurate
>    SW timeout value (Impacts all platforms)
> *) Fix a bug in sdhci which was using data_timer for non data line
>    commands
>
> Kishon Vijay Abraham I (11):
>   mmc: sdhci-omap: Fix when capabilities are obtained from
>     SDHCI_CAPABILITIES reg
>   mmc: sdhci-omap: Remove setting ADMA capability in driver
>   mmc: sdhci-omap: Workaround for Errata i843
>   mmc: sdhci-omap: Invoke sdhci_get_of_property to read sdhci dt
>     properties
>   mmc: sdhci: Disable HS200 mode if controller can't support 1.8v
>   mmc: sdhci: Add quirk to disable HW timeout
>   mmc: sdhci: Program a relatively accurate SW timeout value
>   mmc: sdhci-omap: Workaround for Errata i834
>   dt-bindings: sdhci-omap: Add K2G specific binding
>   mmc: sdhci-omap: Add support for MMC/SD controller in k2g SoC
>   mmc: sdhci-omap: Add sdhci_omap specific ops for enable_sdio_irq
>
>  .../devicetree/bindings/mmc/sdhci-omap.txt         |  2 +
>  drivers/mmc/host/sdhci-omap.c                      | 78 +++++++++++++++++++---
>  drivers/mmc/host/sdhci.c                           | 75 +++++++++++++++++----
>  drivers/mmc/host/sdhci.h                           | 15 +++++
>  4 files changed, 148 insertions(+), 22 deletions(-)
>
> --
> 2.11.0
>

Overall this looks good to me, however it seems like we need to give
Adrian a little more time to comment.

Kind regards
Uffe

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

* Re: [PATCH v3 00/11] mmc: sdhci-omap: Add UHS/HS200 mode support
  2018-03-15  8:47 ` Ulf Hansson
@ 2018-03-15  8:52   ` Adrian Hunter
  2018-03-15 10:02     ` Kishon Vijay Abraham I
  0 siblings, 1 reply; 31+ messages in thread
From: Adrian Hunter @ 2018-03-15  8:52 UTC (permalink / raw)
  To: Ulf Hansson, Kishon Vijay Abraham I
  Cc: Tony Lindgren, Rob Herring, Mark Rutland, Russell King,
	linux-mmc, devicetree, Linux Kernel Mailing List, linux-omap,
	Linux ARM

On 15/03/18 10:47, Ulf Hansson wrote:
> On 7 March 2018 at 14:20, Kishon Vijay Abraham I <kishon@ti.com> wrote:
>> Add UHS/HS200 mode support in sdhci-omap. The programming sequence
>> for voltage switching, tuning is followed from AM572x TRM
>> http://www.ti.com/lit/ug/spruhz6i/spruhz6i.pdf
>> (Similar to all AM57x/DRA7x SoCs). The patch series also implements
>> workaround for errata published in
>> http://www.ti.com/lit/er/sprz429k/sprz429k.pdf
>>
>> patches are created on top of
>> git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc.git next
>>
>> Patches in v2 already applied to mmc -next are dropped from the
>> series.
>>
>> Changes from v2:
>> *) Changed SW timeout logic as per Adrians's suggestion
>> *) Validated SDIO with the current patches (added a couple of fixes
>>    found while adding SDIO support).
>> *) Used soc_device_match() instead of pdata-quirks as per Tony's
>>    suggestions.
>>
>> Changes from v1:
>> *) Only poll on DAT0 and DATI for card_busy status
>> *) Cleanup iodelay patch as suggested by Tony.
>> *) Added quirk to disable HW timeout
>> *) Use the existing data timer but program a relatively accurate
>>    SW timeout value (Impacts all platforms)
>> *) Fix a bug in sdhci which was using data_timer for non data line
>>    commands
>>
>> Kishon Vijay Abraham I (11):
>>   mmc: sdhci-omap: Fix when capabilities are obtained from
>>     SDHCI_CAPABILITIES reg
>>   mmc: sdhci-omap: Remove setting ADMA capability in driver
>>   mmc: sdhci-omap: Workaround for Errata i843
>>   mmc: sdhci-omap: Invoke sdhci_get_of_property to read sdhci dt
>>     properties
>>   mmc: sdhci: Disable HS200 mode if controller can't support 1.8v
>>   mmc: sdhci: Add quirk to disable HW timeout
>>   mmc: sdhci: Program a relatively accurate SW timeout value
>>   mmc: sdhci-omap: Workaround for Errata i834
>>   dt-bindings: sdhci-omap: Add K2G specific binding
>>   mmc: sdhci-omap: Add support for MMC/SD controller in k2g SoC
>>   mmc: sdhci-omap: Add sdhci_omap specific ops for enable_sdio_irq
>>
>>  .../devicetree/bindings/mmc/sdhci-omap.txt         |  2 +
>>  drivers/mmc/host/sdhci-omap.c                      | 78 +++++++++++++++++++---
>>  drivers/mmc/host/sdhci.c                           | 75 +++++++++++++++++----
>>  drivers/mmc/host/sdhci.h                           | 15 +++++
>>  4 files changed, 148 insertions(+), 22 deletions(-)
>>
>> --
>> 2.11.0
>>
> 
> Overall this looks good to me, however it seems like we need to give
> Adrian a little more time to comment.
> 

I will try to look at it today.

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

* Re: [PATCH v3 00/11] mmc: sdhci-omap: Add UHS/HS200 mode support
  2018-03-15  8:52   ` Adrian Hunter
@ 2018-03-15 10:02     ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 31+ messages in thread
From: Kishon Vijay Abraham I @ 2018-03-15 10:02 UTC (permalink / raw)
  To: Adrian Hunter, Ulf Hansson
  Cc: Tony Lindgren, Rob Herring, Mark Rutland, Russell King,
	linux-mmc, devicetree, Linux Kernel Mailing List, linux-omap,
	Linux ARM



On Thursday 15 March 2018 02:22 PM, Adrian Hunter wrote:
> On 15/03/18 10:47, Ulf Hansson wrote:
>> On 7 March 2018 at 14:20, Kishon Vijay Abraham I <kishon@ti.com> wrote:
>>> Add UHS/HS200 mode support in sdhci-omap. The programming sequence
>>> for voltage switching, tuning is followed from AM572x TRM
>>> http://www.ti.com/lit/ug/spruhz6i/spruhz6i.pdf
>>> (Similar to all AM57x/DRA7x SoCs). The patch series also implements
>>> workaround for errata published in
>>> http://www.ti.com/lit/er/sprz429k/sprz429k.pdf
>>>
>>> patches are created on top of
>>> git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc.git next
>>>
>>> Patches in v2 already applied to mmc -next are dropped from the
>>> series.
>>>
>>> Changes from v2:
>>> *) Changed SW timeout logic as per Adrians's suggestion
>>> *) Validated SDIO with the current patches (added a couple of fixes
>>>    found while adding SDIO support).
>>> *) Used soc_device_match() instead of pdata-quirks as per Tony's
>>>    suggestions.
>>>
>>> Changes from v1:
>>> *) Only poll on DAT0 and DATI for card_busy status
>>> *) Cleanup iodelay patch as suggested by Tony.
>>> *) Added quirk to disable HW timeout
>>> *) Use the existing data timer but program a relatively accurate
>>>    SW timeout value (Impacts all platforms)
>>> *) Fix a bug in sdhci which was using data_timer for non data line
>>>    commands
>>>
>>> Kishon Vijay Abraham I (11):
>>>   mmc: sdhci-omap: Fix when capabilities are obtained from
>>>     SDHCI_CAPABILITIES reg
>>>   mmc: sdhci-omap: Remove setting ADMA capability in driver
>>>   mmc: sdhci-omap: Workaround for Errata i843
>>>   mmc: sdhci-omap: Invoke sdhci_get_of_property to read sdhci dt
>>>     properties
>>>   mmc: sdhci: Disable HS200 mode if controller can't support 1.8v
>>>   mmc: sdhci: Add quirk to disable HW timeout
>>>   mmc: sdhci: Program a relatively accurate SW timeout value
>>>   mmc: sdhci-omap: Workaround for Errata i834
>>>   dt-bindings: sdhci-omap: Add K2G specific binding
>>>   mmc: sdhci-omap: Add support for MMC/SD controller in k2g SoC
>>>   mmc: sdhci-omap: Add sdhci_omap specific ops for enable_sdio_irq
>>>
>>>  .../devicetree/bindings/mmc/sdhci-omap.txt         |  2 +
>>>  drivers/mmc/host/sdhci-omap.c                      | 78 +++++++++++++++++++---
>>>  drivers/mmc/host/sdhci.c                           | 75 +++++++++++++++++----
>>>  drivers/mmc/host/sdhci.h                           | 15 +++++
>>>  4 files changed, 148 insertions(+), 22 deletions(-)
>>>
>>> --
>>> 2.11.0
>>>
>>
>> Overall this looks good to me, however it seems like we need to give
>> Adrian a little more time to comment.
>>
> 
> I will try to look at it today.

sure, thanks!

-Kishon

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

* Re: [PATCH v3 05/11] mmc: sdhci: Disable HS200 mode if controller can't support 1.8v
  2018-03-07 13:20 ` [PATCH v3 05/11] mmc: sdhci: Disable HS200 mode if controller can't support 1.8v Kishon Vijay Abraham I
@ 2018-03-15 10:58   ` Adrian Hunter
  0 siblings, 0 replies; 31+ messages in thread
From: Adrian Hunter @ 2018-03-15 10:58 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Ulf Hansson, Tony Lindgren
  Cc: Rob Herring, Mark Rutland, Russell King, linux-mmc, devicetree,
	linux-kernel, linux-omap, linux-arm-kernel

On 07/03/18 15:20, Kishon Vijay Abraham I wrote:
> Though MMC controller can indicate HS200 mode capability (by
> using "mmc-hs200-1_8v" dt property), if the IO lines in the board
> is connected to 3.3v supply, HS200 mode cannot be supported.
> Such boards have "no-1-8-v" property in their dts file. Disable HS200
> mode for boards which have "no-1-8-v" set.
> 
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> ---
>  drivers/mmc/host/sdhci.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index 2ededa7f43df..aa8b5ca0d1b0 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -3672,6 +3672,7 @@ int sdhci_setup_host(struct sdhci_host *host)
>  	if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V) {
>  		host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
>  				 SDHCI_SUPPORT_DDR50);
> +		mmc->caps2 &= ~MMC_CAP2_HS200;

Pedantically, shouldn't that be:

	~(MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS400_1_8V)

We have MMC_CAP2_HSX00_1_2V so maybe we should add:

	#define MMC_CAP2_HSX00_1_8V	(MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS400_1_8V)

And then

		mmc->caps2 &= ~MMC_CAP2_HSX00_1_8V;

>  	}
>  
>  	/* Any UHS-I mode in caps implies SDR12 and SDR25 support. */
> 

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

* Re: [PATCH v3 06/11] mmc: sdhci: Add quirk to disable HW timeout
  2018-03-07 13:20 ` [PATCH v3 06/11] mmc: sdhci: Add quirk to disable HW timeout Kishon Vijay Abraham I
@ 2018-03-15 11:26   ` Adrian Hunter
  0 siblings, 0 replies; 31+ messages in thread
From: Adrian Hunter @ 2018-03-15 11:26 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Ulf Hansson, Tony Lindgren
  Cc: Rob Herring, Mark Rutland, Russell King, linux-mmc, devicetree,
	linux-kernel, linux-omap, linux-arm-kernel

On 07/03/18 15:20, Kishon Vijay Abraham I wrote:
> Add quirk to disable HW timeout if the requested timeout is more than
> the maximum obtainable timeout.
> 
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> ---
>  drivers/mmc/host/sdhci.c | 27 +++++++++++++++++++++------
>  drivers/mmc/host/sdhci.h |  5 +++++
>  2 files changed, 26 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index aa8b5ca0d1b0..1dd117cbeb6e 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -767,12 +767,6 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
>  			break;
>  	}
>  
> -	if (count >= 0xF) {
> -		DBG("Too large timeout 0x%x requested for CMD%d!\n",
> -		    count, cmd->opcode);
> -		count = 0xE;
> -	}
> -
>  	return count;
>  }
>  
> @@ -790,6 +784,16 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host)
>  	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
>  }
>  
> +static void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable)
> +{
> +	if (enable)
> +		host->ier |= SDHCI_INT_DATA_TIMEOUT;
> +	else
> +		host->ier &= ~SDHCI_INT_DATA_TIMEOUT;
> +	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
> +	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
> +}
> +
>  static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
>  {
>  	u8 count;
> @@ -798,6 +802,17 @@ static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
>  		host->ops->set_timeout(host, cmd);
>  	} else {
>  		count = sdhci_calc_timeout(host, cmd);
> +		if (count >= 0xF &&
> +		    host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT)
> +			sdhci_set_data_timeout_irq(host, false);
> +		else if (!(host->ier & SDHCI_INT_DATA_TIMEOUT))
> +			sdhci_set_data_timeout_irq(host, true);
> +
> +		if (count >= 0xF) {
> +			DBG("Too large timeout 0x%x requested for CMD%d!\n",
> +			    count, cmd->opcode);
> +			count = 0xE;
> +		}
>  		sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
>  	}
>  }

I guess I misunderstood you, but we need to cater for
open-ended busy timeouts (i.e. busy_timeout==0) and broken
timeout (i.e. SDHCI_QUIRK_BROKEN_TIMEOUT_VAL and
SDHCI_QUIRK2_DISABLE_HW_TIMEOUT together mean never use the
HW timeout)

So maybe like this:

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index aa8b5ca0d1b0..a358eb5c5f98 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -709,12 +709,15 @@ static u32 sdhci_sdma_address(struct sdhci_host *host)
 		return sg_dma_address(host->data->sg);
 }
 
-static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
+static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd,
+			     bool *too_big)
 {
 	u8 count;
 	struct mmc_data *data = cmd->data;
 	unsigned target_timeout, current_timeout;
 
+	*too_big = true;
+
 	/*
 	 * If the host controller provides us with an incorrect timeout
 	 * value, just skip the check and use 0xE.  The hardware may take
@@ -768,9 +771,12 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
 	}
 
 	if (count >= 0xF) {
-		DBG("Too large timeout 0x%x requested for CMD%d!\n",
-		    count, cmd->opcode);
+		if (!(host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT))
+			DBG("Too large timeout 0x%x requested for CMD%d!\n",
+			    count, cmd->opcode);
 		count = 0xE;
+	} else {
+		*too_big = false;
 	}
 
 	return count;
@@ -790,6 +796,16 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host)
 	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 }
 
+static void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable)
+{
+	if (enable)
+		host->ier |= SDHCI_INT_DATA_TIMEOUT;
+	else
+		host->ier &= ~SDHCI_INT_DATA_TIMEOUT;
+	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+}
+
 static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
 {
 	u8 count;
@@ -797,7 +813,17 @@ static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
 	if (host->ops->set_timeout) {
 		host->ops->set_timeout(host, cmd);
 	} else {
-		count = sdhci_calc_timeout(host, cmd);
+		bool too_big = false;
+
+		count = sdhci_calc_timeout(host, cmd, &too_big);
+
+		if (too_big &&
+		    host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT) {
+			sdhci_set_data_timeout_irq(host, false);
+		} else if (!(host->ier & SDHCI_INT_DATA_TIMEOUT)) {
+			sdhci_set_data_timeout_irq(host, true);
+		}
+
 		sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
 	}
 }

> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> index c95b0a4a7594..ff283ee08854 100644
> --- a/drivers/mmc/host/sdhci.h
> +++ b/drivers/mmc/host/sdhci.h
> @@ -437,6 +437,11 @@ struct sdhci_host {
>  #define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN		(1<<15)
>  /* Controller has CRC in 136 bit Command Response */
>  #define SDHCI_QUIRK2_RSP_136_HAS_CRC			(1<<16)
> +/*
> + * Disable HW timeout if the requested timeout is more than the maximum
> + * obtainable timeout
> + */
> +#define SDHCI_QUIRK2_DISABLE_HW_TIMEOUT			(1<<17)
>  
>  	int irq;		/* Device IRQ */
>  	void __iomem *ioaddr;	/* Mapped address */
> 

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

* Re: [PATCH v3 07/11] mmc: sdhci: Program a relatively accurate SW timeout value
  2018-03-07 13:20 ` [PATCH v3 07/11] mmc: sdhci: Program a relatively accurate SW timeout value Kishon Vijay Abraham I
@ 2018-03-15 13:13   ` Adrian Hunter
  2018-03-16  6:29     ` Kishon Vijay Abraham I
  0 siblings, 1 reply; 31+ messages in thread
From: Adrian Hunter @ 2018-03-15 13:13 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Ulf Hansson, Tony Lindgren
  Cc: Rob Herring, Mark Rutland, Russell King, linux-mmc, devicetree,
	linux-kernel, linux-omap, linux-arm-kernel

On 07/03/18 15:20, Kishon Vijay Abraham I wrote:
> sdhci has a 10 second timeout to catch devices that stop responding.
> Instead of programming 10 second arbitrary value, calculate the total time
> it would take for the entire transfer to happen and program the timeout
> value accordingly.
> 
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> ---
>  drivers/mmc/host/sdhci.c | 47 ++++++++++++++++++++++++++++++++++++++++-------
>  drivers/mmc/host/sdhci.h | 10 ++++++++++
>  2 files changed, 50 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index 1dd117cbeb6e..baab67bfa39b 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -709,6 +709,36 @@ static u32 sdhci_sdma_address(struct sdhci_host *host)
>  		return sg_dma_address(host->data->sg);
>  }
>  
> +static void sdhci_calc_sw_timeout(struct sdhci_host *host,
> +				  struct mmc_command *cmd,
> +				  unsigned int target_timeout)
> +{
> +	struct mmc_data *data = cmd->data;
> +	struct mmc_host *mmc = host->mmc;
> +	u64 transfer_time;
> +	struct mmc_ios *ios = &mmc->ios;
> +	unsigned char bus_width = 1 << ios->bus_width;
> +	unsigned int blksz;
> +	unsigned int freq;
> +
> +	if (data) {
> +		blksz = data->blksz;
> +		freq = host->mmc->actual_clock ? : host->clock;
> +		transfer_time = (u64)blksz * NSEC_PER_SEC * (8 / bus_width);
> +		do_div(transfer_time, freq);
> +		/* multiply by '2' to account for any unknowns */
> +		transfer_time = transfer_time * 2;
> +		/* calculate timeout for the entire data */
> +		host->data_timeout = (data->blocks * ((target_timeout *
> +						       NSEC_PER_USEC) +
> +						       transfer_time));

(target_timeout * NSEC_PER_USEC) might be 32-bit and therefore overflow
for timeouts greater than about 4 seconds.

> +	} else {
> +		host->data_timeout = (u64)target_timeout * NSEC_PER_USEC;
> +	}
> +
> +	host->data_timeout += MMC_CMD_TRANSFER_TIME;

Need to allow for target_timeout == 0 so:

	if (host->data_timeout)
		host->data_timeout += MMC_CMD_TRANSFER_TIME;

> +}
> +
>  static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
>  {
>  	u8 count;
> @@ -766,6 +796,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
>  		if (count >= 0xF)
>  			break;
>  	}
> +	sdhci_calc_sw_timeout(host, cmd, target_timeout);

If you make the changes I suggest for patch 6, then this would
move sdhci_calc_sw_timeout() into sdhci_set_timeout().

I suggest you factor out the target_timeout calculation e.g.

static unsigned int sdhci_target_timeout(struct sdhci_host *host,
					 struct mmc_command *cmd,
					 struct mmc_data *data)
{
	unsigned int target_timeout;

	/* timeout in us */
	if (!data)
		target_timeout = cmd->busy_timeout * 1000;
	else {
		target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000);
		if (host->clock && data->timeout_clks) {
			unsigned long long val;

			/*
			 * data->timeout_clks is in units of clock cycles.
			 * host->clock is in Hz.  target_timeout is in us.
			 * Hence, us = 1000000 * cycles / Hz.  Round up.
			 */
			val = 1000000ULL * data->timeout_clks;
			if (do_div(val, host->clock))
				target_timeout++;
			target_timeout += val;
		}
	}

	return target_timeout;
}

And call it from sdhci_calc_sw_timeout()

>  
>  	return count;
>  }
> @@ -1175,13 +1206,6 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
>  		mdelay(1);
>  	}
>  
> -	timeout = jiffies;
> -	if (!cmd->data && cmd->busy_timeout > 9000)
> -		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
> -	else
> -		timeout += 10 * HZ;
> -	sdhci_mod_timer(host, cmd->mrq, timeout);
> -
>  	host->cmd = cmd;
>  	if (sdhci_data_line_cmd(cmd)) {
>  		WARN_ON(host->data_cmd);
> @@ -1221,6 +1245,15 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
>  	    cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
>  		flags |= SDHCI_CMD_DATA;
>  
> +	timeout = jiffies;
> +	if (host->data_timeout > 0) {

This can be just:

	if (host->data_timeout) {

> +		timeout += nsecs_to_jiffies(host->data_timeout);
> +		host->data_timeout = 0;

It would be better to initialize host->data_timeout = 0 at the top of
sdhci_prepare_data().

Also still need:

	else if (!cmd->data && cmd->busy_timeout > 9000) {
		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;


> +	} else {
> +		timeout += 10 * HZ;
> +	}
> +	sdhci_mod_timer(host, cmd->mrq, timeout);
> +
>  	sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
>  }
>  EXPORT_SYMBOL_GPL(sdhci_send_command);
> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> index ff283ee08854..29b242fd17de 100644
> --- a/drivers/mmc/host/sdhci.h
> +++ b/drivers/mmc/host/sdhci.h
> @@ -332,6 +332,14 @@ struct sdhci_adma2_64_desc {
>  /* Allow for a a command request and a data request at the same time */
>  #define SDHCI_MAX_MRQS		2
>  
> +/*
> + * 48bit command and 136 bit response in 100KHz clock could take upto 2.48ms.
> + * However since the start time of the command, the time between
> + * command and response, and the time between response and start of data is
> + * not known, set the command transfer time to 10ms.
> + */
> +#define MMC_CMD_TRANSFER_TIME	(10 * NSEC_PER_MSEC) /* max 10 ms */
> +
>  enum sdhci_cookie {
>  	COOKIE_UNMAPPED,
>  	COOKIE_PRE_MAPPED,	/* mapped by sdhci_pre_req() */
> @@ -555,6 +563,8 @@ struct sdhci_host {
>  	/* Host SDMA buffer boundary. */
>  	u32			sdma_boundary;
>  
> +	u64			data_timeout;
> +
>  	unsigned long private[0] ____cacheline_aligned;
>  };
>  
> 

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

* Re: [PATCH v3 01/11] mmc: sdhci-omap: Fix when capabilities are obtained from SDHCI_CAPABILITIES reg
  2018-03-07 13:20 ` [PATCH v3 01/11] mmc: sdhci-omap: Fix when capabilities are obtained from SDHCI_CAPABILITIES reg Kishon Vijay Abraham I
@ 2018-03-15 14:17   ` Adrian Hunter
  0 siblings, 0 replies; 31+ messages in thread
From: Adrian Hunter @ 2018-03-15 14:17 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Ulf Hansson, Tony Lindgren
  Cc: Rob Herring, Mark Rutland, Russell King, linux-mmc, devicetree,
	linux-kernel, linux-omap, linux-arm-kernel

On 07/03/18 15:20, Kishon Vijay Abraham I wrote:
> sdhci_omap_config_iodelay_pinctrl_state() requires caps and caps2 to be
> initialized (speed mode capabilities like UHS/HS200) before it is
> invoked. While mmc_of_parse() initializes caps/caps2 if capabilities is
> populated in device tree, it will remain uninitialized for capabilities
> obtained from SDHCI_CAPABILITIES register.
> Fix sdhci_omap_config_iodelay_pinctrl_state() to be used even while
> getting the capabilities from SDHCI_CAPABILITIES register by invoking
> sdhci_setup_host() before sdhci_omap_config_iodelay_pinctrl_state().
> 
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
> ---
>  drivers/mmc/host/sdhci-omap.c | 14 +++++++++-----
>  1 file changed, 9 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c
> index 1456abd5eeb9..3cce30584d2f 100644
> --- a/drivers/mmc/host/sdhci-omap.c
> +++ b/drivers/mmc/host/sdhci-omap.c
> @@ -916,10 +916,6 @@ static int sdhci_omap_probe(struct platform_device *pdev)
>  		goto err_put_sync;
>  	}
>  
> -	ret = sdhci_omap_config_iodelay_pinctrl_state(omap_host);
> -	if (ret)
> -		goto err_put_sync;
> -
>  	host->mmc_host_ops.get_ro = mmc_gpio_get_ro;
>  	host->mmc_host_ops.start_signal_voltage_switch =
>  					sdhci_omap_start_signal_voltage_switch;
> @@ -930,7 +926,15 @@ static int sdhci_omap_probe(struct platform_device *pdev)
>  	sdhci_read_caps(host);
>  	host->caps |= SDHCI_CAN_DO_ADMA2;
>  
> -	ret = sdhci_add_host(host);
> +	ret = sdhci_setup_host(host);
> +	if (ret)
> +		goto err_put_sync;
> +
> +	ret = sdhci_omap_config_iodelay_pinctrl_state(omap_host);
> +	if (ret)
> +		goto err_put_sync;
> +
> +	ret = __sdhci_add_host(host);
>  	if (ret)
>  		goto err_put_sync;

if __sdhci_add_host() fails, then sdhci_cleanup_host() needs to be called to
free resources allocated by sdhci_setup_host().

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

* Re: [PATCH v3 02/11] mmc: sdhci-omap: Remove setting ADMA capability in driver
  2018-03-07 13:20 ` [PATCH v3 02/11] mmc: sdhci-omap: Remove setting ADMA capability in driver Kishon Vijay Abraham I
@ 2018-03-15 14:18   ` Adrian Hunter
  0 siblings, 0 replies; 31+ messages in thread
From: Adrian Hunter @ 2018-03-15 14:18 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Ulf Hansson, Tony Lindgren
  Cc: Rob Herring, Mark Rutland, Russell King, linux-mmc, devicetree,
	linux-kernel, linux-omap, linux-arm-kernel

On 07/03/18 15:20, Kishon Vijay Abraham I wrote:
> sdhci can directly get ADMA capability from MMCHS_CAPA register.
> Remove explicitly setting ADMA here as some instances might not have
> ADMA enabled. (sdhci_read_caps() is also removed from here since
> sdhci_setup_host() invokes it).
> 
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>

Acked-by: Adrian Hunter <adrian.hunter@intel.com>

> ---
>  drivers/mmc/host/sdhci-omap.c | 3 ---
>  1 file changed, 3 deletions(-)
> 
> diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c
> index 3cce30584d2f..0c40b13fb67d 100644
> --- a/drivers/mmc/host/sdhci-omap.c
> +++ b/drivers/mmc/host/sdhci-omap.c
> @@ -923,9 +923,6 @@ static int sdhci_omap_probe(struct platform_device *pdev)
>  	host->mmc_host_ops.card_busy = sdhci_omap_card_busy;
>  	host->mmc_host_ops.execute_tuning = sdhci_omap_execute_tuning;
>  
> -	sdhci_read_caps(host);
> -	host->caps |= SDHCI_CAN_DO_ADMA2;
> -
>  	ret = sdhci_setup_host(host);
>  	if (ret)
>  		goto err_put_sync;
> 

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

* Re: [PATCH v3 03/11] mmc: sdhci-omap: Workaround for Errata i843
  2018-03-07 13:20 ` [PATCH v3 03/11] mmc: sdhci-omap: Workaround for Errata i843 Kishon Vijay Abraham I
@ 2018-03-15 14:24   ` Adrian Hunter
  0 siblings, 0 replies; 31+ messages in thread
From: Adrian Hunter @ 2018-03-15 14:24 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Ulf Hansson, Tony Lindgren
  Cc: Rob Herring, Mark Rutland, Russell King, linux-mmc, devicetree,
	linux-kernel, linux-omap, linux-arm-kernel

On 07/03/18 15:20, Kishon Vijay Abraham I wrote:
> Errata i843 in AM572x Sitara Processors Silicon Revision 2.0, 1.1
> (SPRZ429K July 2014–Revised March 2017 [1]) mentions
> PG 1.0/1.1 silicon has limitations w.r.t frequencies at which MMC1/2/3
> can operate.
> 
> Use soc_device_match() to identify rev 1.0/1.1 silicon and
> override mmc->f_max according to the errata workaround.
> "max-frequency" dt property cannot be used since the device
> tree is added for rev 2.0 silicon.
> 
> soc_device_match() is also used in order to get the IODelay values
> for rev 1.0/1.1 silicon.
> 
> [1] -> http://www.ti.com/lit/er/sprz429k/sprz429k.pdf
> 
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>

Acked-by: Adrian Hunter <adrian.hunter@intel.com>

> ---
>  drivers/mmc/host/sdhci-omap.c | 35 ++++++++++++++++++++++++++++++++++-
>  1 file changed, 34 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c
> index 0c40b13fb67d..fbc20a4fbb23 100644
> --- a/drivers/mmc/host/sdhci-omap.c
> +++ b/drivers/mmc/host/sdhci-omap.c
> @@ -26,6 +26,7 @@
>  #include <linux/pm_runtime.h>
>  #include <linux/regulator/consumer.h>
>  #include <linux/pinctrl/consumer.h>
> +#include <linux/sys_soc.h>
>  
>  #include "sdhci-pltfm.h"
>  
> @@ -100,6 +101,7 @@ struct sdhci_omap_data {
>  };
>  
>  struct sdhci_omap_host {
> +	char			*version;
>  	void __iomem		*base;
>  	struct device		*dev;
>  	struct	regulator	*pbias;
> @@ -733,12 +735,21 @@ static struct pinctrl_state
>  				  u32 *caps, u32 capmask)
>  {
>  	struct device *dev = omap_host->dev;
> +	char *version = omap_host->version;
>  	struct pinctrl_state *pinctrl_state = ERR_PTR(-ENODEV);
> +	char str[20];
>  
>  	if (!(*caps & capmask))
>  		goto ret;
>  
> -	pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, mode);
> +	if (version) {
> +		snprintf(str, 20, "%s-%s", mode, version);
> +		pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, str);
> +	}
> +
> +	if (IS_ERR(pinctrl_state))
> +		pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, mode);
> +
>  	if (IS_ERR(pinctrl_state)) {
>  		dev_err(dev, "no pinctrl state for %s mode", mode);
>  		*caps &= ~capmask;
> @@ -830,6 +841,16 @@ static int sdhci_omap_config_iodelay_pinctrl_state(struct sdhci_omap_host
>  	return 0;
>  }
>  
> +static const struct soc_device_attribute sdhci_omap_soc_devices[] = {
> +	{
> +		.machine = "DRA7[45]*",
> +		.revision = "ES1.[01]",
> +	},
> +	{
> +		/* sentinel */
> +	}
> +};
> +
>  static int sdhci_omap_probe(struct platform_device *pdev)
>  {
>  	int ret;
> @@ -841,6 +862,7 @@ static int sdhci_omap_probe(struct platform_device *pdev)
>  	struct mmc_host *mmc;
>  	const struct of_device_id *match;
>  	struct sdhci_omap_data *data;
> +	const struct soc_device_attribute *soc;
>  
>  	match = of_match_device(omap_sdhci_match, dev);
>  	if (!match)
> @@ -875,6 +897,17 @@ static int sdhci_omap_probe(struct platform_device *pdev)
>  	if (ret)
>  		goto err_pltfm_free;
>  
> +	soc = soc_device_match(sdhci_omap_soc_devices);
> +	if (soc) {
> +		omap_host->version = "rev11";
> +		if (!strcmp(dev_name(dev), "4809c000.mmc"))
> +			mmc->f_max = 96000000;
> +		if (!strcmp(dev_name(dev), "480b4000.mmc"))
> +			mmc->f_max = 48000000;
> +		if (!strcmp(dev_name(dev), "480ad000.mmc"))
> +			mmc->f_max = 48000000;
> +	}
> +
>  	pltfm_host->clk = devm_clk_get(dev, "fck");
>  	if (IS_ERR(pltfm_host->clk)) {
>  		ret = PTR_ERR(pltfm_host->clk);
> 

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

* Re: [PATCH v3 04/11] mmc: sdhci-omap: Invoke sdhci_get_of_property to read sdhci dt properties
  2018-03-07 13:20 ` [PATCH v3 04/11] mmc: sdhci-omap: Invoke sdhci_get_of_property to read sdhci dt properties Kishon Vijay Abraham I
@ 2018-03-15 14:27   ` Adrian Hunter
  0 siblings, 0 replies; 31+ messages in thread
From: Adrian Hunter @ 2018-03-15 14:27 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Ulf Hansson, Tony Lindgren
  Cc: Rob Herring, Mark Rutland, Russell King, linux-mmc, devicetree,
	linux-kernel, linux-omap, linux-arm-kernel

On 07/03/18 15:20, Kishon Vijay Abraham I wrote:
> Invoke sdhci_get_of_property defined in sdhci-pltfm.c to read
> sdhci specific properties from dt node.
> 
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>

Acked-by: Adrian Hunter <adrian.hunter@intel.com>

> ---
>  drivers/mmc/host/sdhci-omap.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c
> index fbc20a4fbb23..314dbe4d7412 100644
> --- a/drivers/mmc/host/sdhci-omap.c
> +++ b/drivers/mmc/host/sdhci-omap.c
> @@ -893,6 +893,7 @@ static int sdhci_omap_probe(struct platform_device *pdev)
>  	host->ioaddr += offset;
>  
>  	mmc = host->mmc;
> +	sdhci_get_of_property(pdev);
>  	ret = mmc_of_parse(mmc);
>  	if (ret)
>  		goto err_pltfm_free;
> 

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

* Re: [PATCH v3 11/11] mmc: sdhci-omap: Add sdhci_omap specific ops for enable_sdio_irq
  2018-03-07 13:20 ` [PATCH v3 11/11] mmc: sdhci-omap: Add sdhci_omap specific ops for enable_sdio_irq Kishon Vijay Abraham I
@ 2018-03-15 14:34   ` Adrian Hunter
  0 siblings, 0 replies; 31+ messages in thread
From: Adrian Hunter @ 2018-03-15 14:34 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Ulf Hansson, Tony Lindgren
  Cc: Rob Herring, Mark Rutland, Russell King, linux-mmc, devicetree,
	linux-kernel, linux-omap, linux-arm-kernel

On 07/03/18 15:20, Kishon Vijay Abraham I wrote:
> Add sdhci_omap_enable_sdio_irq to set CTPL and CLKEXTFREE bits in
> MMCHS_CON register required to detect asynchronous card interrupt
> on DAT[1].
> 
> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>

Acked-by: Adrian Hunter <adrian.hunter@intel.com>

> ---
>  drivers/mmc/host/sdhci-omap.c | 19 +++++++++++++++++++
>  1 file changed, 19 insertions(+)
> 
> diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c
> index 14dd51b51b41..8ceb3956b211 100644
> --- a/drivers/mmc/host/sdhci-omap.c
> +++ b/drivers/mmc/host/sdhci-omap.c
> @@ -36,6 +36,7 @@
>  #define CON_DDR			BIT(19)
>  #define CON_CLKEXTFREE		BIT(16)
>  #define CON_PADEN		BIT(15)
> +#define CON_CTPL		BIT(11)
>  #define CON_INIT		BIT(1)
>  #define CON_OD			BIT(0)
>  
> @@ -226,6 +227,23 @@ static void sdhci_omap_conf_bus_power(struct sdhci_omap_host *omap_host,
>  	}
>  }
>  
> +static void sdhci_omap_enable_sdio_irq(struct mmc_host *mmc, int enable)
> +{
> +	struct sdhci_host *host = mmc_priv(mmc);
> +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> +	struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
> +	u32 reg;
> +
> +	reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON);
> +	if (enable)
> +		reg |= (CON_CTPL | CON_CLKEXTFREE);
> +	else
> +		reg &= ~(CON_CTPL | CON_CLKEXTFREE);
> +	sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg);
> +
> +	sdhci_enable_sdio_irq(mmc, enable);
> +}
> +
>  static inline void sdhci_omap_set_dll(struct sdhci_omap_host *omap_host,
>  				      int count)
>  {
> @@ -962,6 +980,7 @@ static int sdhci_omap_probe(struct platform_device *pdev)
>  	host->mmc_host_ops.set_ios = sdhci_omap_set_ios;
>  	host->mmc_host_ops.card_busy = sdhci_omap_card_busy;
>  	host->mmc_host_ops.execute_tuning = sdhci_omap_execute_tuning;
> +	host->mmc_host_ops.enable_sdio_irq = sdhci_omap_enable_sdio_irq;
>  
>  	ret = sdhci_setup_host(host);
>  	if (ret)
> 

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

* Re: [PATCH v3 07/11] mmc: sdhci: Program a relatively accurate SW timeout value
  2018-03-15 13:13   ` Adrian Hunter
@ 2018-03-16  6:29     ` Kishon Vijay Abraham I
  2018-03-16 14:21       ` Adrian Hunter
  0 siblings, 1 reply; 31+ messages in thread
From: Kishon Vijay Abraham I @ 2018-03-16  6:29 UTC (permalink / raw)
  To: Adrian Hunter, Ulf Hansson, Tony Lindgren
  Cc: Rob Herring, Mark Rutland, Russell King, linux-mmc, devicetree,
	linux-kernel, linux-omap, linux-arm-kernel

Hi,

On Thursday 15 March 2018 06:43 PM, Adrian Hunter wrote:
> On 07/03/18 15:20, Kishon Vijay Abraham I wrote:
>> sdhci has a 10 second timeout to catch devices that stop responding.
>> Instead of programming 10 second arbitrary value, calculate the total time
>> it would take for the entire transfer to happen and program the timeout
>> value accordingly.
>>
>> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
>> ---
>>  drivers/mmc/host/sdhci.c | 47 ++++++++++++++++++++++++++++++++++++++++-------
>>  drivers/mmc/host/sdhci.h | 10 ++++++++++
>>  2 files changed, 50 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
>> index 1dd117cbeb6e..baab67bfa39b 100644
>> --- a/drivers/mmc/host/sdhci.c
>> +++ b/drivers/mmc/host/sdhci.c
>> @@ -709,6 +709,36 @@ static u32 sdhci_sdma_address(struct sdhci_host *host)
>>  		return sg_dma_address(host->data->sg);
>>  }
>>  
>> +static void sdhci_calc_sw_timeout(struct sdhci_host *host,
>> +				  struct mmc_command *cmd,
>> +				  unsigned int target_timeout)
>> +{
>> +	struct mmc_data *data = cmd->data;
>> +	struct mmc_host *mmc = host->mmc;
>> +	u64 transfer_time;
>> +	struct mmc_ios *ios = &mmc->ios;
>> +	unsigned char bus_width = 1 << ios->bus_width;
>> +	unsigned int blksz;
>> +	unsigned int freq;
>> +
>> +	if (data) {
>> +		blksz = data->blksz;
>> +		freq = host->mmc->actual_clock ? : host->clock;
>> +		transfer_time = (u64)blksz * NSEC_PER_SEC * (8 / bus_width);
>> +		do_div(transfer_time, freq);
>> +		/* multiply by '2' to account for any unknowns */
>> +		transfer_time = transfer_time * 2;
>> +		/* calculate timeout for the entire data */
>> +		host->data_timeout = (data->blocks * ((target_timeout *
>> +						       NSEC_PER_USEC) +
>> +						       transfer_time));
> 
> (target_timeout * NSEC_PER_USEC) might be 32-bit and therefore overflow
> for timeouts greater than about 4 seconds.
> 
>> +	} else {
>> +		host->data_timeout = (u64)target_timeout * NSEC_PER_USEC;
>> +	}
>> +
>> +	host->data_timeout += MMC_CMD_TRANSFER_TIME;
> 
> Need to allow for target_timeout == 0 so:
> 
> 	if (host->data_timeout)
> 		host->data_timeout += MMC_CMD_TRANSFER_TIME;
> 
>> +}
>> +
>>  static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
>>  {
>>  	u8 count;
>> @@ -766,6 +796,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
>>  		if (count >= 0xF)
>>  			break;
>>  	}
>> +	sdhci_calc_sw_timeout(host, cmd, target_timeout);
> 
> If you make the changes I suggest for patch 6, then this would
> move sdhci_calc_sw_timeout() into sdhci_set_timeout().
> 
> I suggest you factor out the target_timeout calculation e.g.
> 
> static unsigned int sdhci_target_timeout(struct sdhci_host *host,
> 					 struct mmc_command *cmd,
> 					 struct mmc_data *data)
> {
> 	unsigned int target_timeout;
> 
> 	/* timeout in us */
> 	if (!data)
> 		target_timeout = cmd->busy_timeout * 1000;
> 	else {
> 		target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000);
> 		if (host->clock && data->timeout_clks) {
> 			unsigned long long val;
> 
> 			/*
> 			 * data->timeout_clks is in units of clock cycles.
> 			 * host->clock is in Hz.  target_timeout is in us.
> 			 * Hence, us = 1000000 * cycles / Hz.  Round up.
> 			 */
> 			val = 1000000ULL * data->timeout_clks;
> 			if (do_div(val, host->clock))
> 				target_timeout++;
> 			target_timeout += val;
> 		}
> 	}
> 
> 	return target_timeout;
> }
> 
> And call it from sdhci_calc_sw_timeout()
> 
>>  
>>  	return count;
>>  }
>> @@ -1175,13 +1206,6 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
>>  		mdelay(1);
>>  	}
>>  
>> -	timeout = jiffies;
>> -	if (!cmd->data && cmd->busy_timeout > 9000)
>> -		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
>> -	else
>> -		timeout += 10 * HZ;
>> -	sdhci_mod_timer(host, cmd->mrq, timeout);
>> -
>>  	host->cmd = cmd;
>>  	if (sdhci_data_line_cmd(cmd)) {
>>  		WARN_ON(host->data_cmd);
>> @@ -1221,6 +1245,15 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
>>  	    cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
>>  		flags |= SDHCI_CMD_DATA;
>>  
>> +	timeout = jiffies;
>> +	if (host->data_timeout > 0) {
> 
> This can be just:
> 
> 	if (host->data_timeout) {
> 
>> +		timeout += nsecs_to_jiffies(host->data_timeout);
>> +		host->data_timeout = 0;
> 
> It would be better to initialize host->data_timeout = 0 at the top of
> sdhci_prepare_data().
> 
> Also still need:
> 
> 	else if (!cmd->data && cmd->busy_timeout > 9000) {
> 		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;

sdhci_calc_sw_timeout should have calculated the timeout for this case too no?

Thanks
Kishon

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

* Re: [PATCH v3 07/11] mmc: sdhci: Program a relatively accurate SW timeout value
  2018-03-16  6:29     ` Kishon Vijay Abraham I
@ 2018-03-16 14:21       ` Adrian Hunter
  2018-03-19  9:20         ` Kishon Vijay Abraham I
  0 siblings, 1 reply; 31+ messages in thread
From: Adrian Hunter @ 2018-03-16 14:21 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Ulf Hansson, Tony Lindgren
  Cc: Rob Herring, Mark Rutland, Russell King, linux-mmc, devicetree,
	linux-kernel, linux-omap, linux-arm-kernel

On 16/03/18 08:29, Kishon Vijay Abraham I wrote:
> Hi,
> 
> On Thursday 15 March 2018 06:43 PM, Adrian Hunter wrote:
>> On 07/03/18 15:20, Kishon Vijay Abraham I wrote:
>>> sdhci has a 10 second timeout to catch devices that stop responding.
>>> Instead of programming 10 second arbitrary value, calculate the total time
>>> it would take for the entire transfer to happen and program the timeout
>>> value accordingly.
>>>
>>> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
>>> ---
>>>  drivers/mmc/host/sdhci.c | 47 ++++++++++++++++++++++++++++++++++++++++-------
>>>  drivers/mmc/host/sdhci.h | 10 ++++++++++
>>>  2 files changed, 50 insertions(+), 7 deletions(-)
>>>
>>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
>>> index 1dd117cbeb6e..baab67bfa39b 100644
>>> --- a/drivers/mmc/host/sdhci.c
>>> +++ b/drivers/mmc/host/sdhci.c
>>> @@ -709,6 +709,36 @@ static u32 sdhci_sdma_address(struct sdhci_host *host)
>>>  		return sg_dma_address(host->data->sg);
>>>  }
>>>  
>>> +static void sdhci_calc_sw_timeout(struct sdhci_host *host,
>>> +				  struct mmc_command *cmd,
>>> +				  unsigned int target_timeout)
>>> +{
>>> +	struct mmc_data *data = cmd->data;
>>> +	struct mmc_host *mmc = host->mmc;
>>> +	u64 transfer_time;
>>> +	struct mmc_ios *ios = &mmc->ios;
>>> +	unsigned char bus_width = 1 << ios->bus_width;
>>> +	unsigned int blksz;
>>> +	unsigned int freq;
>>> +
>>> +	if (data) {
>>> +		blksz = data->blksz;
>>> +		freq = host->mmc->actual_clock ? : host->clock;
>>> +		transfer_time = (u64)blksz * NSEC_PER_SEC * (8 / bus_width);
>>> +		do_div(transfer_time, freq);
>>> +		/* multiply by '2' to account for any unknowns */
>>> +		transfer_time = transfer_time * 2;
>>> +		/* calculate timeout for the entire data */
>>> +		host->data_timeout = (data->blocks * ((target_timeout *
>>> +						       NSEC_PER_USEC) +
>>> +						       transfer_time));
>>
>> (target_timeout * NSEC_PER_USEC) might be 32-bit and therefore overflow
>> for timeouts greater than about 4 seconds.
>>
>>> +	} else {
>>> +		host->data_timeout = (u64)target_timeout * NSEC_PER_USEC;
>>> +	}
>>> +
>>> +	host->data_timeout += MMC_CMD_TRANSFER_TIME;
>>
>> Need to allow for target_timeout == 0 so:
>>
>> 	if (host->data_timeout)
>> 		host->data_timeout += MMC_CMD_TRANSFER_TIME;
>>
>>> +}
>>> +
>>>  static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
>>>  {
>>>  	u8 count;
>>> @@ -766,6 +796,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
>>>  		if (count >= 0xF)
>>>  			break;
>>>  	}
>>> +	sdhci_calc_sw_timeout(host, cmd, target_timeout);
>>
>> If you make the changes I suggest for patch 6, then this would
>> move sdhci_calc_sw_timeout() into sdhci_set_timeout().
>>
>> I suggest you factor out the target_timeout calculation e.g.
>>
>> static unsigned int sdhci_target_timeout(struct sdhci_host *host,
>> 					 struct mmc_command *cmd,
>> 					 struct mmc_data *data)
>> {
>> 	unsigned int target_timeout;
>>
>> 	/* timeout in us */
>> 	if (!data)
>> 		target_timeout = cmd->busy_timeout * 1000;
>> 	else {
>> 		target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000);
>> 		if (host->clock && data->timeout_clks) {
>> 			unsigned long long val;
>>
>> 			/*
>> 			 * data->timeout_clks is in units of clock cycles.
>> 			 * host->clock is in Hz.  target_timeout is in us.
>> 			 * Hence, us = 1000000 * cycles / Hz.  Round up.
>> 			 */
>> 			val = 1000000ULL * data->timeout_clks;
>> 			if (do_div(val, host->clock))
>> 				target_timeout++;
>> 			target_timeout += val;
>> 		}
>> 	}
>>
>> 	return target_timeout;
>> }
>>
>> And call it from sdhci_calc_sw_timeout()
>>
>>>  
>>>  	return count;
>>>  }
>>> @@ -1175,13 +1206,6 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
>>>  		mdelay(1);
>>>  	}
>>>  
>>> -	timeout = jiffies;
>>> -	if (!cmd->data && cmd->busy_timeout > 9000)
>>> -		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
>>> -	else
>>> -		timeout += 10 * HZ;
>>> -	sdhci_mod_timer(host, cmd->mrq, timeout);
>>> -
>>>  	host->cmd = cmd;
>>>  	if (sdhci_data_line_cmd(cmd)) {
>>>  		WARN_ON(host->data_cmd);
>>> @@ -1221,6 +1245,15 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
>>>  	    cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
>>>  		flags |= SDHCI_CMD_DATA;
>>>  
>>> +	timeout = jiffies;
>>> +	if (host->data_timeout > 0) {
>>
>> This can be just:
>>
>> 	if (host->data_timeout) {
>>
>>> +		timeout += nsecs_to_jiffies(host->data_timeout);
>>> +		host->data_timeout = 0;
>>
>> It would be better to initialize host->data_timeout = 0 at the top of
>> sdhci_prepare_data().
>>
>> Also still need:
>>
>> 	else if (!cmd->data && cmd->busy_timeout > 9000) {
>> 		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
> 
> sdhci_calc_sw_timeout should have calculated the timeout for this case too no?

Yes, but I was thinking you would only calculate when it was needed.

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

* Re: [PATCH v3 07/11] mmc: sdhci: Program a relatively accurate SW timeout value
  2018-03-16 14:21       ` Adrian Hunter
@ 2018-03-19  9:20         ` Kishon Vijay Abraham I
  2018-03-19 10:00           ` Adrian Hunter
  0 siblings, 1 reply; 31+ messages in thread
From: Kishon Vijay Abraham I @ 2018-03-19  9:20 UTC (permalink / raw)
  To: Adrian Hunter, Ulf Hansson, Tony Lindgren
  Cc: Rob Herring, Mark Rutland, Russell King, linux-mmc, devicetree,
	linux-kernel, linux-omap, linux-arm-kernel

Hi Adrian,

On Friday 16 March 2018 07:51 PM, Adrian Hunter wrote:
> On 16/03/18 08:29, Kishon Vijay Abraham I wrote:
>> Hi,
>>
>> On Thursday 15 March 2018 06:43 PM, Adrian Hunter wrote:
>>> On 07/03/18 15:20, Kishon Vijay Abraham I wrote:
>>>> sdhci has a 10 second timeout to catch devices that stop responding.
>>>> Instead of programming 10 second arbitrary value, calculate the total time
>>>> it would take for the entire transfer to happen and program the timeout
>>>> value accordingly.
>>>>
>>>> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
>>>> ---
>>>>  drivers/mmc/host/sdhci.c | 47 ++++++++++++++++++++++++++++++++++++++++-------
>>>>  drivers/mmc/host/sdhci.h | 10 ++++++++++
>>>>  2 files changed, 50 insertions(+), 7 deletions(-)
>>>>
>>>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
>>>> index 1dd117cbeb6e..baab67bfa39b 100644
>>>> --- a/drivers/mmc/host/sdhci.c
>>>> +++ b/drivers/mmc/host/sdhci.c
>>>> @@ -709,6 +709,36 @@ static u32 sdhci_sdma_address(struct sdhci_host *host)
>>>>  		return sg_dma_address(host->data->sg);
>>>>  }
>>>>  
>>>> +static void sdhci_calc_sw_timeout(struct sdhci_host *host,
>>>> +				  struct mmc_command *cmd,
>>>> +				  unsigned int target_timeout)
>>>> +{
>>>> +	struct mmc_data *data = cmd->data;
>>>> +	struct mmc_host *mmc = host->mmc;
>>>> +	u64 transfer_time;
>>>> +	struct mmc_ios *ios = &mmc->ios;
>>>> +	unsigned char bus_width = 1 << ios->bus_width;
>>>> +	unsigned int blksz;
>>>> +	unsigned int freq;
>>>> +
>>>> +	if (data) {
>>>> +		blksz = data->blksz;
>>>> +		freq = host->mmc->actual_clock ? : host->clock;
>>>> +		transfer_time = (u64)blksz * NSEC_PER_SEC * (8 / bus_width);
>>>> +		do_div(transfer_time, freq);
>>>> +		/* multiply by '2' to account for any unknowns */
>>>> +		transfer_time = transfer_time * 2;
>>>> +		/* calculate timeout for the entire data */
>>>> +		host->data_timeout = (data->blocks * ((target_timeout *
>>>> +						       NSEC_PER_USEC) +
>>>> +						       transfer_time));
>>>
>>> (target_timeout * NSEC_PER_USEC) might be 32-bit and therefore overflow
>>> for timeouts greater than about 4 seconds.
>>>
>>>> +	} else {
>>>> +		host->data_timeout = (u64)target_timeout * NSEC_PER_USEC;
>>>> +	}
>>>> +
>>>> +	host->data_timeout += MMC_CMD_TRANSFER_TIME;
>>>
>>> Need to allow for target_timeout == 0 so:
>>>
>>> 	if (host->data_timeout)
>>> 		host->data_timeout += MMC_CMD_TRANSFER_TIME;
>>>
>>>> +}
>>>> +
>>>>  static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
>>>>  {
>>>>  	u8 count;
>>>> @@ -766,6 +796,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
>>>>  		if (count >= 0xF)
>>>>  			break;
>>>>  	}
>>>> +	sdhci_calc_sw_timeout(host, cmd, target_timeout);
>>>
>>> If you make the changes I suggest for patch 6, then this would
>>> move sdhci_calc_sw_timeout() into sdhci_set_timeout().
>>>
>>> I suggest you factor out the target_timeout calculation e.g.
>>>
>>> static unsigned int sdhci_target_timeout(struct sdhci_host *host,
>>> 					 struct mmc_command *cmd,
>>> 					 struct mmc_data *data)
>>> {
>>> 	unsigned int target_timeout;
>>>
>>> 	/* timeout in us */
>>> 	if (!data)
>>> 		target_timeout = cmd->busy_timeout * 1000;
>>> 	else {
>>> 		target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000);
>>> 		if (host->clock && data->timeout_clks) {
>>> 			unsigned long long val;
>>>
>>> 			/*
>>> 			 * data->timeout_clks is in units of clock cycles.
>>> 			 * host->clock is in Hz.  target_timeout is in us.
>>> 			 * Hence, us = 1000000 * cycles / Hz.  Round up.
>>> 			 */
>>> 			val = 1000000ULL * data->timeout_clks;
>>> 			if (do_div(val, host->clock))
>>> 				target_timeout++;
>>> 			target_timeout += val;
>>> 		}
>>> 	}
>>>
>>> 	return target_timeout;
>>> }
>>>
>>> And call it from sdhci_calc_sw_timeout()
>>>
>>>>  
>>>>  	return count;
>>>>  }
>>>> @@ -1175,13 +1206,6 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
>>>>  		mdelay(1);
>>>>  	}
>>>>  
>>>> -	timeout = jiffies;
>>>> -	if (!cmd->data && cmd->busy_timeout > 9000)
>>>> -		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
>>>> -	else
>>>> -		timeout += 10 * HZ;
>>>> -	sdhci_mod_timer(host, cmd->mrq, timeout);
>>>> -
>>>>  	host->cmd = cmd;
>>>>  	if (sdhci_data_line_cmd(cmd)) {
>>>>  		WARN_ON(host->data_cmd);
>>>> @@ -1221,6 +1245,15 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
>>>>  	    cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
>>>>  		flags |= SDHCI_CMD_DATA;
>>>>  
>>>> +	timeout = jiffies;
>>>> +	if (host->data_timeout > 0) {
>>>
>>> This can be just:
>>>
>>> 	if (host->data_timeout) {
>>>
>>>> +		timeout += nsecs_to_jiffies(host->data_timeout);
>>>> +		host->data_timeout = 0;
>>>
>>> It would be better to initialize host->data_timeout = 0 at the top of
>>> sdhci_prepare_data().
>>>
>>> Also still need:
>>>
>>> 	else if (!cmd->data && cmd->busy_timeout > 9000) {
>>> 		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
>>
>> sdhci_calc_sw_timeout should have calculated the timeout for this case too no?
> 
> Yes, but I was thinking you would only calculate when it was needed.

I feel since we would have anyways calculated data_timeout, we should use that
instead unless you see a problem with that.

Thanks
Kishon

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

* Re: [PATCH v3 07/11] mmc: sdhci: Program a relatively accurate SW timeout value
  2018-03-19  9:20         ` Kishon Vijay Abraham I
@ 2018-03-19 10:00           ` Adrian Hunter
  2018-03-19 10:19             ` Kishon Vijay Abraham I
  0 siblings, 1 reply; 31+ messages in thread
From: Adrian Hunter @ 2018-03-19 10:00 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Ulf Hansson, Tony Lindgren
  Cc: Rob Herring, Mark Rutland, Russell King, linux-mmc, devicetree,
	linux-kernel, linux-omap, linux-arm-kernel

On 19/03/18 11:20, Kishon Vijay Abraham I wrote:
> Hi Adrian,
> 
> On Friday 16 March 2018 07:51 PM, Adrian Hunter wrote:
>> On 16/03/18 08:29, Kishon Vijay Abraham I wrote:
>>> Hi,
>>>
>>> On Thursday 15 March 2018 06:43 PM, Adrian Hunter wrote:
>>>> On 07/03/18 15:20, Kishon Vijay Abraham I wrote:
>>>>> sdhci has a 10 second timeout to catch devices that stop responding.
>>>>> Instead of programming 10 second arbitrary value, calculate the total time
>>>>> it would take for the entire transfer to happen and program the timeout
>>>>> value accordingly.
>>>>>
>>>>> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
>>>>> ---
>>>>>  drivers/mmc/host/sdhci.c | 47 ++++++++++++++++++++++++++++++++++++++++-------
>>>>>  drivers/mmc/host/sdhci.h | 10 ++++++++++
>>>>>  2 files changed, 50 insertions(+), 7 deletions(-)
>>>>>
>>>>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
>>>>> index 1dd117cbeb6e..baab67bfa39b 100644
>>>>> --- a/drivers/mmc/host/sdhci.c
>>>>> +++ b/drivers/mmc/host/sdhci.c
>>>>> @@ -709,6 +709,36 @@ static u32 sdhci_sdma_address(struct sdhci_host *host)
>>>>>  		return sg_dma_address(host->data->sg);
>>>>>  }
>>>>>  
>>>>> +static void sdhci_calc_sw_timeout(struct sdhci_host *host,
>>>>> +				  struct mmc_command *cmd,
>>>>> +				  unsigned int target_timeout)
>>>>> +{
>>>>> +	struct mmc_data *data = cmd->data;
>>>>> +	struct mmc_host *mmc = host->mmc;
>>>>> +	u64 transfer_time;
>>>>> +	struct mmc_ios *ios = &mmc->ios;
>>>>> +	unsigned char bus_width = 1 << ios->bus_width;
>>>>> +	unsigned int blksz;
>>>>> +	unsigned int freq;
>>>>> +
>>>>> +	if (data) {
>>>>> +		blksz = data->blksz;
>>>>> +		freq = host->mmc->actual_clock ? : host->clock;
>>>>> +		transfer_time = (u64)blksz * NSEC_PER_SEC * (8 / bus_width);
>>>>> +		do_div(transfer_time, freq);
>>>>> +		/* multiply by '2' to account for any unknowns */
>>>>> +		transfer_time = transfer_time * 2;
>>>>> +		/* calculate timeout for the entire data */
>>>>> +		host->data_timeout = (data->blocks * ((target_timeout *
>>>>> +						       NSEC_PER_USEC) +
>>>>> +						       transfer_time));
>>>>
>>>> (target_timeout * NSEC_PER_USEC) might be 32-bit and therefore overflow
>>>> for timeouts greater than about 4 seconds.
>>>>
>>>>> +	} else {
>>>>> +		host->data_timeout = (u64)target_timeout * NSEC_PER_USEC;
>>>>> +	}
>>>>> +
>>>>> +	host->data_timeout += MMC_CMD_TRANSFER_TIME;
>>>>
>>>> Need to allow for target_timeout == 0 so:
>>>>
>>>> 	if (host->data_timeout)
>>>> 		host->data_timeout += MMC_CMD_TRANSFER_TIME;
>>>>
>>>>> +}
>>>>> +
>>>>>  static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
>>>>>  {
>>>>>  	u8 count;
>>>>> @@ -766,6 +796,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
>>>>>  		if (count >= 0xF)
>>>>>  			break;
>>>>>  	}
>>>>> +	sdhci_calc_sw_timeout(host, cmd, target_timeout);
>>>>
>>>> If you make the changes I suggest for patch 6, then this would
>>>> move sdhci_calc_sw_timeout() into sdhci_set_timeout().
>>>>
>>>> I suggest you factor out the target_timeout calculation e.g.
>>>>
>>>> static unsigned int sdhci_target_timeout(struct sdhci_host *host,
>>>> 					 struct mmc_command *cmd,
>>>> 					 struct mmc_data *data)
>>>> {
>>>> 	unsigned int target_timeout;
>>>>
>>>> 	/* timeout in us */
>>>> 	if (!data)
>>>> 		target_timeout = cmd->busy_timeout * 1000;
>>>> 	else {
>>>> 		target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000);
>>>> 		if (host->clock && data->timeout_clks) {
>>>> 			unsigned long long val;
>>>>
>>>> 			/*
>>>> 			 * data->timeout_clks is in units of clock cycles.
>>>> 			 * host->clock is in Hz.  target_timeout is in us.
>>>> 			 * Hence, us = 1000000 * cycles / Hz.  Round up.
>>>> 			 */
>>>> 			val = 1000000ULL * data->timeout_clks;
>>>> 			if (do_div(val, host->clock))
>>>> 				target_timeout++;
>>>> 			target_timeout += val;
>>>> 		}
>>>> 	}
>>>>
>>>> 	return target_timeout;
>>>> }
>>>>
>>>> And call it from sdhci_calc_sw_timeout()
>>>>
>>>>>  
>>>>>  	return count;
>>>>>  }
>>>>> @@ -1175,13 +1206,6 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
>>>>>  		mdelay(1);
>>>>>  	}
>>>>>  
>>>>> -	timeout = jiffies;
>>>>> -	if (!cmd->data && cmd->busy_timeout > 9000)
>>>>> -		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
>>>>> -	else
>>>>> -		timeout += 10 * HZ;
>>>>> -	sdhci_mod_timer(host, cmd->mrq, timeout);
>>>>> -
>>>>>  	host->cmd = cmd;
>>>>>  	if (sdhci_data_line_cmd(cmd)) {
>>>>>  		WARN_ON(host->data_cmd);
>>>>> @@ -1221,6 +1245,15 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
>>>>>  	    cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
>>>>>  		flags |= SDHCI_CMD_DATA;
>>>>>  
>>>>> +	timeout = jiffies;
>>>>> +	if (host->data_timeout > 0) {
>>>>
>>>> This can be just:
>>>>
>>>> 	if (host->data_timeout) {
>>>>
>>>>> +		timeout += nsecs_to_jiffies(host->data_timeout);
>>>>> +		host->data_timeout = 0;
>>>>
>>>> It would be better to initialize host->data_timeout = 0 at the top of
>>>> sdhci_prepare_data().
>>>>
>>>> Also still need:
>>>>
>>>> 	else if (!cmd->data && cmd->busy_timeout > 9000) {
>>>> 		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
>>>
>>> sdhci_calc_sw_timeout should have calculated the timeout for this case too no?
>>
>> Yes, but I was thinking you would only calculate when it was needed.
> 
> I feel since we would have anyways calculated data_timeout, we should use that
> instead unless you see a problem with that.

I would prefer not to calculate data_timeout when a hardware timeout is
being used.

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

* Re: [PATCH v3 07/11] mmc: sdhci: Program a relatively accurate SW timeout value
  2018-03-19 10:00           ` Adrian Hunter
@ 2018-03-19 10:19             ` Kishon Vijay Abraham I
  2018-03-20  9:48               ` Kishon Vijay Abraham I
  0 siblings, 1 reply; 31+ messages in thread
From: Kishon Vijay Abraham I @ 2018-03-19 10:19 UTC (permalink / raw)
  To: Adrian Hunter, Ulf Hansson, Tony Lindgren
  Cc: Rob Herring, Mark Rutland, Russell King, linux-mmc, devicetree,
	linux-kernel, linux-omap, linux-arm-kernel

Hi Adrian,

On Monday 19 March 2018 03:30 PM, Adrian Hunter wrote:
> On 19/03/18 11:20, Kishon Vijay Abraham I wrote:
>> Hi Adrian,
>>
>> On Friday 16 March 2018 07:51 PM, Adrian Hunter wrote:
>>> On 16/03/18 08:29, Kishon Vijay Abraham I wrote:
>>>> Hi,
>>>>
>>>> On Thursday 15 March 2018 06:43 PM, Adrian Hunter wrote:
>>>>> On 07/03/18 15:20, Kishon Vijay Abraham I wrote:
>>>>>> sdhci has a 10 second timeout to catch devices that stop responding.
>>>>>> Instead of programming 10 second arbitrary value, calculate the total time
>>>>>> it would take for the entire transfer to happen and program the timeout
>>>>>> value accordingly.
>>>>>>
>>>>>> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
>>>>>> ---
>>>>>>  drivers/mmc/host/sdhci.c | 47 ++++++++++++++++++++++++++++++++++++++++-------
>>>>>>  drivers/mmc/host/sdhci.h | 10 ++++++++++
>>>>>>  2 files changed, 50 insertions(+), 7 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
>>>>>> index 1dd117cbeb6e..baab67bfa39b 100644
>>>>>> --- a/drivers/mmc/host/sdhci.c
>>>>>> +++ b/drivers/mmc/host/sdhci.c
>>>>>> @@ -709,6 +709,36 @@ static u32 sdhci_sdma_address(struct sdhci_host *host)
>>>>>>  		return sg_dma_address(host->data->sg);
>>>>>>  }
>>>>>>  
>>>>>> +static void sdhci_calc_sw_timeout(struct sdhci_host *host,
>>>>>> +				  struct mmc_command *cmd,
>>>>>> +				  unsigned int target_timeout)
>>>>>> +{
>>>>>> +	struct mmc_data *data = cmd->data;
>>>>>> +	struct mmc_host *mmc = host->mmc;
>>>>>> +	u64 transfer_time;
>>>>>> +	struct mmc_ios *ios = &mmc->ios;
>>>>>> +	unsigned char bus_width = 1 << ios->bus_width;
>>>>>> +	unsigned int blksz;
>>>>>> +	unsigned int freq;
>>>>>> +
>>>>>> +	if (data) {
>>>>>> +		blksz = data->blksz;
>>>>>> +		freq = host->mmc->actual_clock ? : host->clock;
>>>>>> +		transfer_time = (u64)blksz * NSEC_PER_SEC * (8 / bus_width);
>>>>>> +		do_div(transfer_time, freq);
>>>>>> +		/* multiply by '2' to account for any unknowns */
>>>>>> +		transfer_time = transfer_time * 2;
>>>>>> +		/* calculate timeout for the entire data */
>>>>>> +		host->data_timeout = (data->blocks * ((target_timeout *
>>>>>> +						       NSEC_PER_USEC) +
>>>>>> +						       transfer_time));
>>>>>
>>>>> (target_timeout * NSEC_PER_USEC) might be 32-bit and therefore overflow
>>>>> for timeouts greater than about 4 seconds.
>>>>>
>>>>>> +	} else {
>>>>>> +		host->data_timeout = (u64)target_timeout * NSEC_PER_USEC;
>>>>>> +	}
>>>>>> +
>>>>>> +	host->data_timeout += MMC_CMD_TRANSFER_TIME;
>>>>>
>>>>> Need to allow for target_timeout == 0 so:
>>>>>
>>>>> 	if (host->data_timeout)
>>>>> 		host->data_timeout += MMC_CMD_TRANSFER_TIME;
>>>>>
>>>>>> +}
>>>>>> +
>>>>>>  static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
>>>>>>  {
>>>>>>  	u8 count;
>>>>>> @@ -766,6 +796,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
>>>>>>  		if (count >= 0xF)
>>>>>>  			break;
>>>>>>  	}
>>>>>> +	sdhci_calc_sw_timeout(host, cmd, target_timeout);
>>>>>
>>>>> If you make the changes I suggest for patch 6, then this would
>>>>> move sdhci_calc_sw_timeout() into sdhci_set_timeout().
>>>>>
>>>>> I suggest you factor out the target_timeout calculation e.g.
>>>>>
>>>>> static unsigned int sdhci_target_timeout(struct sdhci_host *host,
>>>>> 					 struct mmc_command *cmd,
>>>>> 					 struct mmc_data *data)
>>>>> {
>>>>> 	unsigned int target_timeout;
>>>>>
>>>>> 	/* timeout in us */
>>>>> 	if (!data)
>>>>> 		target_timeout = cmd->busy_timeout * 1000;
>>>>> 	else {
>>>>> 		target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000);
>>>>> 		if (host->clock && data->timeout_clks) {
>>>>> 			unsigned long long val;
>>>>>
>>>>> 			/*
>>>>> 			 * data->timeout_clks is in units of clock cycles.
>>>>> 			 * host->clock is in Hz.  target_timeout is in us.
>>>>> 			 * Hence, us = 1000000 * cycles / Hz.  Round up.
>>>>> 			 */
>>>>> 			val = 1000000ULL * data->timeout_clks;
>>>>> 			if (do_div(val, host->clock))
>>>>> 				target_timeout++;
>>>>> 			target_timeout += val;
>>>>> 		}
>>>>> 	}
>>>>>
>>>>> 	return target_timeout;
>>>>> }
>>>>>
>>>>> And call it from sdhci_calc_sw_timeout()
>>>>>
>>>>>>  
>>>>>>  	return count;
>>>>>>  }
>>>>>> @@ -1175,13 +1206,6 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
>>>>>>  		mdelay(1);
>>>>>>  	}
>>>>>>  
>>>>>> -	timeout = jiffies;
>>>>>> -	if (!cmd->data && cmd->busy_timeout > 9000)
>>>>>> -		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
>>>>>> -	else
>>>>>> -		timeout += 10 * HZ;
>>>>>> -	sdhci_mod_timer(host, cmd->mrq, timeout);
>>>>>> -
>>>>>>  	host->cmd = cmd;
>>>>>>  	if (sdhci_data_line_cmd(cmd)) {
>>>>>>  		WARN_ON(host->data_cmd);
>>>>>> @@ -1221,6 +1245,15 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
>>>>>>  	    cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
>>>>>>  		flags |= SDHCI_CMD_DATA;
>>>>>>  
>>>>>> +	timeout = jiffies;
>>>>>> +	if (host->data_timeout > 0) {
>>>>>
>>>>> This can be just:
>>>>>
>>>>> 	if (host->data_timeout) {
>>>>>
>>>>>> +		timeout += nsecs_to_jiffies(host->data_timeout);
>>>>>> +		host->data_timeout = 0;
>>>>>
>>>>> It would be better to initialize host->data_timeout = 0 at the top of
>>>>> sdhci_prepare_data().
>>>>>
>>>>> Also still need:
>>>>>
>>>>> 	else if (!cmd->data && cmd->busy_timeout > 9000) {
>>>>> 		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
>>>>
>>>> sdhci_calc_sw_timeout should have calculated the timeout for this case too no?
>>>
>>> Yes, but I was thinking you would only calculate when it was needed.
>>
>> I feel since we would have anyways calculated data_timeout, we should use that
>> instead unless you see a problem with that.
> 
> I would prefer not to calculate data_timeout when a hardware timeout is
> being used.
> 

That differs from what I had thought. This patch tries to program a relatively
accurate SW timeout value (for data_timer) irrespective of whether hardware
timeout is used or not. This only tries to change the 10 Sec SW timeout value
programmed for all data transfer commands.

Thanks
Kishon

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

* Re: [PATCH v3 07/11] mmc: sdhci: Program a relatively accurate SW timeout value
  2018-03-19 10:19             ` Kishon Vijay Abraham I
@ 2018-03-20  9:48               ` Kishon Vijay Abraham I
  2018-04-04 12:48                 ` Adrian Hunter
  0 siblings, 1 reply; 31+ messages in thread
From: Kishon Vijay Abraham I @ 2018-03-20  9:48 UTC (permalink / raw)
  To: Adrian Hunter, Ulf Hansson, Tony Lindgren
  Cc: Rob Herring, Mark Rutland, Russell King, linux-mmc, devicetree,
	linux-kernel, linux-omap, linux-arm-kernel

Hi Adrian,

On Monday 19 March 2018 03:49 PM, Kishon Vijay Abraham I wrote:
> Hi Adrian,
> 
> On Monday 19 March 2018 03:30 PM, Adrian Hunter wrote:
>> On 19/03/18 11:20, Kishon Vijay Abraham I wrote:
>>> Hi Adrian,
>>>
>>> On Friday 16 March 2018 07:51 PM, Adrian Hunter wrote:
>>>> On 16/03/18 08:29, Kishon Vijay Abraham I wrote:
>>>>> Hi,
>>>>>
>>>>> On Thursday 15 March 2018 06:43 PM, Adrian Hunter wrote:
>>>>>> On 07/03/18 15:20, Kishon Vijay Abraham I wrote:
>>>>>>> sdhci has a 10 second timeout to catch devices that stop responding.
>>>>>>> Instead of programming 10 second arbitrary value, calculate the total time
>>>>>>> it would take for the entire transfer to happen and program the timeout
>>>>>>> value accordingly.
>>>>>>>
>>>>>>> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
>>>>>>> ---
>>>>>>>  drivers/mmc/host/sdhci.c | 47 ++++++++++++++++++++++++++++++++++++++++-------
>>>>>>>  drivers/mmc/host/sdhci.h | 10 ++++++++++
>>>>>>>  2 files changed, 50 insertions(+), 7 deletions(-)
>>>>>>>
>>>>>>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
>>>>>>> index 1dd117cbeb6e..baab67bfa39b 100644
>>>>>>> --- a/drivers/mmc/host/sdhci.c
>>>>>>> +++ b/drivers/mmc/host/sdhci.c
>>>>>>> @@ -709,6 +709,36 @@ static u32 sdhci_sdma_address(struct sdhci_host *host)
>>>>>>>  		return sg_dma_address(host->data->sg);
>>>>>>>  }
>>>>>>>  
>>>>>>> +static void sdhci_calc_sw_timeout(struct sdhci_host *host,
>>>>>>> +				  struct mmc_command *cmd,
>>>>>>> +				  unsigned int target_timeout)
>>>>>>> +{
>>>>>>> +	struct mmc_data *data = cmd->data;
>>>>>>> +	struct mmc_host *mmc = host->mmc;
>>>>>>> +	u64 transfer_time;
>>>>>>> +	struct mmc_ios *ios = &mmc->ios;
>>>>>>> +	unsigned char bus_width = 1 << ios->bus_width;
>>>>>>> +	unsigned int blksz;
>>>>>>> +	unsigned int freq;
>>>>>>> +
>>>>>>> +	if (data) {
>>>>>>> +		blksz = data->blksz;
>>>>>>> +		freq = host->mmc->actual_clock ? : host->clock;
>>>>>>> +		transfer_time = (u64)blksz * NSEC_PER_SEC * (8 / bus_width);
>>>>>>> +		do_div(transfer_time, freq);
>>>>>>> +		/* multiply by '2' to account for any unknowns */
>>>>>>> +		transfer_time = transfer_time * 2;
>>>>>>> +		/* calculate timeout for the entire data */
>>>>>>> +		host->data_timeout = (data->blocks * ((target_timeout *
>>>>>>> +						       NSEC_PER_USEC) +
>>>>>>> +						       transfer_time));
>>>>>>
>>>>>> (target_timeout * NSEC_PER_USEC) might be 32-bit and therefore overflow
>>>>>> for timeouts greater than about 4 seconds.
>>>>>>
>>>>>>> +	} else {
>>>>>>> +		host->data_timeout = (u64)target_timeout * NSEC_PER_USEC;
>>>>>>> +	}
>>>>>>> +
>>>>>>> +	host->data_timeout += MMC_CMD_TRANSFER_TIME;
>>>>>>
>>>>>> Need to allow for target_timeout == 0 so:
>>>>>>
>>>>>> 	if (host->data_timeout)
>>>>>> 		host->data_timeout += MMC_CMD_TRANSFER_TIME;
>>>>>>
>>>>>>> +}
>>>>>>> +
>>>>>>>  static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
>>>>>>>  {
>>>>>>>  	u8 count;
>>>>>>> @@ -766,6 +796,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
>>>>>>>  		if (count >= 0xF)
>>>>>>>  			break;
>>>>>>>  	}
>>>>>>> +	sdhci_calc_sw_timeout(host, cmd, target_timeout);
>>>>>>
>>>>>> If you make the changes I suggest for patch 6, then this would
>>>>>> move sdhci_calc_sw_timeout() into sdhci_set_timeout().
>>>>>>
>>>>>> I suggest you factor out the target_timeout calculation e.g.
>>>>>>
>>>>>> static unsigned int sdhci_target_timeout(struct sdhci_host *host,
>>>>>> 					 struct mmc_command *cmd,
>>>>>> 					 struct mmc_data *data)
>>>>>> {
>>>>>> 	unsigned int target_timeout;
>>>>>>
>>>>>> 	/* timeout in us */
>>>>>> 	if (!data)
>>>>>> 		target_timeout = cmd->busy_timeout * 1000;
>>>>>> 	else {
>>>>>> 		target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000);
>>>>>> 		if (host->clock && data->timeout_clks) {
>>>>>> 			unsigned long long val;
>>>>>>
>>>>>> 			/*
>>>>>> 			 * data->timeout_clks is in units of clock cycles.
>>>>>> 			 * host->clock is in Hz.  target_timeout is in us.
>>>>>> 			 * Hence, us = 1000000 * cycles / Hz.  Round up.
>>>>>> 			 */
>>>>>> 			val = 1000000ULL * data->timeout_clks;
>>>>>> 			if (do_div(val, host->clock))
>>>>>> 				target_timeout++;
>>>>>> 			target_timeout += val;
>>>>>> 		}
>>>>>> 	}
>>>>>>
>>>>>> 	return target_timeout;
>>>>>> }
>>>>>>
>>>>>> And call it from sdhci_calc_sw_timeout()
>>>>>>
>>>>>>>  
>>>>>>>  	return count;
>>>>>>>  }
>>>>>>> @@ -1175,13 +1206,6 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
>>>>>>>  		mdelay(1);
>>>>>>>  	}
>>>>>>>  
>>>>>>> -	timeout = jiffies;
>>>>>>> -	if (!cmd->data && cmd->busy_timeout > 9000)
>>>>>>> -		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
>>>>>>> -	else
>>>>>>> -		timeout += 10 * HZ;
>>>>>>> -	sdhci_mod_timer(host, cmd->mrq, timeout);
>>>>>>> -
>>>>>>>  	host->cmd = cmd;
>>>>>>>  	if (sdhci_data_line_cmd(cmd)) {
>>>>>>>  		WARN_ON(host->data_cmd);
>>>>>>> @@ -1221,6 +1245,15 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
>>>>>>>  	    cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
>>>>>>>  		flags |= SDHCI_CMD_DATA;
>>>>>>>  
>>>>>>> +	timeout = jiffies;
>>>>>>> +	if (host->data_timeout > 0) {
>>>>>>
>>>>>> This can be just:
>>>>>>
>>>>>> 	if (host->data_timeout) {
>>>>>>
>>>>>>> +		timeout += nsecs_to_jiffies(host->data_timeout);
>>>>>>> +		host->data_timeout = 0;
>>>>>>
>>>>>> It would be better to initialize host->data_timeout = 0 at the top of
>>>>>> sdhci_prepare_data().
>>>>>>
>>>>>> Also still need:
>>>>>>
>>>>>> 	else if (!cmd->data && cmd->busy_timeout > 9000) {
>>>>>> 		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
>>>>>
>>>>> sdhci_calc_sw_timeout should have calculated the timeout for this case too no?
>>>>
>>>> Yes, but I was thinking you would only calculate when it was needed.
>>>
>>> I feel since we would have anyways calculated data_timeout, we should use that
>>> instead unless you see a problem with that.
>>
>> I would prefer not to calculate data_timeout when a hardware timeout is
>> being used.
>>
> 
> That differs from what I had thought. This patch tries to program a relatively
> accurate SW timeout value (for data_timer) irrespective of whether hardware
> timeout is used or not. This only tries to change the 10 Sec SW timeout value
> programmed for all data transfer commands.

IMHO since we calculate the worst case timeout value we should be using that
for all cases where we are able to calculate the timeout value so that we don't
give a too high or too low timeout value. Let me know If this sounds okay to you.

Thanks
Kishon

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

* Re: [PATCH v3 07/11] mmc: sdhci: Program a relatively accurate SW timeout value
  2018-03-20  9:48               ` Kishon Vijay Abraham I
@ 2018-04-04 12:48                 ` Adrian Hunter
  0 siblings, 0 replies; 31+ messages in thread
From: Adrian Hunter @ 2018-04-04 12:48 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Ulf Hansson, Tony Lindgren
  Cc: Rob Herring, Mark Rutland, Russell King, linux-mmc, devicetree,
	linux-kernel, linux-omap, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 6921 bytes --]

On 20/03/18 11:48, Kishon Vijay Abraham I wrote:
> Hi Adrian,
> 
> On Monday 19 March 2018 03:49 PM, Kishon Vijay Abraham I wrote:
>> Hi Adrian,
>>
>> On Monday 19 March 2018 03:30 PM, Adrian Hunter wrote:
>>> On 19/03/18 11:20, Kishon Vijay Abraham I wrote:
>>>> Hi Adrian,
>>>>
>>>> On Friday 16 March 2018 07:51 PM, Adrian Hunter wrote:
>>>>> On 16/03/18 08:29, Kishon Vijay Abraham I wrote:
>>>>>> Hi,
>>>>>>
>>>>>> On Thursday 15 March 2018 06:43 PM, Adrian Hunter wrote:
>>>>>>> On 07/03/18 15:20, Kishon Vijay Abraham I wrote:
>>>>>>>> sdhci has a 10 second timeout to catch devices that stop responding.
>>>>>>>> Instead of programming 10 second arbitrary value, calculate the total time
>>>>>>>> it would take for the entire transfer to happen and program the timeout
>>>>>>>> value accordingly.
>>>>>>>>
>>>>>>>> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
>>>>>>>> ---
>>>>>>>>  drivers/mmc/host/sdhci.c | 47 ++++++++++++++++++++++++++++++++++++++++-------
>>>>>>>>  drivers/mmc/host/sdhci.h | 10 ++++++++++
>>>>>>>>  2 files changed, 50 insertions(+), 7 deletions(-)
>>>>>>>>
>>>>>>>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
>>>>>>>> index 1dd117cbeb6e..baab67bfa39b 100644
>>>>>>>> --- a/drivers/mmc/host/sdhci.c
>>>>>>>> +++ b/drivers/mmc/host/sdhci.c
>>>>>>>> @@ -709,6 +709,36 @@ static u32 sdhci_sdma_address(struct sdhci_host *host)
>>>>>>>>  		return sg_dma_address(host->data->sg);
>>>>>>>>  }
>>>>>>>>  
>>>>>>>> +static void sdhci_calc_sw_timeout(struct sdhci_host *host,
>>>>>>>> +				  struct mmc_command *cmd,
>>>>>>>> +				  unsigned int target_timeout)
>>>>>>>> +{
>>>>>>>> +	struct mmc_data *data = cmd->data;
>>>>>>>> +	struct mmc_host *mmc = host->mmc;
>>>>>>>> +	u64 transfer_time;
>>>>>>>> +	struct mmc_ios *ios = &mmc->ios;
>>>>>>>> +	unsigned char bus_width = 1 << ios->bus_width;
>>>>>>>> +	unsigned int blksz;
>>>>>>>> +	unsigned int freq;
>>>>>>>> +
>>>>>>>> +	if (data) {
>>>>>>>> +		blksz = data->blksz;
>>>>>>>> +		freq = host->mmc->actual_clock ? : host->clock;
>>>>>>>> +		transfer_time = (u64)blksz * NSEC_PER_SEC * (8 / bus_width);
>>>>>>>> +		do_div(transfer_time, freq);
>>>>>>>> +		/* multiply by '2' to account for any unknowns */
>>>>>>>> +		transfer_time = transfer_time * 2;
>>>>>>>> +		/* calculate timeout for the entire data */
>>>>>>>> +		host->data_timeout = (data->blocks * ((target_timeout *
>>>>>>>> +						       NSEC_PER_USEC) +
>>>>>>>> +						       transfer_time));
>>>>>>>
>>>>>>> (target_timeout * NSEC_PER_USEC) might be 32-bit and therefore overflow
>>>>>>> for timeouts greater than about 4 seconds.
>>>>>>>
>>>>>>>> +	} else {
>>>>>>>> +		host->data_timeout = (u64)target_timeout * NSEC_PER_USEC;
>>>>>>>> +	}
>>>>>>>> +
>>>>>>>> +	host->data_timeout += MMC_CMD_TRANSFER_TIME;
>>>>>>>
>>>>>>> Need to allow for target_timeout == 0 so:
>>>>>>>
>>>>>>> 	if (host->data_timeout)
>>>>>>> 		host->data_timeout += MMC_CMD_TRANSFER_TIME;
>>>>>>>
>>>>>>>> +}
>>>>>>>> +
>>>>>>>>  static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
>>>>>>>>  {
>>>>>>>>  	u8 count;
>>>>>>>> @@ -766,6 +796,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
>>>>>>>>  		if (count >= 0xF)
>>>>>>>>  			break;
>>>>>>>>  	}
>>>>>>>> +	sdhci_calc_sw_timeout(host, cmd, target_timeout);
>>>>>>>
>>>>>>> If you make the changes I suggest for patch 6, then this would
>>>>>>> move sdhci_calc_sw_timeout() into sdhci_set_timeout().
>>>>>>>
>>>>>>> I suggest you factor out the target_timeout calculation e.g.
>>>>>>>
>>>>>>> static unsigned int sdhci_target_timeout(struct sdhci_host *host,
>>>>>>> 					 struct mmc_command *cmd,
>>>>>>> 					 struct mmc_data *data)
>>>>>>> {
>>>>>>> 	unsigned int target_timeout;
>>>>>>>
>>>>>>> 	/* timeout in us */
>>>>>>> 	if (!data)
>>>>>>> 		target_timeout = cmd->busy_timeout * 1000;
>>>>>>> 	else {
>>>>>>> 		target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000);
>>>>>>> 		if (host->clock && data->timeout_clks) {
>>>>>>> 			unsigned long long val;
>>>>>>>
>>>>>>> 			/*
>>>>>>> 			 * data->timeout_clks is in units of clock cycles.
>>>>>>> 			 * host->clock is in Hz.  target_timeout is in us.
>>>>>>> 			 * Hence, us = 1000000 * cycles / Hz.  Round up.
>>>>>>> 			 */
>>>>>>> 			val = 1000000ULL * data->timeout_clks;
>>>>>>> 			if (do_div(val, host->clock))
>>>>>>> 				target_timeout++;
>>>>>>> 			target_timeout += val;
>>>>>>> 		}
>>>>>>> 	}
>>>>>>>
>>>>>>> 	return target_timeout;
>>>>>>> }
>>>>>>>
>>>>>>> And call it from sdhci_calc_sw_timeout()
>>>>>>>
>>>>>>>>  
>>>>>>>>  	return count;
>>>>>>>>  }
>>>>>>>> @@ -1175,13 +1206,6 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
>>>>>>>>  		mdelay(1);
>>>>>>>>  	}
>>>>>>>>  
>>>>>>>> -	timeout = jiffies;
>>>>>>>> -	if (!cmd->data && cmd->busy_timeout > 9000)
>>>>>>>> -		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
>>>>>>>> -	else
>>>>>>>> -		timeout += 10 * HZ;
>>>>>>>> -	sdhci_mod_timer(host, cmd->mrq, timeout);
>>>>>>>> -
>>>>>>>>  	host->cmd = cmd;
>>>>>>>>  	if (sdhci_data_line_cmd(cmd)) {
>>>>>>>>  		WARN_ON(host->data_cmd);
>>>>>>>> @@ -1221,6 +1245,15 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
>>>>>>>>  	    cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
>>>>>>>>  		flags |= SDHCI_CMD_DATA;
>>>>>>>>  
>>>>>>>> +	timeout = jiffies;
>>>>>>>> +	if (host->data_timeout > 0) {
>>>>>>>
>>>>>>> This can be just:
>>>>>>>
>>>>>>> 	if (host->data_timeout) {
>>>>>>>
>>>>>>>> +		timeout += nsecs_to_jiffies(host->data_timeout);
>>>>>>>> +		host->data_timeout = 0;
>>>>>>>
>>>>>>> It would be better to initialize host->data_timeout = 0 at the top of
>>>>>>> sdhci_prepare_data().
>>>>>>>
>>>>>>> Also still need:
>>>>>>>
>>>>>>> 	else if (!cmd->data && cmd->busy_timeout > 9000) {
>>>>>>> 		timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
>>>>>>
>>>>>> sdhci_calc_sw_timeout should have calculated the timeout for this case too no?
>>>>>
>>>>> Yes, but I was thinking you would only calculate when it was needed.
>>>>
>>>> I feel since we would have anyways calculated data_timeout, we should use that
>>>> instead unless you see a problem with that.
>>>
>>> I would prefer not to calculate data_timeout when a hardware timeout is
>>> being used.
>>>
>>
>> That differs from what I had thought. This patch tries to program a relatively
>> accurate SW timeout value (for data_timer) irrespective of whether hardware
>> timeout is used or not. This only tries to change the 10 Sec SW timeout value
>> programmed for all data transfer commands.
> 
> IMHO since we calculate the worst case timeout value we should be using that
> for all cases where we are able to calculate the timeout value so that we don't
> give a too high or too low timeout value. Let me know If this sounds okay to you.

I don't want to do the calculation for drivers that don't need it.

How about the 3 patches attached

[-- Attachment #2: 0001-mmc-sdhci-Add-quirk-to-disable-HW-timeout.patch --]
[-- Type: text/x-patch, Size: 3963 bytes --]

>From 52d36e3bf42d189378603ecdad06ffda601cc545 Mon Sep 17 00:00:00 2001
From: Adrian Hunter <adrian.hunter@intel.com>
Date: Thu, 29 Mar 2018 16:04:14 +0300
Subject: [PATCH 1/3] mmc: sdhci: Add quirk to disable HW timeout

Add quirk to disable HW timeout if the requested timeout is more than the
maximum obtainable timeout.

Also, if the quirk is set and ->get_max_timeout_count() is not implemented,
max_busy_timeout is set to zero.

Based-on-patch-by: Kishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/host/sdhci.c | 38 ++++++++++++++++++++++++++++++++++----
 drivers/mmc/host/sdhci.h |  5 +++++
 2 files changed, 39 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 3bf6117ee879..5299ea6b5c9c 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -709,12 +709,15 @@ static u32 sdhci_sdma_address(struct sdhci_host *host)
 		return sg_dma_address(host->data->sg);
 }
 
-static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
+static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd,
+			     bool *too_big)
 {
 	u8 count;
 	struct mmc_data *data = cmd->data;
 	unsigned target_timeout, current_timeout;
 
+	*too_big = true;
+
 	/*
 	 * If the host controller provides us with an incorrect timeout
 	 * value, just skip the check and use 0xE.  The hardware may take
@@ -768,9 +771,12 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
 	}
 
 	if (count >= 0xF) {
-		DBG("Too large timeout 0x%x requested for CMD%d!\n",
-		    count, cmd->opcode);
+		if (!(host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT))
+			DBG("Too large timeout 0x%x requested for CMD%d!\n",
+			    count, cmd->opcode);
 		count = 0xE;
+	} else {
+		*too_big = false;
 	}
 
 	return count;
@@ -790,6 +796,16 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host)
 	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 }
 
+static void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable)
+{
+	if (enable)
+		host->ier |= SDHCI_INT_DATA_TIMEOUT;
+	else
+		host->ier &= ~SDHCI_INT_DATA_TIMEOUT;
+	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+}
+
 static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
 {
 	u8 count;
@@ -797,7 +813,17 @@ static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
 	if (host->ops->set_timeout) {
 		host->ops->set_timeout(host, cmd);
 	} else {
-		count = sdhci_calc_timeout(host, cmd);
+		bool too_big = false;
+
+		count = sdhci_calc_timeout(host, cmd, &too_big);
+
+		if (too_big &&
+		    host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT) {
+			sdhci_set_data_timeout_irq(host, false);
+		} else if (!(host->ier & SDHCI_INT_DATA_TIMEOUT)) {
+			sdhci_set_data_timeout_irq(host, true);
+		}
+
 		sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
 	}
 }
@@ -3619,6 +3645,10 @@ int sdhci_setup_host(struct sdhci_host *host)
 		mmc->max_busy_timeout /= host->timeout_clk;
 	}
 
+	if (host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT &&
+	    !host->ops->get_max_timeout_count)
+		mmc->max_busy_timeout = 0;
+
 	mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
 	mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
 
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index c95b0a4a7594..f6555c0f4ad3 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -437,6 +437,11 @@ struct sdhci_host {
 #define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN		(1<<15)
 /* Controller has CRC in 136 bit Command Response */
 #define SDHCI_QUIRK2_RSP_136_HAS_CRC			(1<<16)
+/*
+ * Disable HW timeout if the requested timeout is more than the maximum
+ * obtainable timeout.
+ */
+#define SDHCI_QUIRK2_DISABLE_HW_TIMEOUT			(1<<17)
 
 	int irq;		/* Device IRQ */
 	void __iomem *ioaddr;	/* Mapped address */
-- 
1.9.1


[-- Attachment #3: 0002-mmc-sdhci-Factor-out-target_timeout-calculation.patch --]
[-- Type: text/x-patch, Size: 2377 bytes --]

>From c73df33aa4549301e0b93424990dc16de2b14923 Mon Sep 17 00:00:00 2001
From: Adrian Hunter <adrian.hunter@intel.com>
Date: Wed, 4 Apr 2018 15:14:38 +0300
Subject: [PATCH 2/3] mmc: sdhci: Factor out target_timeout calculation

Factor out the target_timeout calculation so it can be re-used.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/host/sdhci.c | 48 ++++++++++++++++++++++++++++++------------------
 1 file changed, 30 insertions(+), 18 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 5299ea6b5c9c..7c0683b8baba 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -709,6 +709,35 @@ static u32 sdhci_sdma_address(struct sdhci_host *host)
 		return sg_dma_address(host->data->sg);
 }
 
+static unsigned int sdhci_target_timeout(struct sdhci_host *host,
+					 struct mmc_command *cmd,
+					 struct mmc_data *data)
+{
+	unsigned int target_timeout;
+
+	/* timeout in us */
+	if (!data) {
+		target_timeout = cmd->busy_timeout * 1000;
+	} else {
+		target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000);
+		if (host->clock && data->timeout_clks) {
+			unsigned long long val;
+
+			/*
+			 * data->timeout_clks is in units of clock cycles.
+			 * host->clock is in Hz.  target_timeout is in us.
+			 * Hence, us = 1000000 * cycles / Hz.  Round up.
+			 */
+			val = 1000000ULL * data->timeout_clks;
+			if (do_div(val, host->clock))
+				target_timeout++;
+			target_timeout += val;
+		}
+	}
+
+	return target_timeout;
+}
+
 static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd,
 			     bool *too_big)
 {
@@ -732,24 +761,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd,
 		return 0xE;
 
 	/* timeout in us */
-	if (!data)
-		target_timeout = cmd->busy_timeout * 1000;
-	else {
-		target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000);
-		if (host->clock && data->timeout_clks) {
-			unsigned long long val;
-
-			/*
-			 * data->timeout_clks is in units of clock cycles.
-			 * host->clock is in Hz.  target_timeout is in us.
-			 * Hence, us = 1000000 * cycles / Hz.  Round up.
-			 */
-			val = 1000000ULL * data->timeout_clks;
-			if (do_div(val, host->clock))
-				target_timeout++;
-			target_timeout += val;
-		}
-	}
+	target_timeout = sdhci_target_timeout(host, cmd, data);
 
 	/*
 	 * Figure out needed cycles.
-- 
1.9.1


[-- Attachment #4: 0003-mmc-sdhci-Program-a-relatively-accurate-SW-timeout-v.patch --]
[-- Type: text/x-patch, Size: 3715 bytes --]

>From 0976d161bfb9c9a35c5176c8059c4ed9a985a0b2 Mon Sep 17 00:00:00 2001
From: Kishon Vijay Abraham I <kishon@ti.com>
Date: Wed, 7 Mar 2018 18:50:16 +0530
Subject: [PATCH 3/3] mmc: sdhci: Program a relatively accurate SW timeout
 value

sdhci has a 10 second timeout to catch devices that stop responding.
In the case of quirk SDHCI_QUIRK2_DISABLE_HW_TIMEOUT, instead of
programming 10 second arbitrary value, calculate the total time it would
take for the entire transfer to happen and program the timeout value
accordingly.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/host/sdhci.c | 36 ++++++++++++++++++++++++++++++++++++
 drivers/mmc/host/sdhci.h | 10 ++++++++++
 2 files changed, 46 insertions(+)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 7c0683b8baba..d67ac1bf7caa 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -738,6 +738,39 @@ static unsigned int sdhci_target_timeout(struct sdhci_host *host,
 	return target_timeout;
 }
 
+static void sdhci_calc_sw_timeout(struct sdhci_host *host,
+				  struct mmc_command *cmd)
+{
+	struct mmc_data *data = cmd->data;
+	struct mmc_host *mmc = host->mmc;
+	struct mmc_ios *ios = &mmc->ios;
+	unsigned char bus_width = 1 << ios->bus_width;
+	unsigned int blksz;
+	unsigned int freq;
+	u64 target_timeout;
+	u64 transfer_time;
+
+	target_timeout = sdhci_target_timeout(host, cmd, data);
+	target_timeout *= NSEC_PER_USEC;
+
+	if (data) {
+		blksz = data->blksz;
+		freq = host->mmc->actual_clock ? : host->clock;
+		transfer_time = (u64)blksz * NSEC_PER_SEC * (8 / bus_width);
+		do_div(transfer_time, freq);
+		/* multiply by '2' to account for any unknowns */
+		transfer_time = transfer_time * 2;
+		/* calculate timeout for the entire data */
+		host->data_timeout = data->blocks * target_timeout +
+				     transfer_time;
+	} else {
+		host->data_timeout = target_timeout;
+	}
+
+	if (host->data_timeout)
+		host->data_timeout += MMC_CMD_TRANSFER_TIME;
+}
+
 static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd,
 			     bool *too_big)
 {
@@ -831,6 +864,7 @@ static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
 
 		if (too_big &&
 		    host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT) {
+			sdhci_calc_sw_timeout(host, cmd);
 			sdhci_set_data_timeout_irq(host, false);
 		} else if (!(host->ier & SDHCI_INT_DATA_TIMEOUT)) {
 			sdhci_set_data_timeout_irq(host, true);
@@ -845,6 +879,8 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
 	u8 ctrl;
 	struct mmc_data *data = cmd->data;
 
+	host->data_timeout = 0;
+
 	if (sdhci_data_line_cmd(cmd))
 		sdhci_set_timeout(host, cmd);
 
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index f6555c0f4ad3..23966f887da6 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -332,6 +332,14 @@ struct sdhci_adma2_64_desc {
 /* Allow for a a command request and a data request at the same time */
 #define SDHCI_MAX_MRQS		2
 
+/*
+ * 48bit command and 136 bit response in 100KHz clock could take upto 2.48ms.
+ * However since the start time of the command, the time between
+ * command and response, and the time between response and start of data is
+ * not known, set the command transfer time to 10ms.
+ */
+#define MMC_CMD_TRANSFER_TIME	(10 * NSEC_PER_MSEC) /* max 10 ms */
+
 enum sdhci_cookie {
 	COOKIE_UNMAPPED,
 	COOKIE_PRE_MAPPED,	/* mapped by sdhci_pre_req() */
@@ -555,6 +563,8 @@ struct sdhci_host {
 	/* Host SDMA buffer boundary. */
 	u32			sdma_boundary;
 
+	u64			data_timeout;
+
 	unsigned long private[0] ____cacheline_aligned;
 };
 
-- 
1.9.1


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

end of thread, other threads:[~2018-04-04 12:49 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-07 13:20 [PATCH v3 00/11] mmc: sdhci-omap: Add UHS/HS200 mode support Kishon Vijay Abraham I
2018-03-07 13:20 ` [PATCH v3 01/11] mmc: sdhci-omap: Fix when capabilities are obtained from SDHCI_CAPABILITIES reg Kishon Vijay Abraham I
2018-03-15 14:17   ` Adrian Hunter
2018-03-07 13:20 ` [PATCH v3 02/11] mmc: sdhci-omap: Remove setting ADMA capability in driver Kishon Vijay Abraham I
2018-03-15 14:18   ` Adrian Hunter
2018-03-07 13:20 ` [PATCH v3 03/11] mmc: sdhci-omap: Workaround for Errata i843 Kishon Vijay Abraham I
2018-03-15 14:24   ` Adrian Hunter
2018-03-07 13:20 ` [PATCH v3 04/11] mmc: sdhci-omap: Invoke sdhci_get_of_property to read sdhci dt properties Kishon Vijay Abraham I
2018-03-15 14:27   ` Adrian Hunter
2018-03-07 13:20 ` [PATCH v3 05/11] mmc: sdhci: Disable HS200 mode if controller can't support 1.8v Kishon Vijay Abraham I
2018-03-15 10:58   ` Adrian Hunter
2018-03-07 13:20 ` [PATCH v3 06/11] mmc: sdhci: Add quirk to disable HW timeout Kishon Vijay Abraham I
2018-03-15 11:26   ` Adrian Hunter
2018-03-07 13:20 ` [PATCH v3 07/11] mmc: sdhci: Program a relatively accurate SW timeout value Kishon Vijay Abraham I
2018-03-15 13:13   ` Adrian Hunter
2018-03-16  6:29     ` Kishon Vijay Abraham I
2018-03-16 14:21       ` Adrian Hunter
2018-03-19  9:20         ` Kishon Vijay Abraham I
2018-03-19 10:00           ` Adrian Hunter
2018-03-19 10:19             ` Kishon Vijay Abraham I
2018-03-20  9:48               ` Kishon Vijay Abraham I
2018-04-04 12:48                 ` Adrian Hunter
2018-03-07 13:20 ` [PATCH v3 08/11] mmc: sdhci-omap: Workaround for Errata i834 Kishon Vijay Abraham I
2018-03-07 13:20 ` [PATCH v3 09/11] dt-bindings: sdhci-omap: Add K2G specific binding Kishon Vijay Abraham I
2018-03-07 13:20 ` [PATCH v3 10/11] mmc: sdhci-omap: Add support for MMC/SD controller in k2g SoC Kishon Vijay Abraham I
2018-03-07 13:20 ` [PATCH v3 11/11] mmc: sdhci-omap: Add sdhci_omap specific ops for enable_sdio_irq Kishon Vijay Abraham I
2018-03-15 14:34   ` Adrian Hunter
2018-03-07 15:12 ` [PATCH v3 00/11] mmc: sdhci-omap: Add UHS/HS200 mode support Tony Lindgren
2018-03-15  8:47 ` Ulf Hansson
2018-03-15  8:52   ` Adrian Hunter
2018-03-15 10:02     ` Kishon Vijay Abraham I

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).