2013-08-15 14:32:06

by Georgi Djakov

[permalink] [raw]
Subject: [PATCH 0/5] mmc: sdhci: Add quirks for Qualcomm MSM SDHCI controller

This patchset adds quirks for various workarounds and performance
improvements required for Qualcomm MSM SDHCI driver.

1. Read Transfer Active/ Write Transfer Active may be not de-asserted
after end of transaction.
2. Slow interrupt clearance at 400KHz may cause host driver interrupt
handler to be called twice.
3. Controller does not support tuning commands as defined in SD 3.0 spec
and CMD CRC errors are expected for tuning commands.
4. Improve the speed of secure discard operations by not using the
calculated value, but the default one instead.
5. Controller can not handle large timeout values for R1B commands.

Patches are based on v3.11-rc5.

Georgi Djakov (5):
mmc: sdhci: add quirk for R/W Transfer Active EOT
mmc: sdhci: add quirk for slow interrupt clearance
mmc: sdhci: add quirk to ignore CMD CRC err for tuning commands
mmc: sdhci: add quirk for max_discard calculation
mmc: sdhci: add quirk to ignore timeout err for R1B

drivers/mmc/host/sdhci.c | 35 ++++++++++++++++++++++++++++++++++-
include/linux/mmc/sdhci.h | 14 ++++++++++++++
2 files changed, 48 insertions(+), 1 deletion(-)

--
1.7.9.5


2013-08-15 14:32:15

by Georgi Djakov

[permalink] [raw]
Subject: [PATCH 3/5] mmc: sdhci: add quirk to ignore CMD CRC err for tuning commands

The Qualcomm MSM SDHCI controller doesn't support tuning as specified
by the Standard Host Controller 3.0 spec. As a result of which, CMD CRC
errors are expected for tuning commands. Hence, add a new quirk
SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING to ignore those errors for tuning
commands.

CC: Sahitya Tummala <[email protected]>
Signed-off-by: Georgi Djakov <[email protected]>
---
drivers/mmc/host/sdhci.c | 20 ++++++++++++++++++++
include/linux/mmc/sdhci.h | 2 ++
2 files changed, 22 insertions(+)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index d3c9e59..39544b4 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2244,6 +2244,16 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
SDHCI_INT_INDEX))
host->cmd->error = -EILSEQ;

+ if (host->quirks2 & SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING) {
+ if ((host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) ||
+ (host->cmd->opcode == MMC_SEND_TUNING_BLOCK)) {
+ if (intmask & SDHCI_INT_CRC) {
+ sdhci_reset(host, SDHCI_RESET_CMD);
+ host->cmd->error = 0;
+ }
+ }
+ }
+
if (host->cmd->error) {
tasklet_schedule(&host->finish_tasklet);
return;
@@ -2271,6 +2281,16 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
* fall through and take the SDHCI_INT_RESPONSE */
}

+ if (host->quirks2 & SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING) {
+ if ((host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) ||
+ (host->cmd->opcode == MMC_SEND_TUNING_BLOCK)) {
+ if (intmask & SDHCI_INT_CRC) {
+ sdhci_finish_command(host);
+ return;
+ }
+ }
+ }
+
if (intmask & SDHCI_INT_RESPONSE)
sdhci_finish_command(host);
}
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index afd7cdf..603ef9d 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -102,6 +102,8 @@ struct sdhci_host {
#define SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT (1<<6)
/* Controller clears interrupt slowly and IRQ handler may be called twice */
#define SDHCI_QUIRK2_SLOW_INT_CLR (1<<7)
+/* Ignore CMD CRC errors for tuning commands */
+#define SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING (1<<8)

int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */
--
1.7.9.5

2013-08-15 14:32:31

by Georgi Djakov

[permalink] [raw]
Subject: [PATCH 5/5] mmc: sdhci: add quirk to ignore timeout err for R1B

This patch adds a quirk to ignore data timeout error for R1B commands
as there will be no data associated and the busy timeout value for these
commands could be larger than the maximum timeout value that controller
can handle.

CC: Sahitya Tummala <[email protected]>
Signed-off-by: Georgi Djakov <[email protected]>
---
drivers/mmc/host/sdhci.c | 3 +++
include/linux/mmc/sdhci.h | 4 ++++
2 files changed, 7 insertions(+)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index e21bb6f..f120b14 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2353,6 +2353,9 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
}
}

