Skip to contentSkip to conversation

SDHCI support for Samsung SoC

PATCH In review Ben Dooks 4 participants 27 messages Nov 3, 2008 – Nov 19, 2008

Subsystems (3)
lore
Share & tools
lore

Ben Dooks

author maintainer
#0 lore raw

cover SDHCI support for Samsung SoC

The following patch set gets working SDHCI on the
Samsung SoC series.

Signature · 3 lines
Ben ([email protected], http://www.fluff.org/)

  'a smiley only costs 4 bytes'
author maintainer
#1 lore raw

PATCH 1/7 SDHCI: Add timeout hooks

Some controllers do not provide clock information in their capabilities (in the Samsung case, it is because there are multiple clock sources available to the controller). Add hooks to allow the system to supply clock information.

drivers/mmc/host/sdhci.c +11 -5
Index: linux.git/drivers/mmc/host/sdhci.c
===================================================================
@@ -1604,17 +1604,23 @@ int sdhci_add_host(struct sdhci_host *ho
 		mmc_dev(host->mmc)->dma_mask = &host->dma_mask;
 	}
 
-	host->max_clk =
-		(caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
+	if (host->ops->get_max_clock)
+		host->max_clk = host->ops->get_max_clock(host);
+	else {
+		host->max_clk =	(caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
+		host->max_clk *= 1000000;
+	}
 	if (host->max_clk == 0) {
 		printk(KERN_ERR "%s: Hardware doesn't specify base clock "
 			"frequency.\n", mmc_hostname(mmc));
 		return -ENODEV;
 	}
-	host->max_clk *= 1000000;
 
-	host->timeout_clk =
-		(caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
+	if (host->ops->get_timeout_clock)
+		host->timeout_clk = host->ops->get_timeout_clock(host);
+	else
+		host->timeout_clk =
+			(caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
 	if (host->timeout_clk == 0) {
 		printk(KERN_ERR "%s: Hardware doesn't specify timeout clock "
 			"frequency.\n", mmc_hostname(mmc));
drivers/mmc/host/sdhci.h +2 -0
Index: linux.git/drivers/mmc/host/sdhci.h
===================================================================
@@ -267,6 +267,8 @@ struct sdhci_host {
 
 struct sdhci_ops {
 	int		(*enable_dma)(struct sdhci_host *host);
+	unsigned int	(*get_max_clock)(struct sdhci_host *host);
+	unsigned int	(*get_timeout_clock)(struct sdhci_host *host);
 };
 
 
Signature · 3 lines
Ben ([email protected], http://www.fluff.org/)

  'a smiley only costs 4 bytes'
#2 lore raw

Re: [patch 1/7] SDHCI: Add timeout hooks

Quoted 7 lines · On Mon, 03 Nov 2008 20:09:45 +0000 Ben Dooks <[email protected]> wrote:

Some controllers do not provide clock information in their capabilities (in the Samsung case, it is because there are multiple clock sources available to the controller). Add hooks to allow the system to supply clock information.

Could we at least initally try to strictly adhere to the SDHCI spec and only use the callback if the controller reports 0 for the freqs?

Rgds

Signature · 9 lines
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  rdesktop, core developer          http://www.rdesktop.org

  WARNING: This correspondence is being monitored by the
  Swedish government. Make sure your server uses encryption
  for SMTP traffic and consider using PGP for end-to-end
  encryption.
author maintainer
#3 lore raw

PATCH 2/7 SDHCI: Print ADMA status and pointer on debug

In reply to Ben Dooks

If using ADMA, then we should print the ADMA error and current pointer in sdhci_dumpregs() when any debug is requested.

drivers/mmc/host/sdhci.c +5 -0
@@ -73,6 +73,11 @@ static void sdhci_dumpregs(struct sdhci_
 		readl(host->ioaddr + SDHCI_CAPABILITIES),
 		readl(host->ioaddr + SDHCI_MAX_CURRENT));
 
+	if (host->flags & SDHCI_USE_ADMA)
+		printk(KERN_DEBUG DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
+		       readl(host->ioaddr + SDHCI_ADMA_ERROR),
+		       readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
+
 	printk(KERN_DEBUG DRIVER_NAME ": ===========================================\n");
 }
 
Signature · 3 lines
Ben ([email protected], http://www.fluff.org/)

  'a smiley only costs 4 bytes'
#4 lore raw

Re: [patch 2/7] SDHCI: Print ADMA status and pointer on debug

Quoted 6 lines · On Mon, 03 Nov 2008 20:09:46 +0000 Ben Dooks <[email protected]> wrote:

If using ADMA, then we should print the ADMA error and current pointer in sdhci_dumpregs() when any debug is requested.

Looks ok. I think that dump routine could use some more TLC to be really useful.

Rgds

Signature · 9 lines
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  rdesktop, core developer          http://www.rdesktop.org

  WARNING: This correspondence is being monitored by the
  Swedish government. Make sure your server uses encryption
  for SMTP traffic and consider using PGP for end-to-end
  encryption.
author maintainer
#5 lore raw

PATCH 3/7 SDHCI: Add set_ios hook

In reply to Ben Dooks

Add a set_ios hook which is called when the SDHCI driver is called to change parameters such as clock or card width.

drivers/mmc/host/sdhci.c +3 -0
@@ -1038,6 +1038,9 @@ static void sdhci_set_ios(struct mmc_hos
 		sdhci_init(host);
 	}
 
+	if (host->ops->set_ios)
+		host->ops->set_ios(host, ios);
+
 	sdhci_set_clock(host, ios->clock);
 
 	if (ios->power_mode == MMC_POWER_OFF)
drivers/mmc/host/sdhci.h +3 -0
@@ -269,6 +269,9 @@ struct sdhci_ops {
 	int		(*enable_dma)(struct sdhci_host *host);
 	unsigned int	(*get_max_clock)(struct sdhci_host *host);
 	unsigned int	(*get_timeout_clock)(struct sdhci_host *host);
+
+	void		(*set_ios)(struct sdhci_host *host,
+				   struct mmc_ios *ios);
 };
 
 
Signature · 3 lines
Ben ([email protected], http://www.fluff.org/)

  'a smiley only costs 4 bytes'
#6 lore raw

Re: [patch 3/7] SDHCI: Add set_ios hook

Quoted 6 lines · On Mon, 03 Nov 2008 20:09:47 +0000 Ben Dooks <[email protected]> wrote:

Add a set_ios hook which is called when the SDHCI driver is called to change parameters such as clock or card width.

Hmm... this is very general and very much undefined. I think we need to have some kind of formal API here or I might end up breaking S3C support when I hack away at the driver.

Preferable, I'd like to see a more fine grained set of callbacks.

Signature · 9 lines
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  rdesktop, core developer          http://www.rdesktop.org

  WARNING: This correspondence is being monitored by the
  Swedish government. Make sure your server uses encryption
  for SMTP traffic and consider using PGP for end-to-end
  encryption.
author maintainer
#7 lore raw

PATCH 4/7 SDHCI: Add quirk for controller with no end-of-busy IRQ

In reply to Ben Dooks

The Samsung SDHCI controller block seems to fail to generate an INT_DATA_END after the transfer has completed and the bus busy state finished.

Changes in e809517f6fa5803a5a1cd56026f0e2190fc13d5c to use the new busy method are the cause of the behaviour change.

drivers/mmc/host/sdhci.c +14 -1
Index: linux.git/drivers/mmc/host/sdhci.c
===================================================================
@@ -1291,11 +1291,24 @@ static void sdhci_cmd_irq(struct sdhci_h
 	 *       controllers.
 	 */
 	if (host->cmd->flags & MMC_RSP_BUSY) {
+		u32 present;
+
 		if (host->cmd->data)
 			DBG("Cannot wait for busy signal when also "
 				"doing a data transfer");
-		else
+		else if (!(host->quirks & SDHCI_QUIRK_NO_TCIRQ_ON_NOT_BUSY))
 			return;
+
+		/* The Samsung SDHCI does not seem to provide an INT_DATA_END
+		 * when the system goes non-busy, so check the state of the
+		 * transfer by reading SDHCI_PRESENT_STATE to see if the
+		 * controller is ready
+		 */
+
+		present = readl(host->ioaddr + SDHCI_PRESENT_STATE);
+		DBG("busy? present %08x, intstat %08x\n", present, intmask);
+
+		/* fall through and take the SDHCI_INT_RESPONSE */
 	}
 
 	if (intmask & SDHCI_INT_RESPONSE)
drivers/mmc/host/sdhci.h +3 -0
Index: linux.git/drivers/mmc/host/sdhci.h
===================================================================
@@ -57,6 +57,7 @@
 #define  SDHCI_DATA_AVAILABLE	0x00000800
 #define  SDHCI_CARD_PRESENT	0x00010000
 #define  SDHCI_WRITE_PROTECT	0x00080000
+#define  SDHCI_DATA_BIT(x)	(1 << ((x) + 20))
 
 #define SDHCI_HOST_CONTROL 	0x28
 #define  SDHCI_CTRL_LED		0x01
@@ -210,6 +211,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK_BROKEN_SMALL_PIO			(1<<13)
 /* Controller supports high speed but doesn't have the caps bit set */
 #define SDHCI_QUIRK_FORCE_HIGHSPEED			(1<<14)
+/* Controller does not provide transfer-complete interrupt when not busy */
+#define SDHCI_QUIRK_NO_TCIRQ_ON_NOT_BUSY		(1<<15)
 
 	int			irq;		/* Device IRQ */
 	void __iomem *		ioaddr;		/* Mapped address */
Signature · 3 lines
Ben ([email protected], http://www.fluff.org/)

  'a smiley only costs 4 bytes'
#8 lore raw

Re: [patch 4/7] SDHCI: Add quirk for controller with no end-of-busy IRQ

Quoted 15 lines · On Mon, 03 Nov 2008 20:09:48 +0000 Ben Dooks <[email protected]> wrote:

The Samsung SDHCI controller block seems to fail to generate an INT_DATA_END after the transfer has completed and the bus busy state finished.

Changes in e809517f6fa5803a5a1cd56026f0e2190fc13d5c to use the new busy method are the cause of the behaviour change.

Index: linux.git/drivers/mmc/host/sdhci.c
===================================================================

drivers/mmc/host/sdhci.c +0 -0
@@ -1291,11 +1291,24 @@ static void sdhci_cmd_irq(struct sdhci_h
 	 *       controllers.

drivers/mmc/host/sdhci.c static void sdhci_cmd_irq(struct sdhci_h · line 1300

Quoted 10 lines
drivers/mmc/host/sdhci.c +3 -1
 	 */
 	if (host->cmd->flags & MMC_RSP_BUSY) {
+		u32 present;
+
 		if (host->cmd->data)
 			DBG("Cannot wait for busy signal when also "
 				"doing a data transfer");
-		else
+		else if (!(host->quirks & SDHCI_QUIRK_NO_TCIRQ_ON_NOT_BUSY))
 			return;

Not the clearest naming I've ever seen. :)
How about NO_BUSY_IRQ?

drivers/mmc/host/sdhci.c static void sdhci_cmd_irq(struct sdhci_h · line 1306

Quoted 6 lines
drivers/mmc/host/sdhci.c +6 -0
+
+		/* The Samsung SDHCI does not seem to provide an INT_DATA_END
+		 * when the system goes non-busy, so check the state of the
+		 * transfer by reading SDHCI_PRESENT_STATE to see if the
+		 * controller is ready
+		 */

There is already a note about this being a problem earlier up, so I don't think we need another.

drivers/mmc/host/sdhci.c static void sdhci_cmd_irq(struct sdhci_h · line 1310

Quoted 4 lines
drivers/mmc/host/sdhci.c +4 -0
+
+		present = readl(host->ioaddr + SDHCI_PRESENT_STATE);
+		DBG("busy? present %08x, intstat %08x\n", present, intmask);
+

And what does this add really? Controllers not being able to wait for the busy state to end is so common that we can just ignore the problem here.

drivers/mmc/host/sdhci.c static void sdhci_cmd_irq(struct sdhci_h · line 1311

Quoted 1 line
drivers/mmc/host/sdhci.c +1 -0
+#define  SDHCI_DATA_BIT(x)	(1 << ((x) + 20))

This was not supposed to be included I suppose :)

Rgds

Signature · 9 lines
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  rdesktop, core developer          http://www.rdesktop.org

  WARNING: This correspondence is being monitored by the
  Swedish government. Make sure your server uses encryption
  for SMTP traffic and consider using PGP for end-to-end
  encryption.
author maintainer
#9 lore raw

Re: [patch 4/7] SDHCI: Add quirk for controller with no end-of-busy IRQ

Quoted 23 lines · Pierre Ossman
Quoted 20 lines · On Mon, 03 Nov 2008 20:09:48 +0000 Ben Dooks <[email protected]> wrote:

The Samsung SDHCI controller block seems to fail to generate an INT_DATA_END after the transfer has completed and the bus busy state finished.

Changes in e809517f6fa5803a5a1cd56026f0e2190fc13d5c to use the new busy method are the cause of the behaviour change.

Index: linux.git/drivers/mmc/host/sdhci.c
===================================================================

drivers/mmc/host/sdhci.c +2 -0
@@ -1291,11 +1291,24 @@ static void sdhci_cmd_irq(struct sdhci_h
 	 *       controllers.
 	 */
 	if (host->cmd->flags & MMC_RSP_BUSY) {
+		u32 present;
+
 		if (host->cmd->data)
Quoted 8 lines

drivers/mmc/host/sdhci.c static void sdhci_cmd_irq(struct sdhci_h · line 1300

Quoted 5 lines
drivers/mmc/host/sdhci.c +1 -1
 			DBG("Cannot wait for busy signal when also "
 				"doing a data transfer");
-		else
+		else if (!(host->quirks & SDHCI_QUIRK_NO_TCIRQ_ON_NOT_BUSY))
 			return;

Not the clearest naming I've ever seen. :)
How about NO_BUSY_IRQ?

ok, will change.

Quoted 9 lines

drivers/mmc/host/sdhci.c static void sdhci_cmd_irq(struct sdhci_h · line 1306

Quoted 6 lines
drivers/mmc/host/sdhci.c +6 -0
+
+		/* The Samsung SDHCI does not seem to provide an INT_DATA_END
+		 * when the system goes non-busy, so check the state of the
+		 * transfer by reading SDHCI_PRESENT_STATE to see if the
+		 * controller is ready
+		 */

There is already a note about this being a problem earlier up, so I don't think we need another.

right.

Quoted 9 lines

drivers/mmc/host/sdhci.c static void sdhci_cmd_irq(struct sdhci_h · line 1310

Quoted 4 lines
drivers/mmc/host/sdhci.c +4 -0
+
+		present = readl(host->ioaddr + SDHCI_PRESENT_STATE);
+		DBG("busy? present %08x, intstat %08x\n", present, intmask);
+

And what does this add really? Controllers not being able to wait for the busy state to end is so common that we can just ignore the problem here.

that was debug.

Quoted 3 lines

drivers/mmc/host/sdhci.c static void sdhci_cmd_irq(struct sdhci_h · line 1311

Quoted 1 line
drivers/mmc/host/sdhci.c +1 -0
+#define  SDHCI_DATA_BIT(x)	(1 << ((x) + 20))

This was not supposed to be included I suppose :)

was with teh debug.

Signature · 3 lines
Ben ([email protected], http://www.fluff.org/)

  'a smiley only costs 4 bytes'
author maintainer
#10 lore raw

PATCH 5/7 SDHCI: Samsung SDHCI (HSMMC) driver

In reply to Ben Dooks

Add support for the 'HSMMC' block(s) in the Samsung SoC line. These are compatible with the SDHCI driver so add the necessary setup and driver binding for the platform devices.

drivers/mmc/host/Kconfig +12 -0
Index: linux.git/drivers/mmc/host/Kconfig
===================================================================
@@ -48,6 +48,18 @@ config MMC_SDHCI_PCI
 
 	  If unsure, say N.
 
+config MMC_SDHCI_S3C
+	tristate "SDHCI support on Samsung S3C SoC"
+	depends on MMC_SDHCI && (PLAT_S3C24XX || PLAT_S3C64XX)
+	help
+	  This selects the Secure Digital Host Controller Interface (SDHCI)
+	  often referrered to as the HSMMC block in some of the Samsung S3C
+	  range of SoC.
+
+	  If you have a controller with this interface, say Y or M here.
+
+	  If unsure, say N.
+
 config MMC_RICOH_MMC
 	tristate "Ricoh MMC Controller Disabler  (EXPERIMENTAL)"
 	depends on MMC_SDHCI_PCI
drivers/mmc/host/Makefile +1 -0
Index: linux.git/drivers/mmc/host/Makefile
===================================================================
@@ -11,6 +11,7 @@ obj-$(CONFIG_MMC_PXA)		+= pxamci.o
 obj-$(CONFIG_MMC_IMX)		+= imxmmc.o
 obj-$(CONFIG_MMC_SDHCI)		+= sdhci.o
 obj-$(CONFIG_MMC_SDHCI_PCI)	+= sdhci-pci.o
+obj-$(CONFIG_MMC_SDHCI_S3C)	+= sdhci-s3c.o
 obj-$(CONFIG_MMC_RICOH_MMC)	+= ricoh_mmc.o
 obj-$(CONFIG_MMC_WBSD)		+= wbsd.o
 obj-$(CONFIG_MMC_AU1X)		+= au1xmmc.o
drivers/mmc/host/sdhci-s3c.c new file +294 -0

294 lines not on this page · raw message

Signature · 3 lines
Ben ([email protected], http://www.fluff.org/)

  'a smiley only costs 4 bytes'
#11 lore raw

Re: [patch 5/7] SDHCI: Samsung SDHCI (HSMMC) driver

Quoted 4 lines · On Mon, 03 Nov 2008 20:09:49 +0000 Ben Dooks <[email protected]> wrote:
drivers/mmc/host/sdhci-s3c.c new file +4 -0
+static void sdhci_s3c_sel_sclk(struct sdhci_host *host)
+{
+	struct sdhci_s3c *ourhost = to_s3c(host);
+

drivers/mmc/host/sdhci-s3c.c line 58

Quoted 10 lines
drivers/mmc/host/sdhci-s3c.c new file +10 -0
+	/* select sclk */
+	u32 tmp = readl(host->ioaddr + 0x80);
+
+	if ((tmp & (3 << 4)) == (2 << 4))
+		return;
+
+	tmp &= ~(3<<4);
+	tmp |= (2 << 4);
+	writel(tmp, host->ioaddr + 0x80);
+}

No defines for this? This is not terribly readable.

drivers/mmc/host/sdhci-s3c.c line 110

Quoted 3 lines
drivers/mmc/host/sdhci-s3c.c new file +3 -0
+	if (pdata->cfg_card)
+		pdata->cfg_card(ourhost->pdev, host->ioaddr,
+				ios, host->mmc->card);

What's the deal here? Hosts shouldn't know more about the card than the MMC core tells them.

Since I have no hardware for this, could you take it upon you to handle support for these chips? I'd like a MAINTAINERS patch for that as well.

Rgds

Signature · 9 lines
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  rdesktop, core developer          http://www.rdesktop.org

  WARNING: This correspondence is being monitored by the
  Swedish government. Make sure your server uses encryption
  for SMTP traffic and consider using PGP for end-to-end
  encryption.
author maintainer
#12 lore raw

Re: [patch 5/7] SDHCI: Samsung SDHCI (HSMMC) driver

Quoted 19 lines · Pierre Ossman
Quoted 4 lines · On Mon, 03 Nov 2008 20:09:49 +0000 Ben Dooks <[email protected]> wrote:
drivers/mmc/host/sdhci-s3c.c new file +4 -0
+static void sdhci_s3c_sel_sclk(struct sdhci_host *host)
+{
+	struct sdhci_s3c *ourhost = to_s3c(host);
+

drivers/mmc/host/sdhci-s3c.c line 58

Quoted 10 lines
drivers/mmc/host/sdhci-s3c.c new file +10 -0
+	/* select sclk */
+	u32 tmp = readl(host->ioaddr + 0x80);
+
+	if ((tmp & (3 << 4)) == (2 << 4))
+		return;
+
+	tmp &= ~(3<<4);
+	tmp |= (2 << 4);
+	writel(tmp, host->ioaddr + 0x80);
+}

No defines for this? This is not terribly readable.

it was only temporary to ensure that if people bisected before the clock callback was added the host would at least work even if it was locked to one clock input.

Quoted 6 lines

drivers/mmc/host/sdhci-s3c.c line 110

Quoted 3 lines
drivers/mmc/host/sdhci-s3c.c new file +3 -0
+	if (pdata->cfg_card)
+		pdata->cfg_card(ourhost->pdev, host->ioaddr,
+				ios, host->mmc->card);

What's the deal here? Hosts shouldn't know more about the card than the MMC core tells them.

Depending on exactly which version, there's a number of configurations in the extra configuration registers that get changed, such as delays used for clock feedback which are meant to be chnaged when the speed of the card is changed. Unfortunately this changes depending on the chip model and possibly also on the board it is on.

The other is that it is possible that depending on the chip and board combination things like the GPIO driver-strength controls will need to be changed.

Quoted 2 lines

Since I have no hardware for this, could you take it upon you to handle support for these chips? I'd like a MAINTAINERS patch for that as well.

ok, i'll add it to the list.

Signature · 3 lines
Ben ([email protected], http://www.fluff.org/)

  'a smiley only costs 4 bytes'
#13 lore raw

Re: [patch 5/7] SDHCI: Samsung SDHCI (HSMMC) driver

Quoted 16 lines · On Sun, 16 Nov 2008 00:03:02 +0000 Ben Dooks <[email protected]> wrote:
Quoted 8 lines · Pierre Ossman

drivers/mmc/host/sdhci-s3c.c line 110

Quoted 3 lines · On Mon, 03 Nov 2008 20:09:49 +0000 Ben Dooks <[email protected]> wrote:
drivers/mmc/host/sdhci-s3c.c new file +3 -0
+	if (pdata->cfg_card)
+		pdata->cfg_card(ourhost->pdev, host->ioaddr,
+				ios, host->mmc->card);

What's the deal here? Hosts shouldn't know more about the card than the MMC core tells them.

Depending on exactly which version, there's a number of configurations in the extra configuration registers that get changed, such as delays used for clock feedback which are meant to be chnaged when the speed of the card is changed. Unfortunately this changes depending on the chip model and possibly also on the board it is on.

Quoted 3 lines

The other is that it is possible that depending on the chip and board combination things like the GPIO driver-strength controls will need to be changed.

I don't see where knowledge about the card gets into the picture here. All of this sounds like information that is gathered from platform data and/or ios information.

Signature · 9 lines
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  rdesktop, core developer          http://www.rdesktop.org

  WARNING: This correspondence is being monitored by the
  Swedish government. Make sure your server uses encryption
  for SMTP traffic and consider using PGP for end-to-end
  encryption.
author maintainer
#14 lore raw

PATCH 6/7 SDHCI: Check DMA for overruns at end of transfer

In reply to Ben Dooks

At the end of a transfer, check that the DMA engine in the SDHCI controller actually did what it was meant to and didn't overrun the end of the buffer.

This seems to be triggered by a timeout during an CMD25 (multiple block write) to a card. The mmc_block module then issues a command to find out how much data was moved and this seems to end up triggering this DMA check. The result is the card's queue generates an OOPS as the stack has been trampled on due to the extra data transfered.

drivers/mmc/host/sdhci.c +19 -0
Index: linux.git/drivers/mmc/host/sdhci.c
===================================================================
@@ -736,6 +736,23 @@ static void sdhci_set_transfer_mode(stru
 	writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE);
 }
 
+static void shdci_check_dma_overrun(struct sdhci_host *host, struct mmc_data *data)
+{
+	u32 dma_pos = readl(host->ioaddr + SDHCI_DMA_ADDRESS);
+	u32 dma_start = sg_dma_address(data->sg);
+	u32 dma_end = dma_start + data->sg->length;
+
+	/* Test whether we ended up moving more data than
+	 * was originally requested. */
+
+	if (dma_pos <= dma_end)
+		return;
+
+	printk(KERN_ERR "%s: dma overrun, dma %08x, req %08x..%08x\n",
+	       mmc_hostname(host->mmc), dma_pos,
+	       dma_start, dma_end);
+}
+
 static void sdhci_finish_data(struct sdhci_host *host)
 {
 	struct mmc_data *data;
@@ -749,6 +766,8 @@ static void sdhci_finish_data(struct sdh
 		if (host->flags & SDHCI_USE_ADMA)
 			sdhci_adma_table_post(host, data);
 		else {
+			shdci_check_dma_overrun(host, data);
+
 			dma_unmap_sg(mmc_dev(host->mmc), data->sg,
 				data->sg_len, (data->flags & MMC_DATA_READ) ?
 					DMA_FROM_DEVICE : DMA_TO_DEVICE);
Signature · 3 lines
Ben ([email protected], http://www.fluff.org/)

  'a smiley only costs 4 bytes'
#15 lore raw

Re: [patch 6/7] SDHCI: Check DMA for overruns at end of transfer

Maybe I didn't understand it right, but if the DMA controller could overrun a buffer, don't you ALSO need to add defensive padding (i.e. increase the buffer) to make sure nothing important gets overrun?

Signature · 4 lines
  "One disk to rule them all, One disk to find them. One disk to bring
  them all and in the darkness grind them. In the Land of Redmond
  where the shadows lie." -- The Silicon Valley Tarot
  Henrique Holschuh
author maintainer
#16 lore raw

Re: [patch 6/7] SDHCI: Check DMA for overruns at end of transfer

Quoted 3 lines · Henrique de Moraes Holschuh

Maybe I didn't understand it right, but if the DMA controller could overrun a buffer, don't you ALSO need to add defensive padding (i.e. increase the buffer) to make sure nothing important gets overrun?

This is only generated by problems elsewhere in the driver, such as getting the timeout clock wrong. It is here just as a precaution and as an aide to debugging, it should not trigger in normal circumstances.

There is a seperate problem where the DMA buffer is passed from the stack which is, IIRC, a complete no-no under Linux.

Signature · 4 lines
Ben

Q:      What's a light-year?
A:      One-third less calories than a regular year.
#17 lore raw

Re: [patch 6/7] SDHCI: Check DMA for overruns at end of transfer

Quoted 8 lines · Ben Dooks
Quoted 3 lines · Henrique de Moraes Holschuh

Maybe I didn't understand it right, but if the DMA controller could overrun a buffer, don't you ALSO need to add defensive padding (i.e. increase the buffer) to make sure nothing important gets overrun?

This is only generated by problems elsewhere in the driver, such as getting the timeout clock wrong. It is here just as a precaution and as an aide to debugging, it should not trigger in normal circumstances.

Then why is it just a WARN_ON, since you had a rogue DMA operation overwriting unknown kernel memory? Seems like an outright BUG_ON to me.

Quoted 2 lines

There is a seperate problem where the DMA buffer is passed from the stack which is, IIRC, a complete no-no under Linux.

Can't say much on that. I just found it strange that something as damaging as an overrun was only getting a WARN_ON and no defensive measure. If it is not going to happen normally, it might not require a defensive buffer, but once it happens, it looks like one must reboot ASAP from what you said...

Signature · 4 lines
  "One disk to rule them all, One disk to find them. One disk to bring
  them all and in the darkness grind them. In the Land of Redmond
  where the shadows lie." -- The Silicon Valley Tarot
  Henrique Holschuh
#18 lore raw

Re: [patch 6/7] SDHCI: Check DMA for overruns at end of transfer

Quoted 6 lines · Henrique de Moraes Holschuh
Quoted 5 lines · Ben Dooks
Quoted 3 lines · Henrique de Moraes Holschuh

Maybe I didn't understand it right, but if the DMA controller could overrun a buffer, don't you ALSO need to add defensive padding (i.e. increase the buffer) to make sure nothing important gets overrun?

Quoted 6 lines
Quoted 3 lines

This is only generated by problems elsewhere in the driver, such as getting the timeout clock wrong. It is here just as a precaution and as an aide to debugging, it should not trigger in normal circumstances.

Then why is it just a WARN_ON, since you had a rogue DMA operation overwriting unknown kernel memory? Seems like an outright BUG_ON to me.

It is a problem, but it doesn't kill the entire system. We could print it at a higher level. The WARN_ON()/BUG_ON() where not appropriate, as we do not need a whole stack backtrace, and I belive the mmc block thread somehow seems to manage to keep running even with an OOPS.

Quoted 7 lines
Quoted 2 lines

There is a seperate problem where the DMA buffer is passed from the stack which is, IIRC, a complete no-no under Linux.

Can't say much on that. I just found it strange that something as damaging as an overrun was only getting a WARN_ON and no defensive measure. If it is not going to happen normally, it might not require a defensive buffer, but once it happens, it looks like one must reboot ASAP from what you said...

Signature · 3 lines
Ben ([email protected], http://www.fluff.org/)

  'a smiley only costs 4 bytes'
#19 lore raw

Re: [patch 6/7] SDHCI: Check DMA for overruns at end of transfer

In reply to Ben Dooks
Quoted 11 lines · On Mon, 03 Nov 2008 20:09:50 +0000 Ben Dooks <[email protected]> wrote:

At the end of a transfer, check that the DMA engine in the SDHCI controller actually did what it was meant to and didn't overrun the end of the buffer.

This seems to be triggered by a timeout during an CMD25 (multiple block write) to a card. The mmc_block module then issues a command to find out how much data was moved and this seems to end up triggering this DMA check. The result is the card's queue generates an OOPS as the stack has been trampled on due to the extra data transfered.

I'm sorry, but I don't see how this is anywhere near acceptable. This should be a panic at the very least, and until this can be sorted out and avoided the driver should avoid using DMA on these chips.

Signature · 9 lines
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  rdesktop, core developer          http://www.rdesktop.org

  WARNING: This correspondence is being monitored by the
  Swedish government. Make sure your server uses encryption
  for SMTP traffic and consider using PGP for end-to-end
  encryption.
author maintainer
#20 lore raw

Re: [patch 6/7] SDHCI: Check DMA for overruns at end of transfer

Quoted 13 lines · Pierre Ossman
Quoted 10 lines · On Mon, 03 Nov 2008 20:09:50 +0000 Ben Dooks <[email protected]> wrote:

At the end of a transfer, check that the DMA engine in the SDHCI controller actually did what it was meant to and didn't overrun the end of the buffer.

This seems to be triggered by a timeout during an CMD25 (multiple block write) to a card. The mmc_block module then issues a command to find out how much data was moved and this seems to end up triggering this DMA check. The result is the card's queue generates an OOPS as the stack has been trampled on due to the extra data transfered.

Quoted 5 lines
Quoted 1 line

I'm sorry, but I don't see how this is anywhere near acceptable. This should be a panic at the very least, and until this can be sorted out and avoided the driver should avoid using DMA on these chips.

A panic won't help get the debug logs out of the kernel. This only turned up whilst debugging the controller, I got the timeout clock calculation wrong and thus ended up timing out pretty much all the CMD25s and seeing this problem.

Signature · 3 lines
Ben ([email protected], http://www.fluff.org/)

  'a smiley only costs 4 bytes'
#21 lore raw

Re: [patch 6/7] SDHCI: Check DMA for overruns at end of transfer

Quoted 7 lines · On Sun, 16 Nov 2008 00:05:08 +0000 Ben Dooks <[email protected]> wrote:
Quoted 4 lines · Pierre Ossman

I'm sorry, but I don't see how this is anywhere near acceptable. This should be a panic at the very least, and until this can be sorted out and avoided the driver should avoid using DMA on these chips.

A panic won't help get the debug logs out of the kernel.

Indeed, but it will avoid corrupting the system.

Quoted 5 lines

This only
turned up whilst debugging the controller, I got the timeout clock calculation wrong and thus ended up timing out pretty much all the CMD25s and seeing this problem.

Just because you had to provoke it doesn't mean it won't appear under "normal" circumstances for others.

Until this problem is fully understood I think DMA should be turned off (or possibly needs to be explicitly forced on using Kconfig or a module parameter).

Do you have any contacts at Samsung that can help out here?

Rgds

Signature · 9 lines
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  rdesktop, core developer          http://www.rdesktop.org

  WARNING: This correspondence is being monitored by the
  Swedish government. Make sure your server uses encryption
  for SMTP traffic and consider using PGP for end-to-end
  encryption.
author maintainer
#22 lore raw

PATCH 7/7 SDHCI: Add change_clock callback for glue drivers

In reply to Ben Dooks

Add a change_clock callback to allow drivers to update device specific clock selections and control registers when there is a change in clock.

Move the main part of sdhci_set_clock() to a new routine which can be called by the glue drivers to do the sdhci standard clock management.

Update the sdhci-s3c driver to use this to select the appropriate clock source when clocks change.

drivers/mmc/host/sdhci-pci.c +1 -0
Index: linux.git/drivers/mmc/host/sdhci-pci.c
===================================================================
@@ -391,6 +391,7 @@ static int sdhci_pci_enable_dma(struct s
 
 static struct sdhci_ops sdhci_pci_ops = {
 	.enable_dma	= sdhci_pci_enable_dma,
+	.change_clock	= sdhci_change_clock,
 };
 
 /*****************************************************************************\
drivers/mmc/host/sdhci-s3c.c +99 -18

172 lines not on this page · raw message

drivers/mmc/host/sdhci.c +10 -3
Index: linux.git/drivers/mmc/host/sdhci.c
===================================================================
@@ -907,13 +907,18 @@ static void sdhci_finish_command(struct 
 
 static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 {
+	if (clock == host->clock)
+		return;
+
+	host->ops->change_clock(host, clock);
+}
+
+void sdhci_change_clock(struct sdhci_host *host, unsigned int clock)
+{
 	int div;
 	u16 clk;
 	unsigned long timeout;
 
-	if (clock == host->clock)
-		return;
-
 	writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
 
 	if (clock == 0)
@@ -950,6 +955,8 @@ out:
 	host->clock = clock;
 }
 
+EXPORT_SYMBOL_GPL(sdhci_set_clock);
+
 static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
 {
 	u8 pwr;
drivers/mmc/host/sdhci.h +5 -0
Index: linux.git/drivers/mmc/host/sdhci.h
===================================================================
@@ -273,6 +273,9 @@ struct sdhci_ops {
 	unsigned int	(*get_max_clock)(struct sdhci_host *host);
 	unsigned int	(*get_timeout_clock)(struct sdhci_host *host);
 
+	void		(*change_clock)(struct sdhci_host *host,
+					unsigned int clock);
+
 	void		(*set_ios)(struct sdhci_host *host,
 				   struct mmc_ios *ios);
 };
@@ -282,6 +285,8 @@ extern struct sdhci_host *sdhci_alloc_ho
 	size_t priv_size);
 extern void sdhci_free_host(struct sdhci_host *host);
 
+extern void sdhci_change_clock(struct sdhci_host *host, unsigned int clock);
+
 static inline void *sdhci_priv(struct sdhci_host *host)
 {
 	return (void *)host->private;
Signature · 3 lines
Ben ([email protected], http://www.fluff.org/)

  'a smiley only costs 4 bytes'
#23 lore raw

Re: [patch 7/7] SDHCI: Add change_clock callback for glue drivers

Quoted 4 lines · On Mon, 03 Nov 2008 20:09:51 +0000 Ben Dooks <[email protected]> wrote:

Add a change_clock callback to allow drivers to update device specific clock selections and control registers when there is a change in clock.

Quoted 9 lines

Move the main part of sdhci_set_clock() to a new routine which can be called by the glue drivers to do the sdhci standard clock management.

Update the sdhci-s3c driver to use this to select the appropriate clock source when clocks change.

I'm afraid I don't quite follow on the requirements here. Care to elaborate as to why this is needed?

drivers/mmc/host/sdhci-pci.c static int sdhci_pci_enable_dma(struct s · line 397

Quoted 12 lines

Index: linux.git/drivers/mmc/host/sdhci-pci.c
===================================================================

drivers/mmc/host/sdhci-pci.c +1 -0
@@ -391,6 +391,7 @@ static int sdhci_pci_enable_dma(struct s
 
 static struct sdhci_ops sdhci_pci_ops = {
 	.enable_dma	= sdhci_pci_enable_dma,
+	.change_clock	= sdhci_change_clock,
 };
 
 /*****************************************************************************\

This seems pointless :)

drivers/mmc/host/sdhci-pci.c out: · line 959

Quoted 6 lines
drivers/mmc/host/sdhci-pci.c +2 -0
@@ -950,6 +955,8 @@ out:
 	host->clock = clock;
 }
 
+EXPORT_SYMBOL_GPL(sdhci_set_clock);
+

Wrong symbol. :)

Signature · 9 lines
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  rdesktop, core developer          http://www.rdesktop.org

  WARNING: This correspondence is being monitored by the
  Swedish government. Make sure your server uses encryption
  for SMTP traffic and consider using PGP for end-to-end
  encryption.
author maintainer
#24 lore raw

Re: [patch 7/7] SDHCI: Add change_clock callback for glue drivers

Quoted 11 lines · Pierre Ossman
Quoted 8 lines · On Mon, 03 Nov 2008 20:09:51 +0000 Ben Dooks <[email protected]> wrote:

Add a change_clock callback to allow drivers to update device specific clock selections and control registers when there is a change in clock.

Move the main part of sdhci_set_clock() to a new routine which can be called by the glue drivers to do the sdhci standard clock management.

Quoted 8 lines
Quoted 5 lines

Update the sdhci-s3c driver to use this to select the appropriate clock source when clocks change.

I'm afraid I don't quite follow on the requirements here. Care to elaborate as to why this is needed?

The controller has a number of possible clock sources, the bus clock it is connected to (generally called hclk) and three more clocks from the heirachy that is muxed/divided from either an 48MHz, 27MHz or the EPLL.

The callback allows the recalculation and selection of the best clock to run the card clock for the controller.

Quoted 15 lines

drivers/mmc/host/sdhci-pci.c static int sdhci_pci_enable_dma(struct s · line 397

Quoted 12 lines

Index: linux.git/drivers/mmc/host/sdhci-pci.c
===================================================================

drivers/mmc/host/sdhci-pci.c +1 -0
@@ -391,6 +391,7 @@ static int sdhci_pci_enable_dma(struct s
 
 static struct sdhci_ops sdhci_pci_ops = {
 	.enable_dma	= sdhci_pci_enable_dma,
+	.change_clock	= sdhci_change_clock,
 };
 
 /*****************************************************************************\

This seems pointless :)

Quoted 8 lines

drivers/mmc/host/sdhci-pci.c out: · line 959

Quoted 6 lines
drivers/mmc/host/sdhci-pci.c +2 -0
@@ -950,6 +955,8 @@ out:
 	host->clock = clock;
 }
 
+EXPORT_SYMBOL_GPL(sdhci_set_clock);
+

Wrong symbol. :)

ok, will fix

Signature · 3 lines
Ben ([email protected], http://www.fluff.org/)

  'a smiley only costs 4 bytes'
#25 lore raw

Re: [patch 7/7] SDHCI: Add change_clock callback for glue drivers

Quoted 9 lines · On Sat, 15 Nov 2008 23:57:39 +0000 Ben Dooks <[email protected]> wrote:

The controller has a number of possible clock sources, the bus clock it is connected to (generally called hclk) and three more clocks from the heirachy that is muxed/divided from either an 48MHz, 27MHz or the EPLL.

The callback allows the recalculation and selection of the best clock to run the card clock for the controller.

Can these clock sources change mid-flight? Otherwise I don't see the need for a callback up to the sdhci core. But I don't see any connection points for such events.

Signature · 9 lines
     -- Pierre Ossman

  Linux kernel, MMC maintainer        http://www.kernel.org
  rdesktop, core developer          http://www.rdesktop.org

  WARNING: This correspondence is being monitored by the
  Swedish government. Make sure your server uses encryption
  for SMTP traffic and consider using PGP for end-to-end
  encryption.
author maintainer
#26 lore raw
In reply to Ben Dooks
Quoted 2 lines · Ben Dooks

The following patch set gets working SDHCI on the
Samsung SoC series.

Any more comments on this, can these be merged for the -next branch?

Signature · 3 lines
Ben ([email protected], http://www.fluff.org/)

  'a smiley only costs 4 bytes'