Re: Status of tmio_mmc DMA support for SDIO

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



(added linux-mmc and tmio_mmc maintainer to CC)

Hi Charles

On Thu, 13 May 2010, Charles D. Krebs wrote:

> Guennadi,
> 
> I'm currently using the BSP 2.0 release (2.6.33) for the Renesas 7724 
> Ecovec platform.  I have two patches (see attached) that enable MMC 
> support and SDIO support in that version of the Kernel.

Great, thanks for the patches!

Regarding MMCIF, have you seen these patches:

http://article.gmane.org/gmane.linux.kernel.mmc/1712
http://article.gmane.org/gmane.linux.ports.sh.devel/7860

> I've seen quite a bit of traffic lately over the linux-sh mailing list 
> regarding the addition of DMA to the tmio driver.  Unfortunately, I 
> really have no good idea as to what the status is of that development, 
> and whether or not it would apply to both MMC and SDIO modes of 
> operation.

The status is: it passes my tests, as long as cache is in write-through 
mode. However, on ecovec I seem to have problems with SD: a simple 
mount-compare-overwrite-umount loop aborts even without DMA after a few 
hundreds of iterations (under 600 in one of my tests) and it happens even 
faster with DMA. However, I haven't repeated this test with the latest 
version of the patches, will do it at some point.

> That said, it looks like at least patch [4/b9 v4] has a few 
> parts that accomplish both MMC and SDIO support separately.

Really? I was unaware of that;) I don't think there is any SDIO specific 
code in that or in any other of my patches for tmio_mmc.

> We have an SDIO based 802.11 b/g/n radio that could definitely benefit 
> from DMA support.  At this point, what patches I would need to apply, 
> and what configuration changes to the kernel are necessary to test this 
> functionality out?  Are there any known limitations to the new code for 
> SDIO support?

This is the basis patch series:

http://thread.gmane.org/gmane.linux.kernel.mmc/1780

in which patch 4/9 you replace with these three patches:

http://thread.gmane.org/gmane.linux.ports.sh.devel/8068

As for SDIO, there's only one limitation: it's not implemented yet;) But 
looking at your patch, it looks like it doesn't touch data paths, only 
command paths. So, so far I don't see any reason, why DMA shouldn't work 
for you out of the box... However, you seem to have much more knowledge 
about tmio unit internals, so, maybe you can just check with your 
documentation. As for changes - do not forget to enable the shdma 
dmaengine driver. And look in /proc/interrupts during your tests to see if 
you're getting any DMA interrupts. You shall see two DMA channels, used 
per SDHI controller - for Tx and Rx.