+ if (host->quirks2 & SDHCI_QUIRK2_IGNORE_DATATOUT_FOR_R1BCMD)
+ return;
+
pr_err("%s: Got data interrupt 0x%08x even "
"though no data operation was in progress.\n",
mmc_hostname(host->mmc), (unsigned)intmask);
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index f42f6dd..ad65fb8 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -108,6 +108,10 @@ struct sdhci_host {
* the mmc queue. Otherwise, it takes a long time for secure discard kind of
* operations to complete. */
#define SDHCI_QUIRK2_USE_MAX_DISCARD_SIZE (1<<9)
+/* Ignore data timeout error for R1B commands as there will be no data
+ * associated and the busy timeout value for these commands could be larger
+ * than the maximum timeout value that controller can handle. */
+#define SDHCI_QUIRK2_IGNORE_DATATOUT_FOR_R1BCMD (1<<10)

int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */
--
1.7.9.5

2013-08-15 14:32:13

by Georgi Djakov

[permalink] [raw]
Subject: [PATCH 2/5] mmc: sdhci: add quirk for slow interrupt clearance

Initial version of Qualcomm SDHC has a hardware issue. This patch adds
a quirk SDHCI_QUIRK2_SLOW_INT_CLR to enable a workaround.

Hardware issue: Slow interrupt clearance at 400KHz may cause host
driver interrupt handler to be called twice.

Software workaround: Add 40us delay in interrupt handler when operating at
initialization frequency(400KHz).

CC: Venkat Gopalakrishnan <[email protected]>
CC: Asutosh Das <[email protected]>
CC: Sahitya Tummala <[email protected]>
Signed-off-by: Georgi Djakov <[email protected]>
---
drivers/mmc/host/sdhci.c | 6 ++++++
include/linux/mmc/sdhci.h | 2 ++
2 files changed, 8 insertions(+)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 57659fb..d3c9e59 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2460,12 +2460,18 @@ again:
if (intmask & SDHCI_INT_CMD_MASK) {
sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK,
SDHCI_INT_STATUS);
+ if ((host->quirks2 & SDHCI_QUIRK2_SLOW_INT_CLR) &&
+ (host->clock <= 400000))
+ udelay(40);
sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
}

if (intmask & SDHCI_INT_DATA_MASK) {
sdhci_writel(host, intmask & SDHCI_INT_DATA_MASK,
SDHCI_INT_STATUS);
+ if ((host->quirks2 & SDHCI_QUIRK2_SLOW_INT_CLR) &&
+ (host->clock <= 400000))
+ udelay(40);
sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
}

diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 3783f4c..afd7cdf 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -100,6 +100,8 @@ struct sdhci_host {
#define SDHCI_QUIRK2_BROKEN_HOST_CONTROL (1<<5)
/* Controller cannot de-assert Read/Write Transfer Active after transaction */
#define SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT (1<<6)
+/* Controller clears interrupt slowly and IRQ handler may be called twice */
+#define SDHCI_QUIRK2_SLOW_INT_CLR (1<<7)

int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */
--
1.7.9.5

2013-08-15 14:33:01

by Georgi Djakov

[permalink] [raw]
Subject: [PATCH 1/5] mmc: sdhci: add quirk for R/W Transfer Active EOT

Initial version of Qualcomm SDHC has a hardware issue. This patch adds
a quirk SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT to enable a workaround.

Hardware issue: Read Transfer Active/ Write Transfer Active may be
not de-asserted after end of transaction.

Software workaround: Set Software Reset for DAT line in Software Reset
Register (Bit 2).

CC: Venkat Gopalakrishnan <[email protected]>
CC: Asutosh Das <[email protected]>
CC: Sahitya Tummala <[email protected]>
Signed-off-by: Georgi Djakov <[email protected]>
---
drivers/mmc/host/sdhci.c | 3 +++
include/linux/mmc/sdhci.h | 2 ++
2 files changed, 5 insertions(+)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index a78bd4f..57659fb 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2155,6 +2155,9 @@ static void sdhci_tasklet_finish(unsigned long param)
controllers do not like that. */
sdhci_reset(host, SDHCI_RESET_CMD);
sdhci_reset(host, SDHCI_RESET_DATA);
+ } else {
+ if (host->quirks2 & SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT)
+ sdhci_reset(host, SDHCI_RESET_DATA);
}

host->mrq = NULL;
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index e3c6a74..3783f4c 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -98,6 +98,8 @@ struct sdhci_host {
#define SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON (1<<4)
/* Controller has a non-standard host control register */
#define SDHCI_QUIRK2_BROKEN_HOST_CONTROL (1<<5)
+/* Controller cannot de-assert Read/Write Transfer Active after transaction */
+#define SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT (1<<6)

int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */
--
1.7.9.5

2013-08-15 14:32:58

by Georgi Djakov

[permalink] [raw]
Subject: [PATCH 4/5] mmc: sdhci: add quirk for max_discard calculation

The SDHCI driver by default specifies a parameter that causes the core
layer to calculate a max discard value which will be set on the mmc queue.
Unfortunately the value calculated because of this would be very small
compared to what comes in by default. As a result of this, any secure
discard kind of operations are very slow.

Add quirk so that the SDHCI host can use the default max_discard value.

CC: Krishna Konda <[email protected]>
Signed-off-by: Georgi Djakov <[email protected]>
---
drivers/mmc/host/sdhci.c | 3 ++-
include/linux/mmc/sdhci.h | 4 ++++
2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 39544b4..e21bb6f 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2957,7 +2957,8 @@ int sdhci_add_host(struct sdhci_host *host)
if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
host->timeout_clk = mmc->f_max / 1000;

- mmc->max_discard_to = (1 << 27) / host->timeout_clk;
+ if (!(host->quirks2 & SDHCI_QUIRK2_USE_MAX_DISCARD_SIZE))
+ mmc->max_discard_to = (1 << 27) / host->timeout_clk;

mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;

diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 603ef9d..f42f6dd 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -104,6 +104,10 @@ struct sdhci_host {
#define SDHCI_QUIRK2_SLOW_INT_CLR (1<<7)
/* Ignore CMD CRC errors for tuning commands */
#define SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING (1<<8)
+/* Dont use the max_discard_to so that the maximum discard unit gets picked by
+ * the mmc queue. Otherwise, it takes a long time for secure discard kind of
+ * operations to complete. */
+#define SDHCI_QUIRK2_USE_MAX_DISCARD_SIZE (1<<9)

int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */
--
1.7.9.5