> We have a team at Redpine Signals in India that is currently working on 
> the implementation of the radio driver.  I'd like to introduce Sailaja 
> Sankabathula, Applications Engineering Manager, who is managing the 
> project.  I know that the Redpine team is eager to work through a couple 
> of issues that they are seeing with the current code that we have, and 
> that they are more than happy to help debug the new DMA enabled driver 
> code and share the results with the community via any means you think 
> best (I'd presume at least by copying the linux-sh mailing list).

That right, and also the mmc list and the driver maintainer.

> I'm still rather new to the community development aspect of the Linux kernel -
> Is there somewhere I can read up about the general development procedure 
> here and how to best interface with the mailing lists?

There are a couple of documents in the Linux kernel source tree, that you 
might find useful:

Documentation/SubmitChecklist
Documentation/SubmittingPatches
Documentation/SubmittingDrivers
Documentation/CodingStyle
Documentation/email-clients.txt

> I tend to feel a little lost in not knowing what version of the kernel 
> these patches are referenced to, if the patches are regularly checked 
> into the kernel repository, etc.

Documents under

Documentation/development-process/

should give you an idea. In short: kernel is being developed in multiple 
topic trees, dedicated to various architectures, drivers, subsystems, etc. 
You work with one or several of those trees, relevant for your 
development, submit your patches to respective mailing lists and 
maintainers, and during the merge window (first two weeks after a final 
kernel version release) those trees get merged into the central kernel 
tree. Bug-fixes can be merged in at any time, of course.

As for your patch, I think, Ian will have a good look at it, so far a 
couple of quick comments:

> diff -Naur sh-2.6_bsp/arch/sh/kernel/cpu/sh4a/setup-sh7724.c sh-2.6_presdio/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
> --- sh-2.6_bsp/arch/sh/kernel/cpu/sh4a/setup-sh7724.c	2010-03-25 04:48:00.000000000 +0000
> +++ sh-2.6_presdio/arch/sh/kernel/cpu/sh4a/setup-sh7724.c	2010-04-06 07:48:37.000000000 +0000
> @@ -890,7 +890,7 @@
>  static struct intc_mask_reg mask_registers[] __initdata = {
>  	{ 0xa4080080, 0xa40800c0, 8, /* IMR0 / IMCR0 */
>  	  { 0, TMU1_TUNI2, TMU1_TUNI1, TMU1_TUNI0,
> -	    0, DISABLED, ENABLED, ENABLED } },
> +	    0, ENABLED, ENABLED, ENABLED } },
>  	{ 0xa4080084, 0xa40800c4, 8, /* IMR1 / IMCR1 */
>  	  { VIO_VOU, VIO_VEU1, VIO_BEU0, VIO_CEU0,
>  	    DMAC0A_DEI3, DMAC0A_DEI2, DMAC0A_DEI1, DMAC0A_DEI0 } },
> diff -Naur sh-2.6_bsp/drivers/mfd/sh_mobile_sdhi.c sh-2.6_presdio/drivers/mfd/sh_mobile_sdhi.c
> --- sh-2.6_bsp/drivers/mfd/sh_mobile_sdhi.c	2010-03-25 04:48:00.000000000 +0000
> +++ sh-2.6_presdio/drivers/mfd/sh_mobile_sdhi.c	2010-04-06 07:48:37.000000000 +0000
> @@ -97,7 +97,7 @@
>  
>  	priv->mmc_data.hclk = clk_get_rate(priv->clk);
>  	priv->mmc_data.set_pwr = sh_mobile_sdhi_set_pwr;
> -	priv->mmc_data.capabilities = MMC_CAP_MMC_HIGHSPEED;
> +	priv->mmc_data.capabilities = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SDIO_IRQ;
>  
>  	memcpy(&priv->cell_mmc, &sh_mobile_sdhi_cell, sizeof(priv->cell_mmc));
>  	priv->cell_mmc.driver_data = &priv->mmc_data;
> diff -Naur sh-2.6_bsp/drivers/mmc/host/tmio_mmc.c sh-2.6_presdio/drivers/mmc/host/tmio_mmc.c
> --- sh-2.6_bsp/drivers/mmc/host/tmio_mmc.c	2010-03-25 04:48:00.000000000 +0000
> +++ sh-2.6_presdio/drivers/mmc/host/tmio_mmc.c	2010-04-06 07:48:37.000000000 +0000
> @@ -30,6 +30,7 @@
>  #include <linux/device.h>
>  #include <linux/delay.h>
>  #include <linux/mmc/host.h>
> +#include <linux/mmc/sdio.h>
>  #include <linux/mfd/core.h>
>  #include <linux/mfd/tmio.h>
>  
> @@ -146,6 +147,28 @@
>  			c |= TRANSFER_READ;
>  	}
>  
> +	switch (cmd->opcode) {
> +	case SD_IO_RW_DIRECT:
> +		sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
> +		enable_mmc_sdio_irqs(host, TMIO_SDIO_STAT_IOIRQ);
> +		break;
> +	case SD_IO_RW_EXTENDED:
> +		sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
> +		enable_mmc_sdio_irqs(host, TMIO_SDIO_STAT_IOIRQ);
> +		if (data->flags & MMC_DATA_READ) {
> +			if (data->sg->length <= 512)
> +				c = CMD_SD_IO_RW_EXTENDED_SREAD;
> +			else
> +				c = CMD_SD_IO_RW_EXTENDED_MREAD;
> +		} else { /* MMC_DATA_WRITE */
> +			if (data->sg->length <= 512)
> +				c = CMD_SD_IO_RW_EXTENDED_SWRITE;
> +			else
> +				c = CMD_SD_IO_RW_EXTENDED_MWRITE;
> +		}
> +		break;
> +	}
> +
>  	enable_mmc_irqs(host, TMIO_MASK_CMD);
>  
>  	/* Fire off the command */
> @@ -235,8 +258,13 @@
>  	if (stop) {
>  		if (stop->opcode == 12 && !stop->arg)
>  			sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x000);
> +#if 0

I realise, this wasn't a final patch submission, but just a remark - you 
don't want commented out code in the final version

> +	/* CMD_SD_IO_RW_EXTENDED_MREAD and CMD_SD_IO_RW_EXTENDED_MWRITE
> +	 * are not necessary.
> +	 */

multi-line comment style is wrong. Should have been

+	/*
+	 * CMD_SD_IO_RW_EXTENDED_MREAD and CMD_SD_IO_RW_EXTENDED_MWRITE
+	 * are not necessary.
+	 */

>  		else
>  			BUG();
> +#endif

But essentially, maybe you can preserve this check and just replace:

> - 			BUG();
> + 			BUG_ON(host->cmd->opcode != SD_IO_RW_EXTENDED);

or something similar.

>  	}
>  
>  	tmio_mmc_finish_request(host);
> @@ -298,6 +326,7 @@
>  {
>  	struct tmio_mmc_host *host = devid;
>  	unsigned int ireg, irq_mask, status;
> +	unsigned short ireg_io, irq_mask_io, status_io;

I would use u16 to explicitly specify 16-bit data.

>  
>  	pr_debug("MMC IRQ begin\n");
>  
> @@ -305,15 +334,31 @@
>  	irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK);
>  	ireg = status & TMIO_MASK_IRQ & ~irq_mask;
>  
> +	status_io = sd_ctrl_read16(host, CTL_SDIO_STATUS);
> +	irq_mask_io = sd_ctrl_read16(host, CTL_SDIO_IRQ_MASK);
> +	ireg_io = status_io & TMIO_SDIO_MASK_IRQ & ~irq_mask_io;
> +
>  	pr_debug_status(status);
>  	pr_debug_status(ireg);
>  
>  	if (!ireg) {
> +		if (ireg_io & TMIO_SDIO_STAT_IOIRQ) {
> +			ack_mmc_sdio_irqs(host, TMIO_SDIO_STAT_IOIRQ);
> +			mmc_signal_sdio_irq(host->mmc);
> +		} else if (ireg_io & TMIO_SDIO_STAT_EXWT)
> +			ack_mmc_sdio_irqs(host, TMIO_SDIO_STAT_EXWT);
> +		else if (ireg_io & TMIO_SDIO_STAT_EXPUB52)
> +			ack_mmc_sdio_irqs(host, TMIO_SDIO_STAT_EXPUB52);
> +		else
> +			ack_mmc_sdio_irqs(host, TMIO_SDIO_STAT_RESERVE);
> +
> +#if 0
>  		disable_mmc_irqs(host, status & ~irq_mask);
>  
>  		pr_debug("tmio_mmc: Spurious irq, disabling! "
>  			"0x%08x 0x%08x 0x%08x\n", status, irq_mask, ireg);
>  		pr_debug_status(status);
> +#endif

Same here, I think, you can preserve this interrupt disabling, if you 
extend the test to mean "no SD and no SDIO bit is set."

>  
>  		goto out;
>  	}
> @@ -321,6 +366,12 @@
>  	while (ireg) {
>  		/* Card insert / remove attempts */
>  		if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) {
> +			if (ireg & TMIO_STAT_CARD_REMOVE) {
> +				sd_ctrl_write16(host,
> +					CTL_TRANSACTION_CTL, 0x0000);
> +				disable_mmc_sdio_irqs(host,
> +					TMIO_SDIO_STAT_IOIRQ);
> +			}
>  			ack_mmc_irqs(host, TMIO_STAT_CARD_INSERT |
>  				TMIO_STAT_CARD_REMOVE);
>  			mmc_detect_change(host->mmc, msecs_to_jiffies(100));
> @@ -462,10 +513,20 @@
>  	return (sd_ctrl_read16(host, CTL_STATUS) & TMIO_STAT_WRPROTECT) ? 0 : 1;
>  }
>  
> +static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
> +{
> +	struct tmio_mmc_host *host = mmc_priv(mmc);
> +	if (enable)
> +		enable_mmc_sdio_irqs(host, TMIO_SDIO_STAT_IOIRQ);
> +	else
> +		disable_mmc_sdio_irqs(host, TMIO_SDIO_STAT_IOIRQ);
> +}
> +
>  static struct mmc_host_ops tmio_mmc_ops = {
>  	.request	= tmio_mmc_request,
>  	.set_ios	= tmio_mmc_set_ios,
>  	.get_ro         = tmio_mmc_get_ro,
> +	.enable_sdio_irq = tmio_mmc_enable_sdio_irq,

Don't be shy, add one more TAB to all struct members to align them 
properly;)

>  };
>  
>  #ifdef CONFIG_PM
> diff -Naur sh-2.6_bsp/drivers/mmc/host/tmio_mmc.h sh-2.6_presdio/drivers/mmc/host/tmio_mmc.h
> --- sh-2.6_bsp/drivers/mmc/host/tmio_mmc.h	2010-03-25 04:48:00.000000000 +0000
> +++ sh-2.6_presdio/drivers/mmc/host/tmio_mmc.h	2010-04-06 07:48:37.000000000 +0000
> @@ -24,6 +24,8 @@
>  #define CTL_SD_ERROR_DETAIL_STATUS 0x2c
>  #define CTL_SD_DATA_PORT 0x30
>  #define CTL_TRANSACTION_CTL 0x34
> +#define CTL_SDIO_STATUS 0x36
> +#define CTL_SDIO_IRQ_MASK 0x38
>  #define CTL_RESET_SD 0xe0
>  #define CTL_SDIO_REGS 0x100
>  #define CTL_CLK_AND_WAIT_CTL 0x138
> @@ -62,6 +64,23 @@
>  #define TMIO_MASK_IRQ     (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD)
>  
>  
> +/* Definitions for values the CTRL_SDIO_STATUS register can take. */
> +#define TMIO_SDIO_STAT_RESERVE	0x0006 /* reserve bit */
> +#define TMIO_SDIO_STAT_IOIRQ	0x0001
> +#define TMIO_SDIO_STAT_EXPUB52	0x4000
> +#define TMIO_SDIO_STAT_EXWT	0x8000
> +
> +#define CMD_SD_IO_RW_EXTENDED_SREAD	0x1C35
> +#define CMD_SD_IO_RW_EXTENDED_MREAD	0x7C35
> +#define CMD_SD_IO_RW_EXTENDED_SWRITE	0x0C35
> +#define CMD_SD_IO_RW_EXTENDED_MWRITE	0x6C35

You can put these four lines in tmio_mmc.c, and maybe "SDIO" without an 
underscore?

> +
> +/* Define some SDIO IRQ masks */
> +#define TMIO_SDIO_MASK_IRQ	(TMIO_SDIO_STAT_IOIRQ	| \
> +				 TMIO_SDIO_STAT_EXPUB52 | \
> +				 TMIO_SDIO_STAT_EXWT	| \
> +				 TMIO_SDIO_STAT_RESERVE)
> +
>  #define enable_mmc_irqs(host, i) \
>  	do { \
>  		u32 mask;\
> @@ -86,6 +105,29 @@
>  		sd_ctrl_write32((host), CTL_STATUS, mask); \
>  	} while (0)
>  
> +#define enable_mmc_sdio_irqs(host, i) \
> +	do { \
> +		u16 mask;\
> +		mask  = sd_ctrl_read16((host), CTL_SDIO_IRQ_MASK); \
> +		mask &= ~((i) & TMIO_SDIO_MASK_IRQ); \
> +		sd_ctrl_write16((host), CTL_SDIO_IRQ_MASK, mask); \
> +	} while (0)
> +
> +#define disable_mmc_sdio_irqs(host, i) \
> +	do { \
> +		u16 mask;\
> +		mask  = sd_ctrl_read16((host), CTL_SDIO_IRQ_MASK); \
> +		mask |= ((i) & TMIO_SDIO_MASK_IRQ); \
> +		sd_ctrl_write16((host), CTL_SDIO_IRQ_MASK, mask); \
> +	} while (0)
> +
> +#define ack_mmc_sdio_irqs(host, i) \
> +	do { \
> +		u16 mask;\
> +		mask  = sd_ctrl_read16((host), CTL_SDIO_STATUS); \
> +		mask &= ~((i) & TMIO_SDIO_MASK_IRQ); \
> +		sd_ctrl_write16((host), CTL_SDIO_STATUS, mask); \
> +	} while (0)
>  
>  struct tmio_mmc_host {
>  	void __iomem *ctl;

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux