linux-ide.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] ata: libata depends on HAS_DMA
       [not found] <20090511222702.352192505@arndb.de>
@ 2009-05-11 22:38 ` Arnd Bergmann
  2009-05-12  0:58   ` Jeff Garzik
  2009-05-12  8:06   ` Alan Cox
  0 siblings, 2 replies; 39+ messages in thread
From: Arnd Bergmann @ 2009-05-11 22:38 UTC (permalink / raw)
  To: linux-kernel, Jeff Garzik, linux-ide

libata uses the DMA mapping API, so it cannot be built
on architectures that don't have DMA support.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/ata/Kconfig |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 9120717..f076268 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -4,7 +4,7 @@
 
 menuconfig ATA
 	tristate "Serial ATA (prod) and Parallel ATA (experimental) drivers"
-	depends on HAS_IOMEM
+	depends on HAS_IOMEM && HAS_DMA
 	depends on BLOCK
 	depends on !(M32R || M68K) || BROKEN
 	select SCSI
-- 
1.6.0.4

-- 



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

* Re: [PATCH] ata: libata depends on HAS_DMA
  2009-05-11 22:38 ` [PATCH] ata: libata depends on HAS_DMA Arnd Bergmann
@ 2009-05-12  0:58   ` Jeff Garzik
  2009-05-12 12:40     ` Arnd Bergmann
  2009-05-12  8:06   ` Alan Cox
  1 sibling, 1 reply; 39+ messages in thread
From: Jeff Garzik @ 2009-05-12  0:58 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linux-kernel, linux-ide

Arnd Bergmann wrote:
> libata uses the DMA mapping API, so it cannot be built
> on architectures that don't have DMA support.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
>  drivers/ata/Kconfig |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
> index 9120717..f076268 100644
> --- a/drivers/ata/Kconfig
> +++ b/drivers/ata/Kconfig
> @@ -4,7 +4,7 @@
>  
>  menuconfig ATA
>  	tristate "Serial ATA (prod) and Parallel ATA (experimental) drivers"
> -	depends on HAS_IOMEM
> +	depends on HAS_IOMEM && HAS_DMA
>  	depends on BLOCK
>  	depends on !(M32R || M68K) || BROKEN

What specifically is breaking?

Ideally we should be able to work with PIO-only...

	JEff





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

* Re: [PATCH] ata: libata depends on HAS_DMA
  2009-05-11 22:38 ` [PATCH] ata: libata depends on HAS_DMA Arnd Bergmann
  2009-05-12  0:58   ` Jeff Garzik
@ 2009-05-12  8:06   ` Alan Cox
  2009-05-12  9:23     ` Arnd Bergmann
  1 sibling, 1 reply; 39+ messages in thread
From: Alan Cox @ 2009-05-12  8:06 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linux-kernel, Jeff Garzik, linux-ide

On Mon, 11 May 2009 22:38:55 +0000
Arnd Bergmann <arnd@arndb.de> wrote:

> libata uses the DMA mapping API, so it cannot be built
> on architectures that don't have DMA support.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>

Nakked-by: Alan Cox <alan@linux.intel.com>

Almost every PATA adapter can fall back to PIO, many are PIO only. We
need a rather cleaner way to sort this.

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

* Re: [PATCH] ata: libata depends on HAS_DMA
  2009-05-12  8:06   ` Alan Cox
@ 2009-05-12  9:23     ` Arnd Bergmann
  2009-05-13  3:30       ` Brad Boyer
  0 siblings, 1 reply; 39+ messages in thread
From: Arnd Bergmann @ 2009-05-12  9:23 UTC (permalink / raw)
  To: Alan Cox
  Cc: linux-kernel, Jeff Garzik, linux-ide, takata, geert, linux-m68k,
	ysato

On Tuesday 12 May 2009, Alan Cox wrote:
> Nakked-by: Alan Cox <alan@linux.intel.com>
> 
> Almost every PATA adapter can fall back to PIO, many are PIO only. We
> need a rather cleaner way to sort this.

Currently, the only architectures that don't set HAS_DMA are h8300, m32r
m68k (except SUN3 and Coldfire), microblaze and s390.
s390 will never get it, microblaze is currently implementing dma-mapping.h.

The other three are still using drivers/ide instead of drivers/ata.

One way to fix this would be to implement dma-mapping.h in h8300, m32r and
m68k and leave !HAS_DMA as the obscure s390 case (this one already can't
use ATA because of !HAS_MMIO).

The other way would be to add some #ifdef CONFIG_HAS_DMA in libata-core.c
and sas_ata.c.

	Arnd <><

	Arnd <><


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

* Re: [PATCH] ata: libata depends on HAS_DMA
  2009-05-12  0:58   ` Jeff Garzik
@ 2009-05-12 12:40     ` Arnd Bergmann
  2009-05-12 13:05       ` Arnd Bergmann
  0 siblings, 1 reply; 39+ messages in thread
From: Arnd Bergmann @ 2009-05-12 12:40 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: linux-kernel, linux-ide

On Tuesday 12 May 2009, Jeff Garzik wrote:
> > --- a/drivers/ata/Kconfig
> > +++ b/drivers/ata/Kconfig
> > @@ -4,7 +4,7 @@
> >  
> >  menuconfig ATA
> >       tristate "Serial ATA (prod) and Parallel ATA (experimental) drivers"
> > -     depends on HAS_IOMEM
> > +     depends on HAS_IOMEM && HAS_DMA
> >       depends on BLOCK
> >       depends on !(M32R || M68K) || BROKEN
> 
> What specifically is breaking?
> 
> Ideally we should be able to work with PIO-only...

CONFIG_HAS_DMA is not set on architectures that are missing
asm/dma-mapping.h or fall back to asm-generic/dma-mapping-broken.h.

In the latter case, you get a link error:
drivers/built-in.o: In function `sas_issue_ata_cmd':
/home/arnd/linux/linux-2.6/drivers/scsi/libsas/sas_ata.c(.text+0x33c50): undefined reference to `dma_map_sg'
/home/arnd/linux/linux-2.6/drivers/scsi/libsas/sas_ata.c(.text+0x33ef0): undefined reference to `dma_unmap_sg'
drivers/built-in.o: In function `ata_sg_clean':
/home/arnd/linux/linux-2.6/drivers/ata/libata-core.c(.text+0x37d18): undefined reference to `dma_unmap_sg'
drivers/built-in.o: In function `ata_qc_issue':
/home/arnd/linux/linux-2.6/drivers/ata/libata-core.c(.text+0x38774): undefined reference to `dma_map_sg'
drivers/built-in.o: In function `ata_port_start':
/home/arnd/linux/linux-2.6/drivers/ata/libata-core.c(.text+0x3bf0c): undefined reference to `dmam_alloc_coherent'

A slightly less naive (but still suboptimal) fix would be the patch below.
I could not find an easy way to force all devices to use PIO, this
patch would simply fail if someone tried to set a DMA mode.

	Arnd <><

--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4629,6 +4629,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev,
  */
 void ata_sg_clean(struct ata_queued_cmd *qc)
 {
+#ifdef CONFIG_HAS_DMA
 	struct ata_port *ap = qc->ap;
 	struct scatterlist *sg = qc->sg;
 	int dir = qc->dma_dir;
@@ -4642,6 +4643,7 @@ void ata_sg_clean(struct ata_queued_cmd *qc)
 
 	qc->flags &= ~ATA_QCFLAG_DMAMAP;
 	qc->sg = NULL;
+#endif /* CONFIG_HAS_DMA */
 }
 
 /**
@@ -4743,6 +4745,7 @@ void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
  */
 static int ata_sg_setup(struct ata_queued_cmd *qc)
 {
+#ifdef CONFIG_HAS_DMA
 	struct ata_port *ap = qc->ap;
 	unsigned int n_elem;
 
@@ -4758,6 +4761,10 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
 	qc->flags |= ATA_QCFLAG_DMAMAP;
 
 	return 0;
+#else
+	DPRINTK("attempted to use DMA on incompatible architecture\n");
+	return -EINVAL;
+#endif /* CONFIG_HAS_DMA */
 }
 
 /**
@@ -5450,8 +5457,12 @@ int ata_port_start(struct ata_port *ap)
 {
 	struct device *dev = ap->dev;
 
+#ifdef CONFIG_HAS_DMA
 	ap->prd = dmam_alloc_coherent(dev, ATA_PRD_TBL_SZ, &ap->prd_dma,
 				      GFP_KERNEL);
+#else
+	ap->prd = devres_alloc(dev, ATA_PRD_TBL_SZ, GFP_KERNEL);
+#endif /* CONFIG_HAS_DMA */
 	if (!ap->prd)
 		return -ENOMEM;
 
diff --git a/drivers/scsi/libsas/Kconfig b/drivers/scsi/libsas/Kconfig
index 59e00fa..e00271f 100644
--- a/drivers/scsi/libsas/Kconfig
+++ b/drivers/scsi/libsas/Kconfig
@@ -34,6 +34,7 @@ config SCSI_SAS_ATA
 	bool "ATA support for libsas (requires libata)"
 	depends on SCSI_SAS_LIBSAS
 	depends on ATA = y || ATA = SCSI_SAS_LIBSAS
+	depends on HAS_DMA
 	help
 		Builds in ATA support into libsas.  Will necessitate
 		the loading of libata along with libsas.

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

* Re: [PATCH] ata: libata depends on HAS_DMA
  2009-05-12 12:40     ` Arnd Bergmann
@ 2009-05-12 13:05       ` Arnd Bergmann
  0 siblings, 0 replies; 39+ messages in thread
From: Arnd Bergmann @ 2009-05-12 13:05 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: linux-kernel, linux-ide

On Tuesday 12 May 2009, Arnd Bergmann wrote:
> +#ifdef CONFIG_HAS_DMA
>         ap->prd = dmam_alloc_coherent(dev, ATA_PRD_TBL_SZ, &ap->prd_dma,
>                                       GFP_KERNEL);
> +#else
> +       ap->prd = devres_alloc(dev, ATA_PRD_TBL_SZ, GFP_KERNEL);
> +#endif /* CONFIG_HAS_DMA */
>         if (!ap->prd)
>                 return -ENOMEM;

this should have been devm_kzalloc, not devres_alloc.

	Arnd <><

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

* Re: [PATCH] ata: libata depends on HAS_DMA
  2009-05-12  9:23     ` Arnd Bergmann
@ 2009-05-13  3:30       ` Brad Boyer
  2009-05-13  4:12         ` Michael Schmitz
  2009-05-13 10:39         ` Arnd Bergmann
  0 siblings, 2 replies; 39+ messages in thread
From: Brad Boyer @ 2009-05-13  3:30 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Alan Cox, linux-kernel, Jeff Garzik, linux-ide, takata, geert,
	linux-m68k, ysato

On Tue, May 12, 2009 at 11:23:20AM +0200, Arnd Bergmann wrote:
> Currently, the only architectures that don't set HAS_DMA are h8300, m32r
> m68k (except SUN3 and Coldfire), microblaze and s390.
> s390 will never get it, microblaze is currently implementing dma-mapping.h.
> 
> The other three are still using drivers/ide instead of drivers/ata.
> 
> One way to fix this would be to implement dma-mapping.h in h8300, m32r and
> m68k and leave !HAS_DMA as the obscure s390 case (this one already can't
> use ATA because of !HAS_MMIO).

If I'm reading the m68k code correctly, SUN3 is the one that doesn't have
DMA. It is implemented on any m68k with a standard Motorola MMU. It might
be possible to get the DMA code working on a sun3, but I doubt they ever
have IDE hardware.

	Brad Boyer
	flar@allandria.com


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

* Re: [PATCH] ata: libata depends on HAS_DMA
  2009-05-13  3:30       ` Brad Boyer
@ 2009-05-13  4:12         ` Michael Schmitz
  2009-05-13  4:34           ` Brad Boyer
  2009-05-13 10:39         ` Arnd Bergmann
  1 sibling, 1 reply; 39+ messages in thread
From: Michael Schmitz @ 2009-05-13  4:12 UTC (permalink / raw)
  To: Brad Boyer
  Cc: Arnd Bergmann, Alan Cox, linux-kernel, Jeff Garzik, linux-ide,
	takata, geert, linux-m68k, ysato

Hi,

> > Currently, the only architectures that don't set HAS_DMA are h8300, m32r
> > m68k (except SUN3 and Coldfire), microblaze and s390.
> > s390 will never get it, microblaze is currently implementing dma-mapping.h.
> > 
> > The other three are still using drivers/ide instead of drivers/ata.
> > 
> > One way to fix this would be to implement dma-mapping.h in h8300, m32r and
> > m68k and leave !HAS_DMA as the obscure s390 case (this one already can't
> > use ATA because of !HAS_MMIO).
> 
> If I'm reading the m68k code correctly, SUN3 is the one that doesn't have
> DMA. It is implemented on any m68k with a standard Motorola MMU. It might
> be possible to get the DMA code working on a sun3, but I doubt they ever
> have IDE hardware.

The Atari IDE interface does not use DMA. I don't see what addition of DMA 
mapping for IDE would achieve. 

If it doesn't interfere with plain PIO mode, fine. 

	Michael


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

* Re: [PATCH] ata: libata depends on HAS_DMA
  2009-05-13  4:12         ` Michael Schmitz
@ 2009-05-13  4:34           ` Brad Boyer
  2009-05-13  8:51             ` Alan Cox
  0 siblings, 1 reply; 39+ messages in thread
From: Brad Boyer @ 2009-05-13  4:34 UTC (permalink / raw)
  To: Michael Schmitz
  Cc: Arnd Bergmann, Alan Cox, linux-kernel, Jeff Garzik, linux-ide,
	takata, geert, linux-m68k, ysato

On Wed, May 13, 2009 at 06:12:31AM +0200, Michael Schmitz wrote:
> The Atari IDE interface does not use DMA. I don't see what addition of DMA 
> mapping for IDE would achieve. 

The macide driver doesn't support anything with DMA hardware either. In
fact, no m68k Macintosh has both DMA capability and an IDE controller.
However, we do support the basic DMA routines on the main m68k platforms.
It's just not used for IDE. I think the proposed change was to require
that the DMA routines be present, not that the IDE ports actually have
to have a DMA capability.

> If it doesn't interfere with plain PIO mode, fine. 

I agree. There definitely needs to still be support for IDE ports that
don't have DMA capability.

	Brad Boyer
	flar@allandria.com


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

* Re: [PATCH] ata: libata depends on HAS_DMA
  2009-05-13  4:34           ` Brad Boyer
@ 2009-05-13  8:51             ` Alan Cox
  2009-05-13  8:55               ` Geert Uytterhoeven
  2009-05-13 23:57               ` Robert Hancock
  0 siblings, 2 replies; 39+ messages in thread
From: Alan Cox @ 2009-05-13  8:51 UTC (permalink / raw)
  To: Brad Boyer
  Cc: Michael Schmitz, Arnd Bergmann, linux-kernel, Jeff Garzik,
	linux-ide, takata, geert, linux-m68k, ysato

> > If it doesn't interfere with plain PIO mode, fine. 
> 
> I agree. There definitely needs to still be support for IDE ports that
> don't have DMA capability.

There is - it's just if the platform doesn't implement the dma_* APIs you
get a problem.

Alan

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

* Re: [PATCH] ata: libata depends on HAS_DMA
  2009-05-13  8:51             ` Alan Cox
@ 2009-05-13  8:55               ` Geert Uytterhoeven
  2009-05-13 23:57               ` Robert Hancock
  1 sibling, 0 replies; 39+ messages in thread
From: Geert Uytterhoeven @ 2009-05-13  8:55 UTC (permalink / raw)
  To: Alan Cox
  Cc: Brad Boyer, Michael Schmitz, Arnd Bergmann, linux-kernel,
	Jeff Garzik, linux-ide, takata, linux-m68k, ysato

On Wed, May 13, 2009 at 10:51, Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:
>> > If it doesn't interfere with plain PIO mode, fine.
>>
>> I agree. There definitely needs to still be support for IDE ports that
>> don't have DMA capability.
>
> There is - it's just if the platform doesn't implement the dma_* APIs you
> get a problem.

Note that there are other things missing on m68k and m32r, that's why
Al added the

| depends on !(M32R || M68K) || BROKEN

commit 9317fd4c60962d3a9423b5f9bb5d1b10cf8a0699
Author: Al Viro <viro@ftp.linux.org.uk>
Date:   Sun Sep 24 23:40:00 2006 +0100

    [PATCH] libata won't build on m68k and m32r

    no ioread*(), for one thing

Gr{oetje,eeting}s,

						Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
							    -- Linus Torvalds

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

* Re: [PATCH] ata: libata depends on HAS_DMA
  2009-05-13  3:30       ` Brad Boyer
  2009-05-13  4:12         ` Michael Schmitz
@ 2009-05-13 10:39         ` Arnd Bergmann
  1 sibling, 0 replies; 39+ messages in thread
From: Arnd Bergmann @ 2009-05-13 10:39 UTC (permalink / raw)
  To: Brad Boyer
  Cc: Alan Cox, linux-kernel, Jeff Garzik, linux-ide, takata, geert,
	linux-m68k, ysato

On Wednesday 13 May 2009, Brad Boyer wrote:
> If I'm reading the m68k code correctly, SUN3 is the one that doesn't have
> DMA. It is implemented on any m68k with a standard Motorola MMU. It might
> be possible to get the DMA code working on a sun3, but I doubt they ever
> have IDE hardware.

Yes, that's right, I misread the Kconfig logic.

In m68nommu, there are also Dragonball and MC68360 that are supported
but don't support the DMA API right now. Is that a real limitation, or
could those potentially have ATA ports?

	Arnd <><

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

* Re: [PATCH] ata: libata depends on HAS_DMA
  2009-05-13  8:51             ` Alan Cox
  2009-05-13  8:55               ` Geert Uytterhoeven
@ 2009-05-13 23:57               ` Robert Hancock
  2009-05-14  0:18                 ` FUJITA Tomonori
  1 sibling, 1 reply; 39+ messages in thread
From: Robert Hancock @ 2009-05-13 23:57 UTC (permalink / raw)
  To: Alan Cox
  Cc: Brad Boyer, Michael Schmitz, Arnd Bergmann, linux-kernel,
	Jeff Garzik, linux-ide, takata, geert, linux-m68k, ysato

Alan Cox wrote:
>>> If it doesn't interfere with plain PIO mode, fine. 
>> I agree. There definitely needs to still be support for IDE ports that
>> don't have DMA capability.
> 
> There is - it's just if the platform doesn't implement the dma_* APIs you
> get a problem.

Wouldn't the easiest solution be to just dummy out the DMA API calls on 
this platform to always fail? That would fix these compile problems..

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

* Re: [PATCH] ata: libata depends on HAS_DMA
  2009-05-13 23:57               ` Robert Hancock
@ 2009-05-14  0:18                 ` FUJITA Tomonori
  2009-05-15  5:31                   ` Tejun Heo
  0 siblings, 1 reply; 39+ messages in thread
From: FUJITA Tomonori @ 2009-05-14  0:18 UTC (permalink / raw)
  To: hancockrwd
  Cc: alan, flar, schmitz, arnd, linux-kernel, jgarzik, linux-ide,
	takata, geert, linux-m68k, ysato

On Wed, 13 May 2009 17:57:14 -0600
Robert Hancock <hancockrwd@gmail.com> wrote:

> Alan Cox wrote:
> >>> If it doesn't interfere with plain PIO mode, fine. 
> >> I agree. There definitely needs to still be support for IDE ports that
> >> don't have DMA capability.
> > 
> > There is - it's just if the platform doesn't implement the dma_* APIs you
> > get a problem.
> 
> Wouldn't the easiest solution be to just dummy out the DMA API calls on 
> this platform to always fail? That would fix these compile problems..

Can libata call dma_supported() per device to decide DMA or PIO mode?
Then, we can solve this problem by add dummy DMA API (just calls BUG)
on such architectures, without Kconfig magic or adding ifdef (like the
old ide stack does), I think.

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

* Re: [PATCH] ata: libata depends on HAS_DMA
  2009-05-14  0:18                 ` FUJITA Tomonori
@ 2009-05-15  5:31                   ` Tejun Heo
  2009-05-15 11:16                     ` Arnd Bergmann
  0 siblings, 1 reply; 39+ messages in thread
From: Tejun Heo @ 2009-05-15  5:31 UTC (permalink / raw)
  To: FUJITA Tomonori
  Cc: hancockrwd, alan, flar, schmitz, arnd, linux-kernel, jgarzik,
	linux-ide, takata, geert, linux-m68k, ysato

FUJITA Tomonori wrote:
> On Wed, 13 May 2009 17:57:14 -0600
> Robert Hancock <hancockrwd@gmail.com> wrote:
> 
>> Alan Cox wrote:
>>>>> If it doesn't interfere with plain PIO mode, fine. 
>>>> I agree. There definitely needs to still be support for IDE ports that
>>>> don't have DMA capability.
>>> There is - it's just if the platform doesn't implement the dma_* APIs you
>>> get a problem.
>> Wouldn't the easiest solution be to just dummy out the DMA API calls on 
>> this platform to always fail? That would fix these compile problems..
> 
> Can libata call dma_supported() per device to decide DMA or PIO mode?
> Then, we can solve this problem by add dummy DMA API (just calls BUG)
> on such architectures, without Kconfig magic or adding ifdef (like the
> old ide stack does), I think.

Sure it can.  Which specific drivers are we talking about?

Thanks.

-- 
tejun

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

* Re: [PATCH] ata: libata depends on HAS_DMA
  2009-05-15  5:31                   ` Tejun Heo
@ 2009-05-15 11:16                     ` Arnd Bergmann
  2009-05-15 11:21                       ` Tejun Heo
  2009-05-18 10:45                       ` [PATCH] ata: libata depends on HAS_DMA FUJITA Tomonori
  0 siblings, 2 replies; 39+ messages in thread
From: Arnd Bergmann @ 2009-05-15 11:16 UTC (permalink / raw)
  To: Tejun Heo
  Cc: FUJITA Tomonori, hancockrwd, alan, flar, schmitz, linux-kernel,
	jgarzik, linux-ide, takata, geert, linux-m68k, ysato

On Friday 15 May 2009, Tejun Heo wrote:
> FUJITA Tomonori wrote:
> > Can libata call dma_supported() per device to decide DMA or PIO mode?
> > Then, we can solve this problem by add dummy DMA API (just calls BUG)
> > on such architectures, without Kconfig magic or adding ifdef (like the
> > old ide stack does), I think.

That would be the !CONFIG_PCI half of the old
include/asm-generic/dma-mapping.h file that you just removed,
right?

In general, I'd prefer keeping the asm-generic/dma-mapping-broken.h
implementation that gives us a compile-time error, but maybe there
is an even better option based on the mn10300 implementation which
basically pretends everything works with just page_to_phys() mappings.

> Sure it can.  Which specific drivers are we talking about?

The main problem is libata-core.c, which references DMA mapping
API calls that are only implemented on architectures setting
CONFIG_HAS_DMA.

	Arnd <><
--
To unsubscribe from this list: send the line "unsubscribe linux-m68k" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH] ata: libata depends on HAS_DMA
  2009-05-15 11:16                     ` Arnd Bergmann
@ 2009-05-15 11:21                       ` Tejun Heo
  2009-05-15 11:55                         ` Arnd Bergmann
  2009-05-18 10:45                       ` [PATCH] ata: libata depends on HAS_DMA FUJITA Tomonori
  1 sibling, 1 reply; 39+ messages in thread
From: Tejun Heo @ 2009-05-15 11:21 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: FUJITA Tomonori, hancockrwd, alan, flar, schmitz, linux-kernel,
	jgarzik, linux-ide, takata, geert, linux-m68k, ysato

Hello,

Arnd Bergmann wrote:
> On Friday 15 May 2009, Tejun Heo wrote:
>> FUJITA Tomonori wrote:
>>> Can libata call dma_supported() per device to decide DMA or PIO mode?
>>> Then, we can solve this problem by add dummy DMA API (just calls BUG)
>>> on such architectures, without Kconfig magic or adding ifdef (like the
>>> old ide stack does), I think.
> 
> That would be the !CONFIG_PCI half of the old
> include/asm-generic/dma-mapping.h file that you just removed,
> right?
> 
> In general, I'd prefer keeping the asm-generic/dma-mapping-broken.h
> implementation that gives us a compile-time error, but maybe there
> is an even better option based on the mn10300 implementation which
> basically pretends everything works with just page_to_phys() mappings.

Don't know much history here but I don't wanna sprinkle ifdefs around
in libata so I would much prefer dummy implementation which doesn't
fail compile.

>> Sure it can.  Which specific drivers are we talking about?
> 
> The main problem is libata-core.c, which references DMA mapping
> API calls that are only implemented on architectures setting
> CONFIG_HAS_DMA.

Yeah, sure, libata-core is used by every driver but I was wondering
whether only SFF drivers are of interest or there are others.

Thanks.

-- 
tejun

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

* Re: [PATCH] ata: libata depends on HAS_DMA
  2009-05-15 11:21                       ` Tejun Heo
@ 2009-05-15 11:55                         ` Arnd Bergmann
  2009-05-17  9:00                           ` Robert Hancock
  0 siblings, 1 reply; 39+ messages in thread
From: Arnd Bergmann @ 2009-05-15 11:55 UTC (permalink / raw)
  To: Tejun Heo
  Cc: FUJITA Tomonori, hancockrwd, alan, flar, schmitz, linux-kernel,
	jgarzik, linux-ide, takata, geert, linux-m68k, ysato

On Friday 15 May 2009, Tejun Heo wrote:
> Don't know much history here but I don't wanna sprinkle ifdefs around
> in libata so I would much prefer dummy implementation which doesn't
> fail compile.

My original patch did that by adding 'depends on HAS_DMA'.

The only architectures that don't have that are m68k, m32r,
h8300, s390 and microblaze. More research has shown that
they all found a different way to disable the ATA drivers
already, except microblaze.

Alan, you objected the patch initially (and loudly), but
maybe you can reconsider this. The only actual effect
that my patch has is to allow an allyesconfig build on
microblaze and that will implement dma-mapping.h in the
next version.

All existing architectures do not care at all about this
change, unless I'm missing something.

Besides, all the other users of the DMA mapping API
also depend on CONFIG_HAS_DMA.

	Arnd <><

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

* Re: [PATCH] ata: libata depends on HAS_DMA
  2009-05-15 11:55                         ` Arnd Bergmann
@ 2009-05-17  9:00                           ` Robert Hancock
  2009-05-17 19:38                             ` Arnd Bergmann
  0 siblings, 1 reply; 39+ messages in thread
From: Robert Hancock @ 2009-05-17  9:00 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Tejun Heo, FUJITA Tomonori, alan, flar, schmitz, linux-kernel,
	jgarzik, linux-ide, takata, geert, linux-m68k, ysato

Arnd Bergmann wrote:
> On Friday 15 May 2009, Tejun Heo wrote:
>> Don't know much history here but I don't wanna sprinkle ifdefs around
>> in libata so I would much prefer dummy implementation which doesn't
>> fail compile.
> 
> My original patch did that by adding 'depends on HAS_DMA'.
> 
> The only architectures that don't have that are m68k, m32r,
> h8300, s390 and microblaze. More research has shown that
> they all found a different way to disable the ATA drivers
> already, except microblaze.
> 
> Alan, you objected the patch initially (and loudly), but
> maybe you can reconsider this. The only actual effect
> that my patch has is to allow an allyesconfig build on
> microblaze and that will implement dma-mapping.h in the
> next version.
> 
> All existing architectures do not care at all about this
> change, unless I'm missing something.
> 
> Besides, all the other users of the DMA mapping API
> also depend on CONFIG_HAS_DMA.

Yes, it fixes the compile problem by preventing libata from being 
compiled at all. But the point is that libata should be able to work 
without DMA support.

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

* Re: [PATCH] ata: libata depends on HAS_DMA
  2009-05-17  9:00                           ` Robert Hancock
@ 2009-05-17 19:38                             ` Arnd Bergmann
  2009-05-17 20:05                               ` Jeff Garzik
  0 siblings, 1 reply; 39+ messages in thread
From: Arnd Bergmann @ 2009-05-17 19:38 UTC (permalink / raw)
  To: Robert Hancock
  Cc: Tejun Heo, FUJITA Tomonori, alan, flar, schmitz, linux-kernel,
	jgarzik, linux-ide, takata, geert, linux-m68k, ysato

On Sunday 17 May 2009, Robert Hancock wrote:
> Arnd Bergmann wrote:
> > On Friday 15 May 2009, Tejun Heo wrote:
> >> Don't know much history here but I don't wanna sprinkle ifdefs around
> >> in libata so I would much prefer dummy implementation which doesn't
> >> fail compile.
> > 
> > My original patch did that by adding 'depends on HAS_DMA'.
> > 
> > The only architectures that don't have that are m68k, m32r,
> > h8300, s390 and microblaze. More research has shown that
> > they all found a different way to disable the ATA drivers
> > already, except microblaze.
> > 
> > Alan, you objected the patch initially (and loudly), but
> > maybe you can reconsider this. The only actual effect
> > that my patch has is to allow an allyesconfig build on
> > microblaze and that will implement dma-mapping.h in the
> > next version.
> > 
> > All existing architectures do not care at all about this
> > change, unless I'm missing something.
> > 
> > Besides, all the other users of the DMA mapping API
> > also depend on CONFIG_HAS_DMA.
> 
> Yes, it fixes the compile problem by preventing libata from being 
> compiled at all. But the point is that libata should be able to work 
> without DMA support.

Please reread my explanations above and your own reply from 
last thursday. The case is entirely theoretical, as all platforms
(except microblaze, which is getting fixed) either set HAS_DMA or
don't allow building ATA drivers anyway. Platforms that don't support
DMA can just define CONFIG_HAS_DMA and do what you suggested:

On Thursday 14 May 2009, Robert Hancock wrote:
> Wouldn't the easiest solution be to just dummy out the DMA API calls on 
> this platform to always fail? That would fix these compile problems..

	Arnd <><

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

* Re: [PATCH] ata: libata depends on HAS_DMA
  2009-05-17 19:38                             ` Arnd Bergmann
@ 2009-05-17 20:05                               ` Jeff Garzik
  2009-05-17 22:45                                 ` [PATCH] asm-generic: add a dma-mapping.h file Arnd Bergmann
  0 siblings, 1 reply; 39+ messages in thread
From: Jeff Garzik @ 2009-05-17 20:05 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Robert Hancock, Tejun Heo, FUJITA Tomonori, alan, flar, schmitz,
	linux-kernel, linux-ide, takata, geert, linux-m68k, ysato

Arnd Bergmann wrote:
> On Sunday 17 May 2009, Robert Hancock wrote:
> Please reread my explanations above and your own reply from 
> last thursday. The case is entirely theoretical, as all platforms
> (except microblaze, which is getting fixed) either set HAS_DMA or
> don't allow building ATA drivers anyway. Platforms that don't support
> DMA can just define CONFIG_HAS_DMA and do what you suggested:
> 
> On Thursday 14 May 2009, Robert Hancock wrote:
>> Wouldn't the easiest solution be to just dummy out the DMA API calls on 
>> this platform to always fail? That would fix these compile problems..


That's what needs to happen.  We provide no-op functions for e.g. PCI 
and x86 DMI, for platforms where this support does not exist.

Pretty much all architectures support some form of ATA.  m68k, m32r, 
h8300 and microblaze all have IDE interface, which means that libata 
needs to work on that platform.

The only !ATA arch in the entire kernel is s390, AFAICT.

	Jeff




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

* [PATCH] asm-generic: add a dma-mapping.h file
  2009-05-17 20:05                               ` Jeff Garzik
@ 2009-05-17 22:45                                 ` Arnd Bergmann
  2009-05-18  6:03                                   ` Geert Uytterhoeven
                                                     ` (2 more replies)
  0 siblings, 3 replies; 39+ messages in thread
From: Arnd Bergmann @ 2009-05-17 22:45 UTC (permalink / raw)
  To: Jeff Garzik
  Cc: Robert Hancock, Tejun Heo, FUJITA Tomonori, alan, flar, schmitz,
	linux-kernel, linux-ide, takata, geert, linux-m68k, ysato

h8300 and m32r currently do not provide a DMA mapping API
and therefore cannot use the ATA drivers. This adds a
generic version of dma-mapping.h for architectures that
have none or very minimal actual support for DMA in hardware
and makes the two architectures use it.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
On Sunday 17 May 2009 20:05:54 Jeff Garzik wrote:

> That's what needs to happen.  We provide no-op functions for e.g. PCI 
> and x86 DMI, for platforms where this support does not exist.
> 
> Pretty much all architectures support some form of ATA.  m68k, m32r, 
> h8300 and microblaze all have IDE interface, which means that libata 
> needs to work on that platform.
> 
> The only !ATA arch in the entire kernel is s390, AFAICT.

m68k only defines NO_DMA for Sun3 and Dragonball. Sun3 does
not have ATA, Dragonball could probably just enable HAS_DMA.

---
 arch/h8300/Kconfig                   |    2 +-
 arch/h8300/include/asm/dma-mapping.h |    1 +
 arch/m32r/Kconfig                    |    2 +-
 arch/m32r/include/asm/dma-mapping.h  |    1 +
 include/asm-generic/dma-mapping.h    |  399 ++++++++++++++++++++++++++++++++++
 5 files changed, 403 insertions(+), 2 deletions(-)
 create mode 100644 arch/h8300/include/asm/dma-mapping.h
 create mode 100644 arch/m32r/include/asm/dma-mapping.h
 create mode 100644 include/asm-generic/dma-mapping.h

diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
index 9420648..36a037d 100644
--- a/arch/h8300/Kconfig
+++ b/arch/h8300/Kconfig
@@ -74,7 +74,7 @@ config NO_IOPORT
 	def_bool y
 
 config NO_DMA
-	def_bool y
+	def_bool n
 
 config ISA
 	bool
diff --git a/arch/h8300/include/asm/dma-mapping.h b/arch/h8300/include/asm/dma-mapping.h
new file mode 100644
index 0000000..e7e1690
--- /dev/null
+++ b/arch/h8300/include/asm/dma-mapping.h
@@ -0,0 +1 @@
+#include <asm-generic/dma-mapping.h>
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
index cabba33..57ad603 100644
--- a/arch/m32r/Kconfig
+++ b/arch/m32r/Kconfig
@@ -35,7 +35,7 @@ config NO_IOPORT
 	def_bool y
 
 config NO_DMA
-	def_bool y
+	def_bool n
 
 config HZ
 	int
diff --git a/arch/m32r/include/asm/dma-mapping.h b/arch/m32r/include/asm/dma-mapping.h
new file mode 100644
index 0000000..e7e1690
--- /dev/null
+++ b/arch/m32r/include/asm/dma-mapping.h
@@ -0,0 +1 @@
+#include <asm-generic/dma-mapping.h>
diff --git a/include/asm-generic/dma-mapping.h b/include/asm-generic/dma-mapping.h
new file mode 100644
index 0000000..5a14fed
--- /dev/null
+++ b/include/asm-generic/dma-mapping.h
@@ -0,0 +1,399 @@
+#ifndef _ASM_GENERIC_DMA_MAPPING_H
+#define _ASM_GENERIC_DMA_MAPPING_H
+/*
+ * This provides a no-op variant of the DMA mapping API,
+ * for use by architectures that do not actually support
+ * DMA, or that are fully consistent and linear-mapped
+ * in their DMA implementation.
+ */
+
+#include <asm/scatterlist.h>
+
+/*
+ * If any driver asks for DMA, it's not supported.
+ */
+#ifndef dma_supported
+static inline int
+dma_supported(struct device *dev, u64 mask)
+{
+	return 0;
+}
+#endif
+
+#ifndef dma_set_mask
+static inline int
+dma_set_mask(struct device *dev, u64 dma_mask)
+{
+	if (!dev->dma_mask || !dma_supported(dev, dma_mask))
+		return -EIO;
+
+	*dev->dma_mask = dma_mask;
+	return 0;
+}
+#endif
+
+/**
+ * dma_alloc_coherent - allocate consistent memory for DMA
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @size: required memory size
+ * @handle: bus-specific DMA address
+ *
+ * Allocate some uncached, unbuffered memory for a device for
+ * performing DMA.  This function allocates pages, and will
+ * return the CPU-viewed address, and sets @handle to be the
+ * device-viewed address.
+ */
+#ifndef dma_alloc_coherent
+static inline void *
+dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
+		   gfp_t flag)
+{
+	void *virt = kmalloc(size, flag);
+	*dma_handle = virt_to_phys(virt);
+
+	return virt;
+}
+#endif
+
+/**
+ * dma_free_coherent - free memory allocated by dma_alloc_coherent
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @size: size of memory originally requested in dma_alloc_coherent
+ * @cpu_addr: CPU-view address returned from dma_alloc_coherent
+ * @handle: device-view address returned from dma_alloc_coherent
+ *
+ * Free (and unmap) a DMA buffer previously allocated by
+ * dma_alloc_coherent().
+ *
+ * References to memory and mappings associated with cpu_addr/handle
+ * during and after this call executing are illegal.
+ */
+#ifndef dma_free_coherent
+static inline void
+dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
+		  dma_addr_t dma_handle)
+{
+	kfree(cpu_addr);
+}
+#endif
+
+#ifndef dma_alloc_noncoherent
+static inline void *
+dma_alloc_noncoherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
+		   gfp_t flag)
+{
+	return dma_alloc_coherent(dev, size, dma_handle, flag);
+}
+#endif
+
+#ifndef dma_free_noncoherent
+static inline void
+dma_free_noncoherent(struct device *dev, size_t size, void *cpu_addr,
+		  dma_addr_t dma_handle)
+{
+	return dma_free_coherent(dev, size, cpu_addr, dma_handle);
+}
+#endif
+
+/**
+ * dma_map_single - map a single buffer for streaming DMA
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @cpu_addr: CPU direct mapped address of buffer
+ * @size: size of buffer to map
+ * @dir: DMA transfer direction
+ *
+ * Ensure that any data held in the cache is appropriately discarded
+ * or written back.
+ *
+ * The device owns this memory once this call has completed.  The CPU
+ * can regain ownership by calling dma_unmap_single() or dma_sync_single().
+ */
+#ifndef dma_map_single
+static inline dma_addr_t
+dma_map_single(struct device *dev, void *cpu_addr, size_t size,
+	       enum dma_data_direction direction)
+{
+	return virt_to_phys(cpu_addr);
+}
+#endif
+
+/**
+ * dma_unmap_single - unmap a single buffer previously mapped
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @handle: DMA address of buffer
+ * @size: size of buffer to map
+ * @dir: DMA transfer direction
+ *
+ * Unmap a single streaming mode DMA translation.  The handle and size
+ * must match what was provided in the previous dma_map_single() call.
+ * All other usages are undefined.
+ *
+ * After this call, reads by the CPU to the buffer are guaranteed to see
+ * whatever the device wrote there.
+ */
+#ifndef dma_unmap_single
+static inline void
+dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
+		 enum dma_data_direction direction)
+{
+}
+#endif
+
+/**
+ * dma_map_page - map a portion of a page for streaming DMA
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @page: page that buffer resides in
+ * @offset: offset into page for start of buffer
+ * @size: size of buffer to map
+ * @dir: DMA transfer direction
+ *
+ * Ensure that any data held in the cache is appropriately discarded
+ * or written back.
+ *
+ * The device owns this memory once this call has completed.  The CPU
+ * can regain ownership by calling dma_unmap_page() or dma_sync_single().
+ */
+#ifndef dma_map_page
+static inline dma_addr_t
+dma_map_page(struct device *dev, struct page *page,
+	     unsigned long offset, size_t size,
+	     enum dma_data_direction direction)
+{
+	return dma_map_single(dev, page_to_virt(page), size, direction);
+}
+#endif
+
+/**
+ * dma_unmap_page - unmap a buffer previously mapped through dma_map_page()
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @handle: DMA address of buffer
+ * @size: size of buffer to map
+ * @dir: DMA transfer direction
+ *
+ * Unmap a single streaming mode DMA translation.  The handle and size
+ * must match what was provided in the previous dma_map_single() call.
+ * All other usages are undefined.
+ *
+ * After this call, reads by the CPU to the buffer are guaranteed to see
+ * whatever the device wrote there.
+ */
+#ifndef dma_unmap_page
+static inline void
+dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
+	       enum dma_data_direction direction)
+{
+	dma_unmap_single(dev, dma_address, size, direction);
+}
+#endif
+
+/**
+ * dma_map_sg - map a set of SG buffers for streaming mode DMA
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @sg: list of buffers
+ * @nents: number of buffers to map
+ * @dir: DMA transfer direction
+ *
+ * Map a set of buffers described by scatterlist in streaming
+ * mode for DMA.  This is the scatter-gather version of the
+ * above pci_map_single interface.  Here the scatter gather list
+ * elements are each tagged with the appropriate dma address
+ * and length.  They are obtained via sg_dma_{address,length}(SG).
+ *
+ * NOTE: An implementation may be able to use a smaller number of
+ *       DMA address/length pairs than there are SG table elements.
+ *       (for example via virtual mapping capabilities)
+ *       The routine returns the number of addr/length pairs actually
+ *       used, at most nents.
+ *
+ * Device ownership issues as mentioned above for pci_map_single are
+ * the same here.
+ */
+#ifndef dma_map_sg
+static inline int
+dma_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
+	   enum dma_data_direction direction)
+{
+	struct scatterlist *sg;
+	int i;
+
+        for_each_sg(sgl, sg, nents, i) {
+                sg->dma_address = sg_phys(sg);
+                sg->dma_length = sg->length;
+        }
+
+	return nents;
+}
+#endif
+
+/**
+ * dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @sg: list of buffers
+ * @nents: number of buffers to map
+ * @dir: DMA transfer direction
+ *
+ * Unmap a set of streaming mode DMA translations.
+ * Again, CPU read rules concerning calls here are the same as for
+ * pci_unmap_single() above.
+ */
+#ifndef dma_unmap_sg
+static inline void
+dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
+	     enum dma_data_direction direction)
+{
+}
+#endif
+
+/**
+ * dma_sync_single_for_cpu
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @handle: DMA address of buffer
+ * @size: size of buffer to map
+ * @dir: DMA transfer direction
+ *
+ * Make physical memory consistent for a single streaming mode DMA
+ * translation after a transfer.
+ *
+ * If you perform a dma_map_single() but wish to interrogate the
+ * buffer using the cpu, yet do not wish to teardown the DMA mapping,
+ * you must call this function before doing so.  At the next point you
+ * give the DMA address back to the card, you must first perform a
+ * dma_sync_single_for_device, and then the device again owns the
+ * buffer.
+ */
+#ifndef dma_sync_single_for_cpu
+static inline void
+dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
+			 size_t size, enum dma_data_direction direction)
+{
+}
+#endif
+
+/**
+ * dma_sync_single_for_device
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @handle: DMA address of buffer
+ * @size: size of buffer to map
+ * @dir: DMA transfer direction
+ *
+ * Make physical memory consistent for a single streaming mode DMA
+ * translation before a transfer.
+ */
+#ifndef dma_sync_single_for_cpu
+static inline void
+dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
+			 size_t size, enum dma_data_direction direction)
+{
+	return dma_sync_single_for_cpu(dev, dma_handle, size, direction);
+}
+#endif
+
+#ifndef dma_sync_single_range_for_cpu
+static inline void
+dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
+			      unsigned long offset, size_t size,
+			      enum dma_data_direction direction)
+{
+	dma_sync_single_for_cpu(dev, dma_handle, offset+size, direction);
+}
+#endif
+
+#ifndef dma_sync_single_range_for_device
+static inline void
+dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
+				 unsigned long offset, size_t size,
+				 enum dma_data_direction direction)
+{
+	dma_sync_single_for_device(dev, dma_handle, offset+size, direction);
+}
+#endif
+
+/**
+ * dma_sync_sg_for_cpu
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @sg: list of buffers
+ * @nents: number of buffers to map
+ * @dir: DMA transfer direction
+ *
+ * Make physical memory consistent for a set of streaming
+ * mode DMA translations after a transfer.
+ *
+ * The same as dma_sync_single_for_cpu but for a
+ * scatter-gather list, same rules and usage.
+ */
+#ifndef dma_sync_sg_for_cpu
+static inline void
+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl,
+		 int nelems, enum dma_data_direction direction)
+{
+	struct scatterlist *sg;
+	int i;
+
+        for_each_sg(sgl, sg, nelems, i) {
+		dma_sync_single_for_cpu(dev, sg->dma_address,
+			 sg->dma_length, direction);
+        }
+}
+#endif
+
+/**
+ * dma_sync_sg_for_device
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @sg: list of buffers
+ * @nents: number of buffers to map
+ * @dir: DMA transfer direction
+ *
+ * Make physical memory consistent for a set of streaming
+ * mode DMA translations before a transfer.
+ *
+ * The same as dma_sync_single_for_device but for a
+ * scatter-gather list, same rules and usage.
+ */
+#ifndef dma_sync_sg_for_device
+static inline void
+dma_sync_sg_for_device(struct device *dev, struct scatterlist *sgl,
+		 int nelems, enum dma_data_direction direction)
+{
+	struct scatterlist *sg;
+	int i;
+
+        for_each_sg(sgl, sg, nelems, i) {
+		dma_sync_single_for_device(dev, sg->dma_address,
+			 sg->dma_length, direction);
+        }
+}
+#endif
+
+#ifndef dma_is_consistent
+static inline int
+dma_is_consistent(struct device *dev, dma_addr_t dma_handle)
+{
+	return 1;
+}
+#endif
+
+#ifndef dma_get_cache_alignment
+static inline int
+dma_get_cache_alignment(void)
+{
+	return 1;
+}
+#endif
+
+#ifndef dma_mapping_error
+static inline int
+dma_mapping_error(struct device *dev, dma_addr_t dma_handle)
+{
+	return 0;
+}
+#endif
+
+#ifndef dma_cache_sync
+static inline void
+dma_cache_sync(struct device *dev, void *vaddr, size_t size,
+	       enum dma_data_direction direction)
+{
+}
+#endif
+
+#endif
-- 
1.6.0.4


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

* Re: [PATCH] asm-generic: add a dma-mapping.h file
  2009-05-17 22:45                                 ` [PATCH] asm-generic: add a dma-mapping.h file Arnd Bergmann
@ 2009-05-18  6:03                                   ` Geert Uytterhoeven
  2009-05-18  8:28                                     ` Arnd Bergmann
  2009-05-18 10:45                                   ` FUJITA Tomonori
  2009-05-18 22:54                                   ` Jeff Garzik
  2 siblings, 1 reply; 39+ messages in thread
From: Geert Uytterhoeven @ 2009-05-18  6:03 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Jeff Garzik, Robert Hancock, Tejun Heo, FUJITA Tomonori, alan,
	flar, schmitz, linux-kernel, linux-ide, takata, linux-m68k, ysato

On Mon, May 18, 2009 at 00:45, Arnd Bergmann <arnd@arndb.de> wrote:
> --- /dev/null
> +++ b/include/asm-generic/dma-mapping.h
> @@ -0,0 +1,399 @@
> +#ifndef _ASM_GENERIC_DMA_MAPPING_H
> +#define _ASM_GENERIC_DMA_MAPPING_H
> +/*
> + * This provides a no-op variant of the DMA mapping API,
> + * for use by architectures that do not actually support
> + * DMA, or that are fully consistent and linear-mapped
> + * in their DMA implementation.
> + */
> +
> +#include <asm/scatterlist.h>
> +
> +/*
> + * If any driver asks for DMA, it's not supported.
> + */
> +#ifndef dma_supported
> +static inline int
> +dma_supported(struct device *dev, u64 mask)
> +{
> +       return 0;
> +}
> +#endif
> +
> +#ifndef dma_set_mask
> +static inline int
> +dma_set_mask(struct device *dev, u64 dma_mask)
> +{
> +       if (!dev->dma_mask || !dma_supported(dev, dma_mask))
> +               return -EIO;
> +
> +       *dev->dma_mask = dma_mask;
> +       return 0;
> +}
> +#endif
> +
> +/**
> + * dma_alloc_coherent - allocate consistent memory for DMA
> + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
> + * @size: required memory size
> + * @handle: bus-specific DMA address
> + *
> + * Allocate some uncached, unbuffered memory for a device for
> + * performing DMA.  This function allocates pages, and will
> + * return the CPU-viewed address, and sets @handle to be the
> + * device-viewed address.
> + */
> +#ifndef dma_alloc_coherent
> +static inline void *
> +dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
> +                  gfp_t flag)
> +{
> +       void *virt = kmalloc(size, flag);

kmalloc() may fail.

> +       *dma_handle = virt_to_phys(virt);

Not all variants of virt_to_phys() may handle the NULL case very well.
I took a statistically invalid sample: some just cast to unsigned
long, other subtract PAGE_OFFSET.

Gr{oetje,eeting}s,

						Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
							    -- Linus Torvalds
--
To unsubscribe from this list: send the line "unsubscribe linux-m68k" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH] asm-generic: add a dma-mapping.h file
  2009-05-18  6:03                                   ` Geert Uytterhoeven
@ 2009-05-18  8:28                                     ` Arnd Bergmann
  0 siblings, 0 replies; 39+ messages in thread
From: Arnd Bergmann @ 2009-05-18  8:28 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Jeff Garzik, Robert Hancock, Tejun Heo, FUJITA Tomonori, alan,
	flar, schmitz, linux-kernel, linux-ide, takata, linux-m68k, ysato

On Monday 18 May 2009, Geert Uytterhoeven wrote:

> > +#ifndef dma_alloc_coherent
> > +static inline void *
> > +dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
> > +                  gfp_t flag)
> > +{
> > +       void *virt = kmalloc(size, flag);
> 
> kmalloc() may fail.
> 
> > +       *dma_handle = virt_to_phys(virt);
> 
> Not all variants of virt_to_phys() may handle the NULL case very well.
> I took a statistically invalid sample: some just cast to unsigned
> long, other subtract PAGE_OFFSET.

Right. It should not really hurt, because all users need to check virt
before using dma_handle, but I can fix it just to be sure.

I'll wait for comments from Fujita Tomonori and others before I repost.

	Arnd <><

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

* Re: [PATCH] asm-generic: add a dma-mapping.h file
  2009-05-17 22:45                                 ` [PATCH] asm-generic: add a dma-mapping.h file Arnd Bergmann
  2009-05-18  6:03                                   ` Geert Uytterhoeven
@ 2009-05-18 10:45                                   ` FUJITA Tomonori
  2009-05-18 14:45                                     ` Arnd Bergmann
  2009-05-18 22:54                                   ` Jeff Garzik
  2 siblings, 1 reply; 39+ messages in thread
From: FUJITA Tomonori @ 2009-05-18 10:45 UTC (permalink / raw)
  To: arnd
  Cc: jgarzik, hancockrwd, htejun, fujita.tomonori, alan, flar, schmitz,
	linux-kernel, linux-ide, takata, geert, linux-m68k, ysato

On Sun, 17 May 2009 22:45:21 +0000
Arnd Bergmann <arnd@arndb.de> wrote:

> h8300 and m32r currently do not provide a DMA mapping API
> and therefore cannot use the ATA drivers. This adds a
> generic version of dma-mapping.h for architectures that
> have none or very minimal actual support for DMA in hardware
> and makes the two architectures use it.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> On Sunday 17 May 2009 20:05:54 Jeff Garzik wrote:
> 
> > That's what needs to happen.  We provide no-op functions for e.g. PCI 
> > and x86 DMI, for platforms where this support does not exist.
> > 
> > Pretty much all architectures support some form of ATA.  m68k, m32r, 
> > h8300 and microblaze all have IDE interface, which means that libata 
> > needs to work on that platform.
> > 
> > The only !ATA arch in the entire kernel is s390, AFAICT.
> 
> m68k only defines NO_DMA for Sun3 and Dragonball. Sun3 does
> not have ATA, Dragonball could probably just enable HAS_DMA.
> 
> ---
>  arch/h8300/Kconfig                   |    2 +-
>  arch/h8300/include/asm/dma-mapping.h |    1 +
>  arch/m32r/Kconfig                    |    2 +-
>  arch/m32r/include/asm/dma-mapping.h  |    1 +
>  include/asm-generic/dma-mapping.h    |  399 ++++++++++++++++++++++++++++++++++
>  5 files changed, 403 insertions(+), 2 deletions(-)
>  create mode 100644 arch/h8300/include/asm/dma-mapping.h
>  create mode 100644 arch/m32r/include/asm/dma-mapping.h
>  create mode 100644 include/asm-generic/dma-mapping.h
> 
> diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
> index 9420648..36a037d 100644
> --- a/arch/h8300/Kconfig
> +++ b/arch/h8300/Kconfig
> @@ -74,7 +74,7 @@ config NO_IOPORT
>  	def_bool y
>  
>  config NO_DMA
> -	def_bool y
> +	def_bool n
>  
>  config ISA
>  	bool
> diff --git a/arch/h8300/include/asm/dma-mapping.h b/arch/h8300/include/asm/dma-mapping.h
> new file mode 100644
> index 0000000..e7e1690
> --- /dev/null
> +++ b/arch/h8300/include/asm/dma-mapping.h
> @@ -0,0 +1 @@
> +#include <asm-generic/dma-mapping.h>
> diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
> index cabba33..57ad603 100644
> --- a/arch/m32r/Kconfig
> +++ b/arch/m32r/Kconfig
> @@ -35,7 +35,7 @@ config NO_IOPORT
>  	def_bool y
>  
>  config NO_DMA
> -	def_bool y
> +	def_bool n
>  
>  config HZ
>  	int
> diff --git a/arch/m32r/include/asm/dma-mapping.h b/arch/m32r/include/asm/dma-mapping.h
> new file mode 100644
> index 0000000..e7e1690
> --- /dev/null
> +++ b/arch/m32r/include/asm/dma-mapping.h
> @@ -0,0 +1 @@
> +#include <asm-generic/dma-mapping.h>
> diff --git a/include/asm-generic/dma-mapping.h b/include/asm-generic/dma-mapping.h
> new file mode 100644
> index 0000000..5a14fed
> --- /dev/null
> +++ b/include/asm-generic/dma-mapping.h
> @@ -0,0 +1,399 @@
> +#ifndef _ASM_GENERIC_DMA_MAPPING_H
> +#define _ASM_GENERIC_DMA_MAPPING_H
> +/*
> + * This provides a no-op variant of the DMA mapping API,
> + * for use by architectures that do not actually support
> + * DMA, or that are fully consistent and linear-mapped
> + * in their DMA implementation.
> + */
> +
> +#include <asm/scatterlist.h>
> +
> +/*
> + * If any driver asks for DMA, it's not supported.
> + */
> +#ifndef dma_supported
> +static inline int
> +dma_supported(struct device *dev, u64 mask)
> +{
> +	return 0;
> +}
> +#endif

NACK'ed, sorry.

- these idndef tricks are really ugly and wrong.

- these functions are not generic at all.

- it's confusing to have two ways to handle this issue;
dma-mapping-broken.h and dma-mapping.h.

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

* Re: [PATCH] ata: libata depends on HAS_DMA
  2009-05-15 11:16                     ` Arnd Bergmann
  2009-05-15 11:21                       ` Tejun Heo
@ 2009-05-18 10:45                       ` FUJITA Tomonori
  1 sibling, 0 replies; 39+ messages in thread
From: FUJITA Tomonori @ 2009-05-18 10:45 UTC (permalink / raw)
  To: arnd
  Cc: htejun, fujita.tomonori, hancockrwd, alan, flar, schmitz,
	linux-kernel, jgarzik, linux-ide, takata, geert, linux-m68k,
	ysato

On Fri, 15 May 2009 13:16:30 +0200
Arnd Bergmann <arnd@arndb.de> wrote:

> On Friday 15 May 2009, Tejun Heo wrote:
> > FUJITA Tomonori wrote:
> > > Can libata call dma_supported() per device to decide DMA or PIO mode?
> > > Then, we can solve this problem by add dummy DMA API (just calls BUG)
> > > on such architectures, without Kconfig magic or adding ifdef (like the
> > > old ide stack does), I think.
> 
> That would be the !CONFIG_PCI half of the old
> include/asm-generic/dma-mapping.h file that you just removed,
> right?

No.

The old include/asm-generic/dma-mapping.h is a workaround for lazy
architecture maintainers who have not converted pci_* API to dma_*
API.

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

* Re: [PATCH] asm-generic: add a dma-mapping.h file
  2009-05-18 10:45                                   ` FUJITA Tomonori
@ 2009-05-18 14:45                                     ` Arnd Bergmann
  2009-05-18 22:44                                       ` FUJITA Tomonori
  0 siblings, 1 reply; 39+ messages in thread
From: Arnd Bergmann @ 2009-05-18 14:45 UTC (permalink / raw)
  To: FUJITA Tomonori
  Cc: jgarzik, hancockrwd, htejun, alan, flar, schmitz, linux-kernel,
	linux-ide, takata, geert, linux-m68k, ysato

On Monday 18 May 2009, FUJITA Tomonori wrote:
> 
> NACK'ed, sorry.

I had no idea how hard it would get to fix a simple
allyesconfig build error. This is the third time
that a new approach to getting ATA to build on all
platforms is gets a NAK...

> - these idndef tricks are really ugly and wrong.
> - these functions are not generic at all.

I was trying to do two things at once:

- provide a default implementation for each function
  that an architecture can override, therefore the
  #ifdef magic.
- Have a minimal working implementation of the API
  that at least makes sense for architectures that
  do not support DMA, but want to share some of the
  code.

Ten of the existing architectures simply try do a
linear mapping, and that should easily be possible
in a generic way not too different from what I posted.
Would you agree to a patch that works with the same
code on e.g. arm, microblaze, mn10300 and sh and
uses only a few #ifdefs?

> - it's confusing to have two ways to handle this issue;
> dma-mapping-broken.h and dma-mapping.h.

We actually already have three ways to handle this right
now:

- dma-mapping-broken.h:
  only used on Sun3 m68k, i.e. not interesting any more,
  plus it does not solve the question of how to build
  ATA drivers on architectures without DMA.
- selecting NO_DMA:
  This works fine for everything except ATA. All other
  drivers using dma-mapping.h either depend on HAS_DMA
  or sprinkle their files with #ifdef.
- adding a bogus dma-mapping.h: cris, um and microblaze
  currently set HAS_DMA but add a dma-mapping.h that
  allows stuff to compile but cannot actually work.

I think that dma-mapping-broken.h has served its purpose
and we should now have two implementations in asm-generic,
the one you posted recently for ia64, x86, parisc, powerpc
and sparc64 and one for all architectures that only have
linear mappings. The version I posted is certainly not
generic enough for those, but I can keep improving it.

	Arnd <><

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

* Re: [PATCH] asm-generic: add a dma-mapping.h file
  2009-05-18 14:45                                     ` Arnd Bergmann
@ 2009-05-18 22:44                                       ` FUJITA Tomonori
  2009-05-19 16:22                                         ` Arnd Bergmann
  0 siblings, 1 reply; 39+ messages in thread
From: FUJITA Tomonori @ 2009-05-18 22:44 UTC (permalink / raw)
  To: arnd
  Cc: fujita.tomonori, jgarzik, hancockrwd, htejun, alan, flar, schmitz,
	linux-kernel, linux-ide, takata, geert, linux-m68k, ysato

On Mon, 18 May 2009 16:45:24 +0200
Arnd Bergmann <arnd@arndb.de> wrote:

> On Monday 18 May 2009, FUJITA Tomonori wrote:
> > 
> > NACK'ed, sorry.
> 
> I had no idea how hard it would get to fix a simple
> allyesconfig build error. This is the third time
> that a new approach to getting ATA to build on all
> platforms is gets a NAK...
> 
> > - these idndef tricks are really ugly and wrong.
> > - these functions are not generic at all.
> 
> I was trying to do two things at once:
> 
> - provide a default implementation for each function
>   that an architecture can override, therefore the
>   #ifdef magic.

I know what you tried with #ifdef but having something like '#define
dma_map_sg' in arch's dma-mapping.h is unacceptable.


> - Have a minimal working implementation of the API
>   that at least makes sense for architectures that
>   do not support DMA, but want to share some of the
>   code.

Well, it might make sense but we don't call architectures that don't
support DMA 'generic'.


> Ten of the existing architectures simply try do a
> linear mapping, and that should easily be possible
> in a generic way not too different from what I posted.

Your proposal doesn't work with arch/x86/kernel/pci-nommu.c, which
is trying a linear mapping, what you are talking about.


> Would you agree to a patch that works with the same
> code on e.g. arm, microblaze, mn10300 and sh and
> uses only a few #ifdefs?

Having such helper for a linear mapping might be helpful but your
approach is wrong.


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

* Re: [PATCH] asm-generic: add a dma-mapping.h file
  2009-05-17 22:45                                 ` [PATCH] asm-generic: add a dma-mapping.h file Arnd Bergmann
  2009-05-18  6:03                                   ` Geert Uytterhoeven
  2009-05-18 10:45                                   ` FUJITA Tomonori
@ 2009-05-18 22:54                                   ` Jeff Garzik
  2009-05-18 23:22                                     ` FUJITA Tomonori
  2 siblings, 1 reply; 39+ messages in thread
From: Jeff Garzik @ 2009-05-18 22:54 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Robert Hancock, Tejun Heo, FUJITA Tomonori, alan, flar, schmitz,
	linux-kernel, linux-ide, takata, geert, linux-m68k, ysato

Arnd Bergmann wrote:
> h8300 and m32r currently do not provide a DMA mapping API
> and therefore cannot use the ATA drivers. This adds a
> generic version of dma-mapping.h for architectures that
> have none or very minimal actual support for DMA in hardware
> and makes the two architectures use it.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> On Sunday 17 May 2009 20:05:54 Jeff Garzik wrote:
> 
>> That's what needs to happen.  We provide no-op functions for e.g. PCI 
>> and x86 DMI, for platforms where this support does not exist.
>>
>> Pretty much all architectures support some form of ATA.  m68k, m32r, 
>> h8300 and microblaze all have IDE interface, which means that libata 
>> needs to work on that platform.
>>
>> The only !ATA arch in the entire kernel is s390, AFAICT.
> 
> m68k only defines NO_DMA for Sun3 and Dragonball. Sun3 does
> not have ATA, Dragonball could probably just enable HAS_DMA.
> 
> ---
>  arch/h8300/Kconfig                   |    2 +-
>  arch/h8300/include/asm/dma-mapping.h |    1 +
>  arch/m32r/Kconfig                    |    2 +-
>  arch/m32r/include/asm/dma-mapping.h  |    1 +
>  include/asm-generic/dma-mapping.h    |  399 ++++++++++++++++++++++++++++++++++
>  5 files changed, 403 insertions(+), 2 deletions(-)
>  create mode 100644 arch/h8300/include/asm/dma-mapping.h
>  create mode 100644 arch/m32r/include/asm/dma-mapping.h
>  create mode 100644 include/asm-generic/dma-mapping.h

My main comment is a bit non-specific...   I tend to think that all 
no-dma platforms should provide an API whose implementation always 
returns errors, e.g. an inlined version of dma-mapping-broken.h.

That sort of setup permits the compiler's dead code elimination to work 
on these no-dma platforms, while not crapping up the libata code with a 
bunch of ifdefs.

	Jeff





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

* Re: [PATCH] asm-generic: add a dma-mapping.h file
  2009-05-18 22:54                                   ` Jeff Garzik
@ 2009-05-18 23:22                                     ` FUJITA Tomonori
  0 siblings, 0 replies; 39+ messages in thread
From: FUJITA Tomonori @ 2009-05-18 23:22 UTC (permalink / raw)
  To: jgarzik
  Cc: arnd, hancockrwd, htejun, fujita.tomonori, alan, flar, schmitz,
	linux-kernel, linux-ide, takata, geert, linux-m68k, ysato

On Mon, 18 May 2009 18:54:49 -0400
Jeff Garzik <jgarzik@pobox.com> wrote:

> Arnd Bergmann wrote:
> > h8300 and m32r currently do not provide a DMA mapping API
> > and therefore cannot use the ATA drivers. This adds a
> > generic version of dma-mapping.h for architectures that
> > have none or very minimal actual support for DMA in hardware
> > and makes the two architectures use it.
> > 
> > Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> > ---
> > On Sunday 17 May 2009 20:05:54 Jeff Garzik wrote:
> > 
> >> That's what needs to happen.  We provide no-op functions for e.g. PCI 
> >> and x86 DMI, for platforms where this support does not exist.
> >>
> >> Pretty much all architectures support some form of ATA.  m68k, m32r, 
> >> h8300 and microblaze all have IDE interface, which means that libata 
> >> needs to work on that platform.
> >>
> >> The only !ATA arch in the entire kernel is s390, AFAICT.
> > 
> > m68k only defines NO_DMA for Sun3 and Dragonball. Sun3 does
> > not have ATA, Dragonball could probably just enable HAS_DMA.
> > 
> > ---
> >  arch/h8300/Kconfig                   |    2 +-
> >  arch/h8300/include/asm/dma-mapping.h |    1 +
> >  arch/m32r/Kconfig                    |    2 +-
> >  arch/m32r/include/asm/dma-mapping.h  |    1 +
> >  include/asm-generic/dma-mapping.h    |  399 ++++++++++++++++++++++++++++++++++
> >  5 files changed, 403 insertions(+), 2 deletions(-)
> >  create mode 100644 arch/h8300/include/asm/dma-mapping.h
> >  create mode 100644 arch/m32r/include/asm/dma-mapping.h
> >  create mode 100644 include/asm-generic/dma-mapping.h
> 
> My main comment is a bit non-specific...   I tend to think that all 
> no-dma platforms should provide an API whose implementation always 
> returns errors, e.g. an inlined version of dma-mapping-broken.h.
> 
> That sort of setup permits the compiler's dead code elimination to work 
> on these no-dma platforms, while not crapping up the libata code with a 
> bunch of ifdefs.

Just adding one ifdef to libata.h works? What libata needs is just
wrapping dma_map_sg and dma_unmap_sg like the old ide stack does.

I'm not against the idea of an inlined version of dma-mapping-broken.h
but having two ways to handle this issue is a bit confusing; so far
what we done to handle this problem is using NO_DMA, like SCSI-ml
does, not putting the dma code in non-architecture code and having
something like scsi_lib_dma.c.

Is it theoretically correct that the dma mapping API lives in low
level drivers instead of libata-core (like how SCSI-ml does)?

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

* Re: [PATCH] asm-generic: add a dma-mapping.h file
  2009-05-18 22:44                                       ` FUJITA Tomonori
@ 2009-05-19 16:22                                         ` Arnd Bergmann
  2009-05-19 17:01                                           ` Grant Grundler
  2009-05-22 12:12                                           ` FUJITA Tomonori
  0 siblings, 2 replies; 39+ messages in thread
From: Arnd Bergmann @ 2009-05-19 16:22 UTC (permalink / raw)
  To: FUJITA Tomonori
  Cc: jgarzik, hancockrwd, htejun, alan, flar, schmitz, linux-kernel,
	linux-ide, takata, geert, linux-m68k, ysato

On Tuesday 19 May 2009, FUJITA Tomonori wrote:
> > Would you agree to a patch that works with the same
> > code on e.g. arm, microblaze, mn10300 and sh and
> > uses only a few #ifdefs?
> 
> Having such helper for a linear mapping might be helpful but your
> approach is wrong.

Do you like this approach better? I've merged a few architectures
that were relatively simple. This file should be usable by all
architectures that have a linear mapping and are either fully coherent
(like cris) or just require flushing the dcache when passing a
buffer to the device.

It's become pretty obvious where some of my bugs were in the previous
code, I hopefully did better this time and maybe you find the rest.
I've also added the dma debugging stuff in here and fixed a number
of bugs in all the different architectures on the way, but I can
send separate patches for those before doing the merge.

I've also tried merging frv and m68k, but they have some peculiarities
that made it slightly harder.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>

 include/asm-generic/dma-mapping-linear.h |  391 +++++++++++++++++++++++++++++
 arch/avr32/include/asm/dma-mapping.h     |  408 ++++---------------------------
 arch/blackfin/include/asm/dma-mapping.h  |  118 +-------
 arch/cris/include/asm/dma-mapping.h      |  194 +-------------
 arch/mn10300/include/asm/dma-mapping.h   |  266 ++------------------
 arch/sh/include/asm/dma-mapping.h        |  258 ++-----------------
 arch/xtensa/include/asm/dma-mapping.h    |  220 +++-------------
 7 files changed, 606 insertions(+), 1249 deletions(-)

diff --git a/include/asm-generic/dma-mapping-linear.h b/include/asm-generic/dma-mapping-linear.h
new file mode 100644
index 0000000..13f37db
--- /dev/null
+++ b/include/asm-generic/dma-mapping-linear.h
@@ -0,0 +1,391 @@
+#ifndef __ASM_GENERIC_DMA_MAPPING_H
+#define __ASM_GENERIC_DMA_MAPPING_H
+
+#include <linux/mm.h>
+#include <linux/device.h>
+#include <linux/dma-debug.h>
+#include <linux/scatterlist.h>
+#include <asm/cacheflush.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_DMA_COHERENT
+/*
+ * An architecture should override these if it needs to
+ * perform cache flushes before passing bus addresses
+ * to a device.
+ * It can either do a full flush in dma_coherent_dev
+ * and return 1 from there, or implement more specific
+ * synchronization in dma_cache_sync, which will be
+ * applied separately to each sg element.
+ */
+static inline int
+dma_coherent_dev(struct device *dev)
+{
+	return 1;
+}
+
+static inline void
+dma_cache_sync(struct device *dev, void *cpu_addr, size_t size,
+	       enum dma_data_direction direction)
+{
+}
+
+/**
+ * dma_alloc_coherent - allocate consistent memory for DMA
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @size: required memory size
+ * @handle: bus-specific DMA address
+ *
+ * Allocate some uncached, unbuffered memory for a device for
+ * performing DMA.  This function allocates pages, and will
+ * return the CPU-viewed address, and sets @handle to be the
+ * device-viewed address.
+ */
+void *dma_alloc_coherent(struct device *dev, size_t size,
+				dma_addr_t *dma_handle, gfp_t flag)
+{
+	void *ret;
+	struct page *page;
+	int node = dev_to_node(dev);
+
+	/* ignore region specifiers */
+	flag  &= ~(__GFP_HIGHMEM);
+
+	page = alloc_pages_node(node, flag, get_order(size));
+	if (page == NULL)
+		return NULL;
+	ret = page_address(page);
+	memset(ret, 0, size);
+	*dma_handle = virt_to_abs(ret) + get_dma_direct_offset(dev);
+
+	return ret;
+}
+
+/**
+ * dma_free_coherent - free memory allocated by dma_alloc_coherent
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @size: size of memory originally requested in dma_alloc_coherent
+ * @cpu_addr: CPU-view address returned from dma_alloc_coherent
+ * @handle: device-view address returned from dma_alloc_coherent
+ *
+ * Free (and unmap) a DMA buffer previously allocated by
+ * dma_alloc_coherent().
+ *
+ * References to memory and mappings associated with cpu_addr/handle
+ * during and after this call executing are illegal.
+ */
+void dma_free_coherent(struct device *dev, size_t size,
+			      void *vaddr, dma_addr_t dma_handle)
+{
+	free_pages((unsigned long)vaddr, get_order(size));
+}
+#else
+extern void *
+dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
+		   gfp_t flag);
+
+extern void
+dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
+		  dma_addr_t dma_handle);
+#endif
+
+#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
+#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+
+/**
+ * dma_map_single - map a single buffer for streaming DMA
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @cpu_addr: CPU direct mapped address of buffer
+ * @size: size of buffer to map
+ * @dir: DMA transfer direction
+ *
+ * Ensure that any data held in the cache is appropriately discarded
+ * or written back.
+ *
+ * The device owns this memory once this call has completed.  The CPU
+ * can regain ownership by calling dma_unmap_single() or dma_sync_single().
+ */
+static inline dma_addr_t
+dma_map_single(struct device *dev, void *ptr, size_t size,
+	       enum dma_data_direction direction)
+{
+	dma_addr_t dma_addr = virt_to_bus(ptr);
+	BUG_ON(!valid_dma_direction(direction));
+
+	if (!dma_coherent_dev(dev))
+		dma_cache_sync(dev, ptr, size, direction);
+
+	debug_dma_map_page(dev, virt_to_page(ptr),
+			   (unsigned long)ptr & ~PAGE_MASK, size,
+			   direction, dma_addr, true);
+
+	return dma_addr;
+}
+
+/**
+ * dma_unmap_single - unmap a single buffer previously mapped
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @handle: DMA address of buffer
+ * @size: size of buffer to map
+ * @dir: DMA transfer direction
+ *
+ * Unmap a single streaming mode DMA translation.  The handle and size
+ * must match what was provided in the previous dma_map_single() call.
+ * All other usages are undefined.
+ *
+ * After this call, reads by the CPU to the buffer are guaranteed to see
+ * whatever the device wrote there.
+ */
+static inline void
+dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
+		 enum dma_data_direction direction)
+{
+	debug_dma_unmap_page(dev, dma_addr, size, direction, true);
+}
+
+/**
+ * dma_map_sg - map a set of SG buffers for streaming mode DMA
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @sg: list of buffers
+ * @nents: number of buffers to map
+ * @dir: DMA transfer direction
+ *
+ * Map a set of buffers described by scatterlist in streaming
+ * mode for DMA.  This is the scatter-gather version of the
+ * above pci_map_single interface.  Here the scatter gather list
+ * elements are each tagged with the appropriate dma address
+ * and length.  They are obtained via sg_dma_{address,length}(SG).
+ *
+ * NOTE: An implementation may be able to use a smaller number of
+ *       DMA address/length pairs than there are SG table elements.
+ *       (for example via virtual mapping capabilities)
+ *       The routine returns the number of addr/length pairs actually
+ *       used, at most nents.
+ *
+ * Device ownership issues as mentioned above for pci_map_single are
+ * the same here.
+ */
+static inline int
+dma_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
+	   enum dma_data_direction direction)
+{
+	struct scatterlist *sg;
+	int i, sync;
+
+	BUG_ON(!valid_dma_direction(direction));
+	WARN_ON(nents == 0 || sglist[0].length == 0);
+
+	sync = !dma_coherent_dev(dev);
+
+	for_each_sg(sglist, sg, nents, i) {
+		BUG_ON(!sg_page(sg));
+
+		sg->dma_address = page_to_bus(sg_page(sg)) + sg->offset;
+		sg_dma_len(sg) = sg->length;
+		if (sync)
+			dma_cache_sync(dev, sg_virt(sg), sg->length, direction);
+	}
+
+	debug_dma_map_sg(dev, sg, nents, i, direction);
+
+	return nents;
+}
+
+/**
+ * dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @sg: list of buffers
+ * @nents: number of buffers to map
+ * @dir: DMA transfer direction
+ *
+ * Unmap a set of streaming mode DMA translations.
+ * Again, CPU read rules concerning calls here are the same as for
+ * pci_unmap_single() above.
+ */
+static inline void
+dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
+	     enum dma_data_direction direction)
+{
+	debug_dma_unmap_sg(dev, sg, nhwentries, direction);
+}
+
+/**
+ * dma_map_page - map a portion of a page for streaming DMA
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @page: page that buffer resides in
+ * @offset: offset into page for start of buffer
+ * @size: size of buffer to map
+ * @dir: DMA transfer direction
+ *
+ * Ensure that any data held in the cache is appropriately discarded
+ * or written back.
+ *
+ * The device owns this memory once this call has completed.  The CPU
+ * can regain ownership by calling dma_unmap_page() or dma_sync_single().
+ */
+static inline dma_addr_t
+dma_map_page(struct device *dev, struct page *page, unsigned long offset,
+	     size_t size, enum dma_data_direction direction)
+{
+	return dma_map_single(dev, page_address(page) + offset,
+			      size, direction);
+}
+
+/**
+ * dma_unmap_page - unmap a buffer previously mapped through dma_map_page()
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @handle: DMA address of buffer
+ * @size: size of buffer to map
+ * @dir: DMA transfer direction
+ *
+ * Unmap a single streaming mode DMA translation.  The handle and size
+ * must match what was provided in the previous dma_map_single() call.
+ * All other usages are undefined.
+ *
+ * After this call, reads by the CPU to the buffer are guaranteed to see
+ * whatever the device wrote there.
+ */
+static inline void
+dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
+	       enum dma_data_direction direction)
+{
+	dma_unmap_single(dev, dma_address, size, direction);
+}
+
+/**
+ * dma_sync_single_for_cpu
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @handle: DMA address of buffer
+ * @size: size of buffer to map
+ * @dir: DMA transfer direction
+ *
+ * Make physical memory consistent for a single streaming mode DMA
+ * translation after a transfer.
+ *
+ * If you perform a dma_map_single() but wish to interrogate the
+ * buffer using the cpu, yet do not wish to teardown the DMA mapping,
+ * you must call this function before doing so.  At the next point you
+ * give the DMA address back to the card, you must first perform a
+ * dma_sync_single_for_device, and then the device again owns the
+ * buffer.
+ */
+static inline void
+dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
+			enum dma_data_direction direction)
+{
+	debug_dma_sync_single_for_cpu(dev, dma_handle, size, direction);
+}
+
+static inline void
+dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
+			      unsigned long offset, size_t size,
+			      enum dma_data_direction direction)
+{
+	debug_dma_sync_single_range_for_cpu(dev, dma_handle,
+					    offset, size, direction);
+}
+
+/**
+ * dma_sync_sg_for_cpu
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @sg: list of buffers
+ * @nents: number of buffers to map
+ * @dir: DMA transfer direction
+ *
+ * Make physical memory consistent for a set of streaming
+ * mode DMA translations after a transfer.
+ *
+ * The same as dma_sync_single_for_* but for a scatter-gather list,
+ * same rules and usage.
+ */
+static inline void
+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents,
+		    enum dma_data_direction direction)
+{
+	debug_dma_sync_sg_for_cpu(dev, sg, nents, direction);
+}
+
+static inline void
+dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
+			   size_t size, enum dma_data_direction direction)
+{
+	if (!dma_coherent_dev(dev))
+		dma_cache_sync(dev, bus_to_virt(dma_handle), size, direction);
+	debug_dma_sync_single_for_device(dev, dma_handle, size, direction);
+}
+
+static inline void
+dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
+				 unsigned long offset, size_t size,
+				 enum dma_data_direction direction)
+{
+	if (!dma_coherent_dev(dev))
+		dma_cache_sync(dev, bus_to_virt(dma_handle), size, direction);
+	debug_dma_sync_single_range_for_device(dev, dma_handle,
+					       offset, size, direction);
+}
+
+static inline void
+dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist,
+		       int nents, enum dma_data_direction direction)
+{
+	struct scatterlist *sg;
+	int i;
+
+	if (!dma_coherent_dev(dev))
+		for_each_sg(sglist, sg, nents, i)
+			dma_cache_sync(dev, sg_virt(sg), sg->length, direction);
+
+	debug_dma_sync_sg_for_device(dev, sg, nents, direction);
+}
+
+static inline int
+dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+	return 0;
+}
+
+/*
+ * Return whether the given device DMA address mask can be supported
+ * properly.  For example, if your device can only drive the low 24-bits
+ * during bus mastering, then you would pass 0x00ffffff as the mask
+ * to this function.
+ */
+static inline int
+dma_supported(struct device *dev, u64 mask)
+{
+	/*
+	 * we fall back to GFP_DMA when the mask isn't all 1s,
+	 * so we can't guarantee allocations that must be
+	 * within a tighter range than GFP_DMA.
+	 */
+	if (mask < 0x00ffffff)
+		return 0;
+
+	return 1;
+}
+
+static inline int
+dma_set_mask(struct device *dev, u64 dma_mask)
+{
+	if (!dev->dma_mask || !dma_supported(dev, dma_mask))
+		return -EIO;
+
+	*dev->dma_mask = dma_mask;
+
+	return 0;
+}
+
+static inline int
+dma_get_cache_alignment(void)
+{
+	return L1_CACHE_BYTES;
+}
+
+static inline int
+dma_is_consistent(struct device *dev, dma_addr_t dma_addr)
+{
+	return dma_coherent_dev(dev);
+}
+
+#endif /* __ASM_GENERIC_DMA_MAPPING_H */
diff --git a/arch/avr32/include/asm/dma-mapping.h b/arch/avr32/include/asm/dma-mapping.h
dissimilarity index 86%
index 0399359..b1d73fb 100644
--- a/arch/avr32/include/asm/dma-mapping.h
+++ b/arch/avr32/include/asm/dma-mapping.h
@@ -1,349 +1,59 @@
-#ifndef __ASM_AVR32_DMA_MAPPING_H
-#define __ASM_AVR32_DMA_MAPPING_H
-
-#include <linux/mm.h>
-#include <linux/device.h>
-#include <linux/scatterlist.h>
-#include <asm/processor.h>
-#include <asm/cacheflush.h>
-#include <asm/io.h>
-
-extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
-	int direction);
-
-/*
- * Return whether the given device DMA address mask can be supported
- * properly.  For example, if your device can only drive the low 24-bits
- * during bus mastering, then you would pass 0x00ffffff as the mask
- * to this function.
- */
-static inline int dma_supported(struct device *dev, u64 mask)
-{
-	/* Fix when needed. I really don't know of any limitations */
-	return 1;
-}
-
-static inline int dma_set_mask(struct device *dev, u64 dma_mask)
-{
-	if (!dev->dma_mask || !dma_supported(dev, dma_mask))
-		return -EIO;
-
-	*dev->dma_mask = dma_mask;
-	return 0;
-}
-
-/*
- * dma_map_single can't fail as it is implemented now.
- */
-static inline int dma_mapping_error(struct device *dev, dma_addr_t addr)
-{
-	return 0;
-}
-
-/**
- * dma_alloc_coherent - allocate consistent memory for DMA
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @size: required memory size
- * @handle: bus-specific DMA address
- *
- * Allocate some uncached, unbuffered memory for a device for
- * performing DMA.  This function allocates pages, and will
- * return the CPU-viewed address, and sets @handle to be the
- * device-viewed address.
- */
-extern void *dma_alloc_coherent(struct device *dev, size_t size,
-				dma_addr_t *handle, gfp_t gfp);
-
-/**
- * dma_free_coherent - free memory allocated by dma_alloc_coherent
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @size: size of memory originally requested in dma_alloc_coherent
- * @cpu_addr: CPU-view address returned from dma_alloc_coherent
- * @handle: device-view address returned from dma_alloc_coherent
- *
- * Free (and unmap) a DMA buffer previously allocated by
- * dma_alloc_coherent().
- *
- * References to memory and mappings associated with cpu_addr/handle
- * during and after this call executing are illegal.
- */
-extern void dma_free_coherent(struct device *dev, size_t size,
-			      void *cpu_addr, dma_addr_t handle);
-
-/**
- * dma_alloc_writecombine - allocate write-combining memory for DMA
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @size: required memory size
- * @handle: bus-specific DMA address
- *
- * Allocate some uncached, buffered memory for a device for
- * performing DMA.  This function allocates pages, and will
- * return the CPU-viewed address, and sets @handle to be the
- * device-viewed address.
- */
-extern void *dma_alloc_writecombine(struct device *dev, size_t size,
-				    dma_addr_t *handle, gfp_t gfp);
-
-/**
- * dma_free_coherent - free memory allocated by dma_alloc_writecombine
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @size: size of memory originally requested in dma_alloc_writecombine
- * @cpu_addr: CPU-view address returned from dma_alloc_writecombine
- * @handle: device-view address returned from dma_alloc_writecombine
- *
- * Free (and unmap) a DMA buffer previously allocated by
- * dma_alloc_writecombine().
- *
- * References to memory and mappings associated with cpu_addr/handle
- * during and after this call executing are illegal.
- */
-extern void dma_free_writecombine(struct device *dev, size_t size,
-				  void *cpu_addr, dma_addr_t handle);
-
-/**
- * dma_map_single - map a single buffer for streaming DMA
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @cpu_addr: CPU direct mapped address of buffer
- * @size: size of buffer to map
- * @dir: DMA transfer direction
- *
- * Ensure that any data held in the cache is appropriately discarded
- * or written back.
- *
- * The device owns this memory once this call has completed.  The CPU
- * can regain ownership by calling dma_unmap_single() or dma_sync_single().
- */
-static inline dma_addr_t
-dma_map_single(struct device *dev, void *cpu_addr, size_t size,
-	       enum dma_data_direction direction)
-{
-	dma_cache_sync(dev, cpu_addr, size, direction);
-	return virt_to_bus(cpu_addr);
-}
-
-/**
- * dma_unmap_single - unmap a single buffer previously mapped
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @handle: DMA address of buffer
- * @size: size of buffer to map
- * @dir: DMA transfer direction
- *
- * Unmap a single streaming mode DMA translation.  The handle and size
- * must match what was provided in the previous dma_map_single() call.
- * All other usages are undefined.
- *
- * After this call, reads by the CPU to the buffer are guaranteed to see
- * whatever the device wrote there.
- */
-static inline void
-dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-		 enum dma_data_direction direction)
-{
-
-}
-
-/**
- * dma_map_page - map a portion of a page for streaming DMA
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @page: page that buffer resides in
- * @offset: offset into page for start of buffer
- * @size: size of buffer to map
- * @dir: DMA transfer direction
- *
- * Ensure that any data held in the cache is appropriately discarded
- * or written back.
- *
- * The device owns this memory once this call has completed.  The CPU
- * can regain ownership by calling dma_unmap_page() or dma_sync_single().
- */
-static inline dma_addr_t
-dma_map_page(struct device *dev, struct page *page,
-	     unsigned long offset, size_t size,
-	     enum dma_data_direction direction)
-{
-	return dma_map_single(dev, page_address(page) + offset,
-			      size, direction);
-}
-
-/**
- * dma_unmap_page - unmap a buffer previously mapped through dma_map_page()
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @handle: DMA address of buffer
- * @size: size of buffer to map
- * @dir: DMA transfer direction
- *
- * Unmap a single streaming mode DMA translation.  The handle and size
- * must match what was provided in the previous dma_map_single() call.
- * All other usages are undefined.
- *
- * After this call, reads by the CPU to the buffer are guaranteed to see
- * whatever the device wrote there.
- */
-static inline void
-dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-	       enum dma_data_direction direction)
-{
-	dma_unmap_single(dev, dma_address, size, direction);
-}
-
-/**
- * dma_map_sg - map a set of SG buffers for streaming mode DMA
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @sg: list of buffers
- * @nents: number of buffers to map
- * @dir: DMA transfer direction
- *
- * Map a set of buffers described by scatterlist in streaming
- * mode for DMA.  This is the scatter-gather version of the
- * above pci_map_single interface.  Here the scatter gather list
- * elements are each tagged with the appropriate dma address
- * and length.  They are obtained via sg_dma_{address,length}(SG).
- *
- * NOTE: An implementation may be able to use a smaller number of
- *       DMA address/length pairs than there are SG table elements.
- *       (for example via virtual mapping capabilities)
- *       The routine returns the number of addr/length pairs actually
- *       used, at most nents.
- *
- * Device ownership issues as mentioned above for pci_map_single are
- * the same here.
- */
-static inline int
-dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-	   enum dma_data_direction direction)
-{
-	int i;
-
-	for (i = 0; i < nents; i++) {
-		char *virt;
-
-		sg[i].dma_address = page_to_bus(sg_page(&sg[i])) + sg[i].offset;
-		virt = sg_virt(&sg[i]);
-		dma_cache_sync(dev, virt, sg[i].length, direction);
-	}
-
-	return nents;
-}
-
-/**
- * dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @sg: list of buffers
- * @nents: number of buffers to map
- * @dir: DMA transfer direction
- *
- * Unmap a set of streaming mode DMA translations.
- * Again, CPU read rules concerning calls here are the same as for
- * pci_unmap_single() above.
- */
-static inline void
-dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-	     enum dma_data_direction direction)
-{
-
-}
-
-/**
- * dma_sync_single_for_cpu
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @handle: DMA address of buffer
- * @size: size of buffer to map
- * @dir: DMA transfer direction
- *
- * Make physical memory consistent for a single streaming mode DMA
- * translation after a transfer.
- *
- * If you perform a dma_map_single() but wish to interrogate the
- * buffer using the cpu, yet do not wish to teardown the DMA mapping,
- * you must call this function before doing so.  At the next point you
- * give the DMA address back to the card, you must first perform a
- * dma_sync_single_for_device, and then the device again owns the
- * buffer.
- */
-static inline void
-dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
-			size_t size, enum dma_data_direction direction)
-{
-	/*
-	 * No need to do anything since the CPU isn't supposed to
-	 * touch this memory after we flushed it at mapping- or
-	 * sync-for-device time.
-	 */
-}
-
-static inline void
-dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
-			   size_t size, enum dma_data_direction direction)
-{
-	dma_cache_sync(dev, bus_to_virt(dma_handle), size, direction);
-}
-
-static inline void
-dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
-			      unsigned long offset, size_t size,
-			      enum dma_data_direction direction)
-{
-	/* just sync everything, that's all the pci API can do */
-	dma_sync_single_for_cpu(dev, dma_handle, offset+size, direction);
-}
-
-static inline void
-dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
-				 unsigned long offset, size_t size,
-				 enum dma_data_direction direction)
-{
-	/* just sync everything, that's all the pci API can do */
-	dma_sync_single_for_device(dev, dma_handle, offset+size, direction);
-}
-
-/**
- * dma_sync_sg_for_cpu
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @sg: list of buffers
- * @nents: number of buffers to map
- * @dir: DMA transfer direction
- *
- * Make physical memory consistent for a set of streaming
- * mode DMA translations after a transfer.
- *
- * The same as dma_sync_single_for_* but for a scatter-gather list,
- * same rules and usage.
- */
-static inline void
-dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
-		    int nents, enum dma_data_direction direction)
-{
-	/*
-	 * No need to do anything since the CPU isn't supposed to
-	 * touch this memory after we flushed it at mapping- or
-	 * sync-for-device time.
-	 */
-}
-
-static inline void
-dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
-		       int nents, enum dma_data_direction direction)
-{
-	int i;
-
-	for (i = 0; i < nents; i++) {
-		dma_cache_sync(dev, sg_virt(&sg[i]), sg[i].length, direction);
-	}
-}
-
-/* Now for the API extensions over the pci_ one */
-
-#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
-#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
-
-static inline int dma_is_consistent(struct device *dev, dma_addr_t dma_addr)
-{
-	return 1;
-}
-
-static inline int dma_get_cache_alignment(void)
-{
-	return boot_cpu_data.dcache.linesz;
-}
-
-#endif /* __ASM_AVR32_DMA_MAPPING_H */
+#ifndef __ASM_AVR32_DMA_MAPPING_H
+#define __ASM_AVR32_DMA_MAPPING_H
+
+#include <linux/mm.h>
+#include <linux/device.h>
+#include <linux/scatterlist.h>
+#include <asm/processor.h>
+#include <asm/cacheflush.h>
+#include <asm/io.h>
+
+static inline int
+dma_coherent_dev(struct device *dev)
+{
+	return 0;
+}
+
+extern void
+dma_cache_sync(struct device *dev, void *cpu_addr, size_t size,
+	       enum dma_data_direction direction);
+
+static inline int
+dma_get_cache_alignment(void)
+{
+	return boot_cpu_data.dcache.linesz;
+}
+
+/**
+ * dma_alloc_writecombine - allocate write-combining memory for DMA
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @size: required memory size
+ * @handle: bus-specific DMA address
+ *
+ * Allocate some uncached, buffered memory for a device for
+ * performing DMA.  This function allocates pages, and will
+ * return the CPU-viewed address, and sets @handle to be the
+ * device-viewed address.
+ */
+extern void *dma_alloc_writecombine(struct device *dev, size_t size,
+				    dma_addr_t *handle, gfp_t gfp);
+
+/**
+ * dma_free_writecombine - free memory allocated by dma_alloc_writecombine
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @size: size of memory originally requested in dma_alloc_writecombine
+ * @cpu_addr: CPU-view address returned from dma_alloc_writecombine
+ * @handle: device-view address returned from dma_alloc_writecombine
+ *
+ * Free (and unmap) a DMA buffer previously allocated by
+ * dma_alloc_writecombine().
+ *
+ * References to memory and mappings associated with cpu_addr/handle
+ * during and after this call executing are illegal.
+ */
+extern void dma_free_writecombine(struct device *dev, size_t size,
+				  void *cpu_addr, dma_addr_t handle);
+
+#include <asm-generic/dma-mapping-linear.h>
+
+#endif /* __ASM_AVR32_DMA_MAPPING_H */
diff --git a/arch/blackfin/include/asm/dma-mapping.h b/arch/blackfin/include/asm/dma-mapping.h
dissimilarity index 95%
index d7d9148..169d82d 100644
--- a/arch/blackfin/include/asm/dma-mapping.h
+++ b/arch/blackfin/include/asm/dma-mapping.h
@@ -1,98 +1,20 @@
-#ifndef _BLACKFIN_DMA_MAPPING_H
-#define _BLACKFIN_DMA_MAPPING_H
-
-#include <asm/scatterlist.h>
-
-void dma_alloc_init(unsigned long start, unsigned long end);
-void *dma_alloc_coherent(struct device *dev, size_t size,
-			 dma_addr_t *dma_handle, gfp_t gfp);
-void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
-		       dma_addr_t dma_handle);
-
-/*
- * Now for the API extensions over the pci_ one
- */
-#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
-#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
-
-static inline
-int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-{
-	return 0;
-}
-
-/*
- * Map a single buffer of the indicated size for DMA in streaming mode.
- * The 32-bit bus address to use is returned.
- *
- * Once the device is given the dma address, the device owns this memory
- * until either pci_unmap_single or pci_dma_sync_single is performed.
- */
-extern dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
-				 enum dma_data_direction direction);
-
-static inline dma_addr_t
-dma_map_page(struct device *dev, struct page *page,
-	     unsigned long offset, size_t size,
-	     enum dma_data_direction dir)
-{
-	return dma_map_single(dev, page_address(page) + offset, size, dir);
-}
-
-/*
- * Unmap a single streaming mode DMA translation.  The dma_addr and size
- * must match what was provided for in a previous pci_map_single call.  All
- * other usages are undefined.
- *
- * After this call, reads by the cpu to the buffer are guarenteed to see
- * whatever the device wrote there.
- */
-extern void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-			  enum dma_data_direction direction);
-
-static inline void
-dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
-	       enum dma_data_direction dir)
-{
-	dma_unmap_single(dev, dma_addr, size, dir);
-}
-
-/*
- * Map a set of buffers described by scatterlist in streaming
- * mode for DMA.  This is the scather-gather version of the
- * above pci_map_single interface.  Here the scatter gather list
- * elements are each tagged with the appropriate dma address
- * and length.  They are obtained via sg_dma_{address,length}(SG).
- *
- * NOTE: An implementation may be able to use a smaller number of
- *       DMA address/length pairs than there are SG table elements.
- *       (for example via virtual mapping capabilities)
- *       The routine returns the number of addr/length pairs actually
- *       used, at most nents.
- *
- * Device ownership issues as mentioned above for pci_map_single are
- * the same here.
- */
-extern int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-		      enum dma_data_direction direction);
-
-/*
- * Unmap a set of streaming mode DMA translations.
- * Again, cpu read rules concerning calls here are the same as for
- * pci_unmap_single() above.
- */
-extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
-		      int nhwentries, enum dma_data_direction direction);
-
-static inline void dma_sync_single_for_cpu(struct device *dev,
-					dma_addr_t handle, size_t size,
-					enum dma_data_direction dir)
-{
-}
-
-static inline void dma_sync_single_for_device(struct device *dev,
-					dma_addr_t handle, size_t size,
-					enum dma_data_direction dir)
-{
-}
-#endif				/* _BLACKFIN_DMA_MAPPING_H */
+#ifndef _BLACKFIN_DMA_MAPPING_H
+#define _BLACKFIN_DMA_MAPPING_H
+
+static inline int
+dma_coherent_dev(struct device *dev)
+{
+	return 0;
+}
+
+static inline void
+dma_cache_sync(struct device *dev, void *cpu_addr, size_t size,
+	       enum dma_data_direction direction)
+{
+}
+
+extern void dma_alloc_init(unsigned long start, unsigned long end);
+
+#include <asm-generic/dma-mapping-linear.h>
+
+#endif				/* _BLACKFIN_DMA_MAPPING_H */
diff --git a/arch/cris/include/asm/dma-mapping.h b/arch/cris/include/asm/dma-mapping.h
dissimilarity index 91%
index da8ef8e..75c837e 100644
--- a/arch/cris/include/asm/dma-mapping.h
+++ b/arch/cris/include/asm/dma-mapping.h
@@ -1,170 +1,24 @@
-/* DMA mapping. Nothing tricky here, just virt_to_phys */
-
-#ifndef _ASM_CRIS_DMA_MAPPING_H
-#define _ASM_CRIS_DMA_MAPPING_H
-
-#include <linux/mm.h>
-#include <linux/kernel.h>
-
-#include <asm/cache.h>
-#include <asm/io.h>
-#include <asm/scatterlist.h>
-
-#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
-#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
-
-#ifdef CONFIG_PCI
-#include <asm-generic/dma-coherent.h>
-
-void *dma_alloc_coherent(struct device *dev, size_t size,
-			   dma_addr_t *dma_handle, gfp_t flag);
-
-void dma_free_coherent(struct device *dev, size_t size,
-			 void *vaddr, dma_addr_t dma_handle);
-#else
-static inline void *
-dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
-                   gfp_t flag)
-{
-        BUG();
-        return NULL;
-}
-
-static inline void
-dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
-                    dma_addr_t dma_handle)
-{
-        BUG();
-}
-#endif
-static inline dma_addr_t
-dma_map_single(struct device *dev, void *ptr, size_t size,
-	       enum dma_data_direction direction)
-{
-	BUG_ON(direction == DMA_NONE);
-	return virt_to_phys(ptr);
-}
-
-static inline void
-dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-		 enum dma_data_direction direction)
-{
-	BUG_ON(direction == DMA_NONE);
-}
-
-static inline int
-dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-	   enum dma_data_direction direction)
-{
-	printk("Map sg\n");
-	return nents;
-}
-
-static inline dma_addr_t
-dma_map_page(struct device *dev, struct page *page, unsigned long offset,
-	     size_t size, enum dma_data_direction direction)
-{
-	BUG_ON(direction == DMA_NONE);
-	return page_to_phys(page) + offset;
-}
-
-static inline void
-dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-	       enum dma_data_direction direction)
-{
-	BUG_ON(direction == DMA_NONE);
-}
-
-
-static inline void
-dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-	     enum dma_data_direction direction)
-{
-	BUG_ON(direction == DMA_NONE);
-}
-
-static inline void
-dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
-			enum dma_data_direction direction)
-{
-}
-
-static inline void
-dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
-			enum dma_data_direction direction)
-{
-}
-
-static inline void
-dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
-			      unsigned long offset, size_t size,
-			      enum dma_data_direction direction)
-{
-}
-
-static inline void
-dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
-				 unsigned long offset, size_t size,
-				 enum dma_data_direction direction)
-{
-}
-
-static inline void
-dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
-		    enum dma_data_direction direction)
-{
-}
-
-static inline void
-dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
-		    enum dma_data_direction direction)
-{
-}
-
-static inline int
-dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-{
-	return 0;
-}
-
-static inline int
-dma_supported(struct device *dev, u64 mask)
-{
-        /*
-         * we fall back to GFP_DMA when the mask isn't all 1s,
-         * so we can't guarantee allocations that must be
-         * within a tighter range than GFP_DMA..
-         */
-        if(mask < 0x00ffffff)
-                return 0;
-
-	return 1;
-}
-
-static inline int
-dma_set_mask(struct device *dev, u64 mask)
-{
-	if(!dev->dma_mask || !dma_supported(dev, mask))
-		return -EIO;
-
-	*dev->dma_mask = mask;
-
-	return 0;
-}
-
-static inline int
-dma_get_cache_alignment(void)
-{
-	return (1 << INTERNODE_CACHE_SHIFT);
-}
-
-#define dma_is_consistent(d, h)	(1)
-
-static inline void
-dma_cache_sync(struct device *dev, void *vaddr, size_t size,
-	       enum dma_data_direction direction)
-{
-}
-
-
-#endif
+#ifndef _ASM_CRIS_DMA_MAPPING_H
+#define _ASM_CRIS_DMA_MAPPING_H
+
+#include <linux/mm.h>
+#include <linux/kernel.h>
+
+#include <asm/cache.h>
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+#include <asm-generic/dma-mapping-linear.h>
+
+#ifdef CONFIG_PCI
+#include <asm-generic/dma-coherent.h>
+#endif
+
+static inline int
+cris_dma_get_cache_alignment(void)
+{
+	return (1 << INTERNODE_CACHE_SHIFT);
+}
+
+#define dma_get_cache_alignment cris_dma_get_cache_alignment
+
+#endif
diff --git a/arch/mn10300/include/asm/dma-mapping.h b/arch/mn10300/include/asm/dma-mapping.h
dissimilarity index 90%
index ccae8f6..d888fd1 100644
--- a/arch/mn10300/include/asm/dma-mapping.h
+++ b/arch/mn10300/include/asm/dma-mapping.h
@@ -1,234 +1,32 @@
-/* DMA mapping routines for the MN10300 arch
- *
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
-#ifndef _ASM_DMA_MAPPING_H
-#define _ASM_DMA_MAPPING_H
-
-#include <linux/mm.h>
-#include <linux/scatterlist.h>
-
-#include <asm/cache.h>
-#include <asm/io.h>
-
-extern void *dma_alloc_coherent(struct device *dev, size_t size,
-				dma_addr_t *dma_handle, int flag);
-
-extern void dma_free_coherent(struct device *dev, size_t size,
-			      void *vaddr, dma_addr_t dma_handle);
-
-#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent((d), (s), (h), (f))
-#define dma_free_noncoherent(d, s, v, h)  dma_free_coherent((d), (s), (v), (h))
-
-/*
- * Map a single buffer of the indicated size for DMA in streaming mode.  The
- * 32-bit bus address to use is returned.
- *
- * Once the device is given the dma address, the device owns this memory until
- * either pci_unmap_single or pci_dma_sync_single is performed.
- */
-static inline
-dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
-			  enum dma_data_direction direction)
-{
-	BUG_ON(direction == DMA_NONE);
-	mn10300_dcache_flush_inv();
-	return virt_to_bus(ptr);
-}
-
-/*
- * Unmap a single streaming mode DMA translation.  The dma_addr and size must
- * match what was provided for in a previous pci_map_single call.  All other
- * usages are undefined.
- *
- * After this call, reads by the cpu to the buffer are guarenteed to see
- * whatever the device wrote there.
- */
-static inline
-void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-		      enum dma_data_direction direction)
-{
-	BUG_ON(direction == DMA_NONE);
-}
-
-/*
- * Map a set of buffers described by scatterlist in streaming mode for DMA.
- * This is the scather-gather version of the above pci_map_single interface.
- * Here the scatter gather list elements are each tagged with the appropriate
- * dma address and length.  They are obtained via sg_dma_{address,length}(SG).
- *
- * NOTE: An implementation may be able to use a smaller number of DMA
- *       address/length pairs than there are SG table elements.  (for example
- *       via virtual mapping capabilities) The routine returns the number of
- *       addr/length pairs actually used, at most nents.
- *
- * Device ownership issues as mentioned above for pci_map_single are the same
- * here.
- */
-static inline
-int dma_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
-	       enum dma_data_direction direction)
-{
-	struct scatterlist *sg;
-	int i;
-
-	BUG_ON(!valid_dma_direction(direction));
-	WARN_ON(nents == 0 || sglist[0].length == 0);
-
-	for_each_sg(sglist, sg, nents, i) {
-		BUG_ON(!sg_page(sg));
-
-		sg->dma_address = sg_phys(sg);
-	}
-
-	mn10300_dcache_flush_inv();
-	return nents;
-}
-
-/*
- * Unmap a set of streaming mode DMA translations.
- * Again, cpu read rules concerning calls here are the same as for
- * pci_unmap_single() above.
- */
-static inline
-void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-		  enum dma_data_direction direction)
-{
-	BUG_ON(!valid_dma_direction(direction));
-}
-
-/*
- * pci_{map,unmap}_single_page maps a kernel page to a dma_addr_t. identical
- * to pci_map_single, but takes a struct page instead of a virtual address
- */
-static inline
-dma_addr_t dma_map_page(struct device *dev, struct page *page,
-			unsigned long offset, size_t size,
-			enum dma_data_direction direction)
-{
-	BUG_ON(direction == DMA_NONE);
-	return page_to_bus(page) + offset;
-}
-
-static inline
-void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-		    enum dma_data_direction direction)
-{
-	BUG_ON(direction == DMA_NONE);
-}
-
-/*
- * Make physical memory consistent for a single streaming mode DMA translation
- * after a transfer.
- *
- * If you perform a pci_map_single() but wish to interrogate the buffer using
- * the cpu, yet do not wish to teardown the PCI dma mapping, you must call this
- * function before doing so.  At the next point you give the PCI dma address
- * back to the card, the device again owns the buffer.
- */
-static inline
-void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
-			     size_t size, enum dma_data_direction direction)
-{
-}
-
-static inline
-void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
-				size_t size, enum dma_data_direction direction)
-{
-	mn10300_dcache_flush_inv();
-}
-
-static inline
-void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
-				   unsigned long offset, size_t size,
-				   enum dma_data_direction direction)
-{
-}
-
-static inline void
-dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
-				 unsigned long offset, size_t size,
-				 enum dma_data_direction direction)
-{
-	mn10300_dcache_flush_inv();
-}
-
-
-/*
- * Make physical memory consistent for a set of streaming mode DMA translations
- * after a transfer.
- *
- * The same as pci_dma_sync_single but for a scatter-gather list, same rules
- * and usage.
- */
-static inline
-void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
-			 int nelems, enum dma_data_direction direction)
-{
-}
-
-static inline
-void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
-			    int nelems, enum dma_data_direction direction)
-{
-	mn10300_dcache_flush_inv();
-}
-
-static inline
-int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-{
-	return 0;
-}
-
-/*
- * Return whether the given PCI device DMA address mask can be supported
- * properly.  For example, if your device can only drive the low 24-bits during
- * PCI bus mastering, then you would pass 0x00ffffff as the mask to this
- * function.
- */
-static inline
-int dma_supported(struct device *dev, u64 mask)
-{
-	/*
-	 * we fall back to GFP_DMA when the mask isn't all 1s, so we can't
-	 * guarantee allocations that must be within a tighter range than
-	 * GFP_DMA
-	 */
-	if (mask < 0x00ffffff)
-		return 0;
-	return 1;
-}
-
-static inline
-int dma_set_mask(struct device *dev, u64 mask)
-{
-	if (!dev->dma_mask || !dma_supported(dev, mask))
-		return -EIO;
-
-	*dev->dma_mask = mask;
-	return 0;
-}
-
-static inline
-int dma_get_cache_alignment(void)
-{
-	return 1 << L1_CACHE_SHIFT;
-}
-
-#define dma_is_consistent(d)	(1)
-
-static inline
-void dma_cache_sync(void *vaddr, size_t size,
-		    enum dma_data_direction direction)
-{
-	mn10300_dcache_flush_inv();
-}
-
-#endif
+/* DMA mapping routines for the MN10300 arch
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#ifndef _ASM_DMA_MAPPING_H
+#define _ASM_DMA_MAPPING_H
+
+#include <linux/mm.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+static inline int
+dma_coherent_dev(struct device *dev)
+{
+	return 0;
+}
+
+static inline void
+dma_cache_sync(struct device *dev, void *cpu_addr, size_t size,
+	       enum dma_data_direction direction)
+{
+	mn10300_dcache_flush_inv();
+}
+
+#include <asm-generic/dma-mapping-linear.h>
+
+#endif
diff --git a/arch/sh/include/asm/dma-mapping.h b/arch/sh/include/asm/dma-mapping.h
dissimilarity index 87%
index ea9d4f4..6b0361c 100644
--- a/arch/sh/include/asm/dma-mapping.h
+++ b/arch/sh/include/asm/dma-mapping.h
@@ -1,219 +1,39 @@
-#ifndef __ASM_SH_DMA_MAPPING_H
-#define __ASM_SH_DMA_MAPPING_H
-
-#include <linux/mm.h>
-#include <linux/scatterlist.h>
-#include <linux/dma-debug.h>
-#include <asm/cacheflush.h>
-#include <asm/io.h>
-#include <asm-generic/dma-coherent.h>
-
-extern struct bus_type pci_bus_type;
-
-#define dma_supported(dev, mask)	(1)
-
-static inline int dma_set_mask(struct device *dev, u64 mask)
-{
-	if (!dev->dma_mask || !dma_supported(dev, mask))
-		return -EIO;
-
-	*dev->dma_mask = mask;
-
-	return 0;
-}
-
-void *dma_alloc_coherent(struct device *dev, size_t size,
-			 dma_addr_t *dma_handle, gfp_t flag);
-
-void dma_free_coherent(struct device *dev, size_t size,
-		       void *vaddr, dma_addr_t dma_handle);
-
-void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
-		    enum dma_data_direction dir);
-
-#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
-#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
-#define dma_is_consistent(d, h) (1)
-
-static inline dma_addr_t dma_map_single(struct device *dev,
-					void *ptr, size_t size,
-					enum dma_data_direction dir)
-{
-	dma_addr_t addr = virt_to_phys(ptr);
-
-#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
-	if (dev->bus == &pci_bus_type)
-		return addr;
-#endif
-	dma_cache_sync(dev, ptr, size, dir);
-
-	debug_dma_map_page(dev, virt_to_page(ptr),
-			   (unsigned long)ptr & ~PAGE_MASK, size,
-			   dir, addr, true);
-
-	return addr;
-}
-
-static inline void dma_unmap_single(struct device *dev, dma_addr_t addr,
-				    size_t size, enum dma_data_direction dir)
-{
-	debug_dma_unmap_page(dev, addr, size, dir, true);
-}
-
-static inline int dma_map_sg(struct device *dev, struct scatterlist *sg,
-			     int nents, enum dma_data_direction dir)
-{
-	int i;
-
-	for (i = 0; i < nents; i++) {
-#if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
-		dma_cache_sync(dev, sg_virt(&sg[i]), sg[i].length, dir);
-#endif
-		sg[i].dma_address = sg_phys(&sg[i]);
-		sg[i].dma_length = sg[i].length;
-	}
-
-	debug_dma_map_sg(dev, sg, nents, i, dir);
-
-	return nents;
-}
-
-static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
-				int nents, enum dma_data_direction dir)
-{
-	debug_dma_unmap_sg(dev, sg, nents, dir);
-}
-
-static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
-				      unsigned long offset, size_t size,
-				      enum dma_data_direction dir)
-{
-	return dma_map_single(dev, page_address(page) + offset, size, dir);
-}
-
-static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
-				  size_t size, enum dma_data_direction dir)
-{
-	dma_unmap_single(dev, dma_address, size, dir);
-}
-
-static inline void dma_sync_single(struct device *dev, dma_addr_t dma_handle,
-				   size_t size, enum dma_data_direction dir)
-{
-#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
-	if (dev->bus == &pci_bus_type)
-		return;
-#endif
-	dma_cache_sync(dev, phys_to_virt(dma_handle), size, dir);
-}
-
-static inline void dma_sync_single_range(struct device *dev,
-					 dma_addr_t dma_handle,
-					 unsigned long offset, size_t size,
-					 enum dma_data_direction dir)
-{
-#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
-	if (dev->bus == &pci_bus_type)
-		return;
-#endif
-	dma_cache_sync(dev, phys_to_virt(dma_handle) + offset, size, dir);
-}
-
-static inline void dma_sync_sg(struct device *dev, struct scatterlist *sg,
-			       int nelems, enum dma_data_direction dir)
-{
-	int i;
-
-	for (i = 0; i < nelems; i++) {
-#if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
-		dma_cache_sync(dev, sg_virt(&sg[i]), sg[i].length, dir);
-#endif
-		sg[i].dma_address = sg_phys(&sg[i]);
-		sg[i].dma_length = sg[i].length;
-	}
-}
-
-static inline void dma_sync_single_for_cpu(struct device *dev,
-					   dma_addr_t dma_handle, size_t size,
-					   enum dma_data_direction dir)
-{
-	dma_sync_single(dev, dma_handle, size, dir);
-	debug_dma_sync_single_for_cpu(dev, dma_handle, size, dir);
-}
-
-static inline void dma_sync_single_for_device(struct device *dev,
-					      dma_addr_t dma_handle,
-					      size_t size,
-					      enum dma_data_direction dir)
-{
-	dma_sync_single(dev, dma_handle, size, dir);
-	debug_dma_sync_single_for_device(dev, dma_handle, size, dir);
-}
-
-static inline void dma_sync_single_range_for_cpu(struct device *dev,
-						 dma_addr_t dma_handle,
-						 unsigned long offset,
-						 size_t size,
-						 enum dma_data_direction direction)
-{
-	dma_sync_single_for_cpu(dev, dma_handle+offset, size, direction);
-	debug_dma_sync_single_range_for_cpu(dev, dma_handle,
-					    offset, size, direction);
-}
-
-static inline void dma_sync_single_range_for_device(struct device *dev,
-						    dma_addr_t dma_handle,
-						    unsigned long offset,
-						    size_t size,
-						    enum dma_data_direction direction)
-{
-	dma_sync_single_for_device(dev, dma_handle+offset, size, direction);
-	debug_dma_sync_single_range_for_device(dev, dma_handle,
-					       offset, size, direction);
-}
-
-
-static inline void dma_sync_sg_for_cpu(struct device *dev,
-				       struct scatterlist *sg, int nelems,
-				       enum dma_data_direction dir)
-{
-	dma_sync_sg(dev, sg, nelems, dir);
-	debug_dma_sync_sg_for_cpu(dev, sg, nelems, dir);
-}
-
-static inline void dma_sync_sg_for_device(struct device *dev,
-					  struct scatterlist *sg, int nelems,
-					  enum dma_data_direction dir)
-{
-	dma_sync_sg(dev, sg, nelems, dir);
-	debug_dma_sync_sg_for_device(dev, sg, nelems, dir);
-}
-
-static inline int dma_get_cache_alignment(void)
-{
-	/*
-	 * Each processor family will define its own L1_CACHE_SHIFT,
-	 * L1_CACHE_BYTES wraps to this, so this is always safe.
-	 */
-	return L1_CACHE_BYTES;
-}
-
-static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-{
-	return dma_addr == 0;
-}
-
-#define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY
-
-extern int
-dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
-			    dma_addr_t device_addr, size_t size, int flags);
-
-extern void
-dma_release_declared_memory(struct device *dev);
-
-extern void *
-dma_mark_declared_memory_occupied(struct device *dev,
-				  dma_addr_t device_addr, size_t size);
-
-#endif /* __ASM_SH_DMA_MAPPING_H */
+#ifndef __ASM_SH_DMA_MAPPING_H
+#define __ASM_SH_DMA_MAPPING_H
+
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-debug.h>
+#include <asm/cacheflush.h>
+#include <asm/io.h>
+#include <asm-generic/dma-coherent.h>
+
+static inline int dma_coherent_dev(struct device *dev)
+{
+#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
+	if (dev->bus == &pci_bus_type)
+		return 1;
+#endif
+	return 0;
+}
+
+extern void
+dma_cache_sync(struct device *dev, void *cpu_addr, size_t size,
+	       enum dma_data_direction direction);
+
+#include <asm-generic/dma-mapping-linear.h>
+
+extern void
+dma_release_declared_memory(struct device *dev);
+
+extern void *
+dma_mark_declared_memory_occupied(struct device *dev,
+				  dma_addr_t device_addr, size_t size);
+
+#define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY
+
+extern int
+dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
+			    dma_addr_t device_addr, size_t size, int flags);
+
+#endif /* __ASM_SH_DMA_MAPPING_H */
diff --git a/arch/xtensa/include/asm/dma-mapping.h b/arch/xtensa/include/asm/dma-mapping.h
dissimilarity index 82%
index 51882ae..4134617 100644
--- a/arch/xtensa/include/asm/dma-mapping.h
+++ b/arch/xtensa/include/asm/dma-mapping.h
@@ -1,179 +1,41 @@
-/*
- * include/asm-xtensa/dma-mapping.h
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2003 - 2005 Tensilica Inc.
- */
-
-#ifndef _XTENSA_DMA_MAPPING_H
-#define _XTENSA_DMA_MAPPING_H
-
-#include <asm/cache.h>
-#include <asm/io.h>
-#include <linux/mm.h>
-#include <linux/scatterlist.h>
-
-/*
- * DMA-consistent mapping functions.
- */
-
-extern void *consistent_alloc(int, size_t, dma_addr_t, unsigned long);
-extern void consistent_free(void*, size_t, dma_addr_t);
-extern void consistent_sync(void*, size_t, int);
-
-#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
-#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
-
-void *dma_alloc_coherent(struct device *dev, size_t size,
-			   dma_addr_t *dma_handle, gfp_t flag);
-
-void dma_free_coherent(struct device *dev, size_t size,
-			 void *vaddr, dma_addr_t dma_handle);
-
-static inline dma_addr_t
-dma_map_single(struct device *dev, void *ptr, size_t size,
-	       enum dma_data_direction direction)
-{
-	BUG_ON(direction == DMA_NONE);
-	consistent_sync(ptr, size, direction);
-	return virt_to_phys(ptr);
-}
-
-static inline void
-dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-		 enum dma_data_direction direction)
-{
-	BUG_ON(direction == DMA_NONE);
-}
-
-static inline int
-dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-	   enum dma_data_direction direction)
-{
-	int i;
-
-	BUG_ON(direction == DMA_NONE);
-
-	for (i = 0; i < nents; i++, sg++ ) {
-		BUG_ON(!sg_page(sg));
-
-		sg->dma_address = sg_phys(sg);
-		consistent_sync(sg_virt(sg), sg->length, direction);
-	}
-
-	return nents;
-}
-
-static inline dma_addr_t
-dma_map_page(struct device *dev, struct page *page, unsigned long offset,
-	     size_t size, enum dma_data_direction direction)
-{
-	BUG_ON(direction == DMA_NONE);
-	return (dma_addr_t)(page_to_pfn(page)) * PAGE_SIZE + offset;
-}
-
-static inline void
-dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-	       enum dma_data_direction direction)
-{
-	BUG_ON(direction == DMA_NONE);
-}
-
-
-static inline void
-dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-	     enum dma_data_direction direction)
-{
-	BUG_ON(direction == DMA_NONE);
-}
-
-static inline void
-dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
-		enum dma_data_direction direction)
-{
-	consistent_sync((void *)bus_to_virt(dma_handle), size, direction);
-}
-
-static inline void
-dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
-		enum dma_data_direction direction)
-{
-	consistent_sync((void *)bus_to_virt(dma_handle), size, direction);
-}
-
-static inline void
-dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
-		      unsigned long offset, size_t size,
-		      enum dma_data_direction direction)
-{
-
-	consistent_sync((void *)bus_to_virt(dma_handle)+offset,size,direction);
-}
-
-static inline void
-dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
-		      unsigned long offset, size_t size,
-		      enum dma_data_direction direction)
-{
-
-	consistent_sync((void *)bus_to_virt(dma_handle)+offset,size,direction);
-}
-static inline void
-dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
-		 enum dma_data_direction dir)
-{
-	int i;
-	for (i = 0; i < nelems; i++, sg++)
-		consistent_sync(sg_virt(sg), sg->length, dir);
-}
-
-static inline void
-dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
-		 enum dma_data_direction dir)
-{
-	int i;
-	for (i = 0; i < nelems; i++, sg++)
-		consistent_sync(sg_virt(sg), sg->length, dir);
-}
-static inline int
-dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-{
-	return 0;
-}
-
-static inline int
-dma_supported(struct device *dev, u64 mask)
-{
-	return 1;
-}
-
-static inline int
-dma_set_mask(struct device *dev, u64 mask)
-{
-	if(!dev->dma_mask || !dma_supported(dev, mask))
-		return -EIO;
-
-	*dev->dma_mask = mask;
-
-	return 0;
-}
-
-static inline int
-dma_get_cache_alignment(void)
-{
-	return L1_CACHE_BYTES;
-}
-
-#define dma_is_consistent(d, h)	(1)
-
-static inline void
-dma_cache_sync(struct device *dev, void *vaddr, size_t size,
-	       enum dma_data_direction direction)
-{
-	consistent_sync(vaddr, size, direction);
-}
-
-#endif	/* _XTENSA_DMA_MAPPING_H */
+/*
+ * include/asm-xtensa/dma-mapping.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_DMA_MAPPING_H
+#define _XTENSA_DMA_MAPPING_H
+
+#include <asm/cache.h>
+#include <asm/io.h>
+#include <linux/mm.h>
+
+/*
+ * DMA-consistent mapping functions.
+ */
+
+extern void *consistent_alloc(int, size_t, dma_addr_t, unsigned long);
+extern void consistent_free(void*, size_t, dma_addr_t);
+extern void consistent_sync(void*, size_t, int);
+
+static inline int
+dma_coherent_dev(struct device *dev)
+{
+	return 0;
+}
+
+static inline void
+dma_cache_sync(struct device *dev, void *cpu_addr, size_t size,
+	       enum dma_data_direction direction)
+{
+	consistent_sync(cpu_addr, size, direction);
+}
+
+#include <asm-generic/dma-mapping-linear.h>
+
+#endif	/* _XTENSA_DMA_MAPPING_H */


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

* Re: [PATCH] asm-generic: add a dma-mapping.h file
  2009-05-19 16:22                                         ` Arnd Bergmann
@ 2009-05-19 17:01                                           ` Grant Grundler
  2009-05-19 17:40                                             ` Arnd Bergmann
  2009-05-22 12:12                                           ` FUJITA Tomonori
  1 sibling, 1 reply; 39+ messages in thread
From: Grant Grundler @ 2009-05-19 17:01 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: FUJITA Tomonori, jgarzik, hancockrwd, htejun, alan, flar, schmitz,
	linux-kernel, linux-ide, takata, geert, linux-m68k, ysato

On Tue, May 19, 2009 at 9:22 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Tuesday 19 May 2009, FUJITA Tomonori wrote:
>> > Would you agree to a patch that works with the same
>> > code on e.g. arm, microblaze, mn10300 and sh and
>> > uses only a few #ifdefs?
>>
>> Having such helper for a linear mapping might be helpful but your
>> approach is wrong.
>
> Do you like this approach better? I've merged a few architectures
> that were relatively simple. This file should be usable by all
> architectures that have a linear mapping and are either fully coherent
> (like cris) or just require flushing the dcache when passing a
> buffer to the device.

I've reviewed the first bit and it looks fine (so far to me).
Two related bugs:
1) dma_alloc_coherent() is not respecting the coherent_dma_mask field
in device.h:struct device.
2) dma_map_single() is not respecting dma_mask in struct pci_dev (and
pointer from struct device).

...
> +/**
> + * dma_alloc_coherent - allocate consistent memory for DMA
> + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
> + * @size: required memory size
> + * @handle: bus-specific DMA address
> + *
> + * Allocate some uncached, unbuffered memory for a device for
> + * performing DMA.  This function allocates pages, and will
> + * return the CPU-viewed address, and sets @handle to be the
> + * device-viewed address.

Key here is the DMA is coherent, bi-directional, and the DMA address fit in
the coherent_dma_mask. "uncached/unbuffered" is one way of doing this and
is how we've implemented "DMA coherency" on parisc platforms that don't
have an IOMMU (which all have PA1.1 CPUs) - see arch/parisc/kernel/pci-dma.c

And I'll confess pci-dma.c doesn't implement support for coherent_dma_mask .
AFAIK, the targeted platforms have < 4GB of RAM and only PCI devices.
ISA support is completely missing and is the only case this class of machines
need coherent_dma_mask support.

More comments on how DMA works for PARISC in
arch/parisc/include/asm/dma-mapping.h

hth,
grant

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

* Re: [PATCH] asm-generic: add a dma-mapping.h file
  2009-05-19 17:01                                           ` Grant Grundler
@ 2009-05-19 17:40                                             ` Arnd Bergmann
  2009-05-19 18:08                                               ` Grant Grundler
  0 siblings, 1 reply; 39+ messages in thread
From: Arnd Bergmann @ 2009-05-19 17:40 UTC (permalink / raw)
  To: Grant Grundler
  Cc: FUJITA Tomonori, jgarzik, hancockrwd, htejun, alan, flar, schmitz,
	linux-kernel, linux-ide, takata, geert, linux-m68k, ysato

On Tuesday 19 May 2009 17:01:27 Grant Grundler wrote:
> On Tue, May 19, 2009 at 9:22 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> I've reviewed the first bit and it looks fine (so far to me).
> Two related bugs:
> 1) dma_alloc_coherent() is not respecting the coherent_dma_mask field
> in device.h:struct device.

Hmm, I've taken that function unchanged from powerpc. I guess that means
that powerpc is broken  here as well, right?

> 2) dma_map_single() is not respecting dma_mask in struct pci_dev (and
> pointer from struct device).

What should it do with the mask? All the architectures I've looked
at as well as arch/parisc/kernel/pci-dma.c ignore it.
Should dma_map_* just fail in case of an address exceeding dma_mask?

> > +/**
> > + * dma_alloc_coherent - allocate consistent memory for DMA
> > + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
> > + * @size: required memory size
> > + * @handle: bus-specific DMA address
> > + *
> > + * Allocate some uncached, unbuffered memory for a device for
> > + * performing DMA.  This function allocates pages, and will
> > + * return the CPU-viewed address, and sets @handle to be the
> > + * device-viewed address.
> 
> Key here is the DMA is coherent, bi-directional, and the DMA address fit in
> the coherent_dma_mask. "uncached/unbuffered" is one way of doing this and
> is how we've implemented "DMA coherency" on parisc platforms that don't
> have an IOMMU (which all have PA1.1 CPUs) - see arch/parisc/kernel/pci-dma.c

All the architectures I've looked at come with their own version of _alloc_coherent
that works in similar ways to allocate an uncached mapping. Now that you
mention this, I realize that there is a bug on cris, which after my patch either
has two conflicting implementations of dma_{alloc,free}_coherent, or
is missing the dma_coherent_dev() function that is hidden inside of the
same #ifdef. The one in arch/cris/arch-v32/drivers/pci/dma.c does seem
to be correct though.

	Arnd <><

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

* Re: [PATCH] asm-generic: add a dma-mapping.h file
  2009-05-19 17:40                                             ` Arnd Bergmann
@ 2009-05-19 18:08                                               ` Grant Grundler
  0 siblings, 0 replies; 39+ messages in thread
From: Grant Grundler @ 2009-05-19 18:08 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: FUJITA Tomonori, jgarzik, hancockrwd, htejun, alan, flar, schmitz,
	linux-kernel, linux-ide, takata, geert, linux-m68k, ysato

On Tue, May 19, 2009 at 10:40 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Tuesday 19 May 2009 17:01:27 Grant Grundler wrote:
>> On Tue, May 19, 2009 at 9:22 AM, Arnd Bergmann <arnd@arndb.de> wrote:
>> I've reviewed the first bit and it looks fine (so far to me).
>> Two related bugs:
>> 1) dma_alloc_coherent() is not respecting the coherent_dma_mask field
>> in device.h:struct device.
>
> Hmm, I've taken that function unchanged from powerpc. I guess that means
> that powerpc is broken  here as well, right?

Not necessarily. It might work fine for the subset of machines that
use that code.
But generic code should use the masks - even if they are set to ~0UL.

>> 2) dma_map_single() is not respecting dma_mask in struct pci_dev (and
>> pointer from struct device).
>
> What should it do with the mask?

Verify or enforce that the physical memory is allocated from a memory
pool suitable for
use by that device. If any bits "stick out" from the address (vs the
mask), the device
won't be able to DMA to that address and very likely truncate the address.

By default the PCI dma_mask is 32-bits. Drivers that can support more
than 32-bits
(some PCI, most PCI-X and all PCI-E devices) will be calling pci_set_dma_mask()
and pci_set_coherent_dma_mask() or the equivalent DMA API call.


> All the architectures I've looked
> at as well as arch/parisc/kernel/pci-dma.c ignore it.

pci-dma.c ignores it for the same reason it ignores coherent_dma_mask.
None of those parisc machines have host memory at a physical address that is NOT
reachable via DMA by *all* known/supported devices.

Maybe it's ok and we just need a comment stating the constraints of
the generic code.

And there must be some way (e.g. dma_support()) to verify the highest physical
memory location is reachable by the given device. So that would be another way
to enforce the mask.

> Should dma_map_* just fail in case of an address exceeding dma_mask?

That would probably be correct behavior too. But my gut feeling is we don't want
the device driver module to load unless we know the device can DMA to
any possible host memory location handed to dma_map_single().
My preference is the initialization path fail first. dma_alloc_coherent()
is generally in the initialization path after the drivers call pci_set*mask().


>
>> > +/**
>> > + * dma_alloc_coherent - allocate consistent memory for DMA
>> > + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
>> > + * @size: required memory size
>> > + * @handle: bus-specific DMA address
>> > + *
>> > + * Allocate some uncached, unbuffered memory for a device for
>> > + * performing DMA.  This function allocates pages, and will
>> > + * return the CPU-viewed address, and sets @handle to be the
>> > + * device-viewed address.
>>
>> Key here is the DMA is coherent, bi-directional, and the DMA address fit in
>> the coherent_dma_mask. "uncached/unbuffered" is one way of doing this and
>> is how we've implemented "DMA coherency" on parisc platforms that don't
>> have an IOMMU (which all have PA1.1 CPUs) - see arch/parisc/kernel/pci-dma.c
>
> All the architectures I've looked at come with their own version of _alloc_coherent
> that works in similar ways to allocate an uncached mapping.

That's what I expected. I'm pretty sure parisc could use a generic
implementation
for PA7100LC and PA7300LC CPUs (other parisc CPUs/memory controllers don't
support uncached mappings to host memory). So we would need run-time detection
and set dma_ops appropriately.

> Now that you
> mention this, I realize that there is a bug on cris, which after my patch either
> has two conflicting implementations of dma_{alloc,free}_coherent, or
> is missing the dma_coherent_dev() function that is hidden inside of the
> same #ifdef. The one in arch/cris/arch-v32/drivers/pci/dma.c does seem
> to be correct though.

Ok - cool!

thanks,
grant
--
To unsubscribe from this list: send the line "unsubscribe linux-m68k" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH] asm-generic: add a dma-mapping.h file
  2009-05-19 16:22                                         ` Arnd Bergmann
  2009-05-19 17:01                                           ` Grant Grundler
@ 2009-05-22 12:12                                           ` FUJITA Tomonori
  2009-05-22 14:07                                             ` Arnd Bergmann
  1 sibling, 1 reply; 39+ messages in thread
From: FUJITA Tomonori @ 2009-05-22 12:12 UTC (permalink / raw)
  To: arnd
  Cc: fujita.tomonori, jgarzik, hancockrwd, htejun, alan, flar, schmitz,
	linux-kernel, linux-ide, takata, geert, linux-m68k, ysato

On Tue, 19 May 2009 18:22:47 +0200
Arnd Bergmann <arnd@arndb.de> wrote:

> On Tuesday 19 May 2009, FUJITA Tomonori wrote:
> > > Would you agree to a patch that works with the same
> > > code on e.g. arm, microblaze, mn10300 and sh and
> > > uses only a few #ifdefs?
> > 
> > Having such helper for a linear mapping might be helpful but your
> > approach is wrong.
> 
> Do you like this approach better? I've merged a few architectures
> that were relatively simple. This file should be usable by all
> architectures that have a linear mapping and are either fully coherent
> (like cris) or just require flushing the dcache when passing a
> buffer to the device.
> 
> It's become pretty obvious where some of my bugs were in the previous
> code, I hopefully did better this time and maybe you find the rest.
> I've also added the dma debugging stuff in here and fixed a number
> of bugs in all the different architectures on the way, but I can
> send separate patches for those before doing the merge.
> 
> I've also tried merging frv and m68k, but they have some peculiarities
> that made it slightly harder.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> 
>  include/asm-generic/dma-mapping-linear.h |  391 +++++++++++++++++++++++++++++
>  arch/avr32/include/asm/dma-mapping.h     |  408 ++++---------------------------
>  arch/blackfin/include/asm/dma-mapping.h  |  118 +-------
>  arch/cris/include/asm/dma-mapping.h      |  194 +-------------
>  arch/mn10300/include/asm/dma-mapping.h   |  266 ++------------------
>  arch/sh/include/asm/dma-mapping.h        |  258 ++-----------------
>  arch/xtensa/include/asm/dma-mapping.h    |  220 +++-------------
>  7 files changed, 606 insertions(+), 1249 deletions(-)
> 
> diff --git a/include/asm-generic/dma-mapping-linear.h b/include/asm-generic/dma-mapping-linear.h
> new file mode 100644
> index 0000000..13f37db
> --- /dev/null
> +++ b/include/asm-generic/dma-mapping-linear.h
> @@ -0,0 +1,391 @@
> +#ifndef __ASM_GENERIC_DMA_MAPPING_H
> +#define __ASM_GENERIC_DMA_MAPPING_H
> +
> +#include <linux/mm.h>
> +#include <linux/device.h>
> +#include <linux/dma-debug.h>
> +#include <linux/scatterlist.h>
> +#include <asm/cacheflush.h>
> +#include <asm/io.h>
> +
> +#ifdef CONFIG_DMA_COHERENT
> +/*
> + * An architecture should override these if it needs to
> + * perform cache flushes before passing bus addresses
> + * to a device.
> + * It can either do a full flush in dma_coherent_dev
> + * and return 1 from there, or implement more specific
> + * synchronization in dma_cache_sync, which will be
> + * applied separately to each sg element.
> + */
> +static inline int
> +dma_coherent_dev(struct device *dev)
> +{
> +	return 1;
> +}
> +
> +static inline void
> +dma_cache_sync(struct device *dev, void *cpu_addr, size_t size,
> +	       enum dma_data_direction direction)
> +{
> +}
> +
> +/**
> + * dma_alloc_coherent - allocate consistent memory for DMA
> + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
> + * @size: required memory size
> + * @handle: bus-specific DMA address
> + *
> + * Allocate some uncached, unbuffered memory for a device for
> + * performing DMA.  This function allocates pages, and will
> + * return the CPU-viewed address, and sets @handle to be the
> + * device-viewed address.
> + */
> +void *dma_alloc_coherent(struct device *dev, size_t size,
> +				dma_addr_t *dma_handle, gfp_t flag)
> +{
> +	void *ret;
> +	struct page *page;
> +	int node = dev_to_node(dev);
> +
> +	/* ignore region specifiers */
> +	flag  &= ~(__GFP_HIGHMEM);
> +
> +	page = alloc_pages_node(node, flag, get_order(size));
> +	if (page == NULL)
> +		return NULL;
> +	ret = page_address(page);
> +	memset(ret, 0, size);
> +	*dma_handle = virt_to_abs(ret) + get_dma_direct_offset(dev);
> +
> +	return ret;
> +}

I don't think that this works for all architectures because a returned
buffer of alloc_pages_node might not be DMA-capable. Needs to use the
coherent_dma_mask here. See x86's dma_alloc_coherent and Alpha's
pci-noop.c (there might be other examples).

I think that having a generic header for simple mapping functions
(dma_map_single, dma_map_page, dma_map_sg, etc) would be useful but
I'm not sure if we can't have a generic version of
dma_alloc_coherent. There are lots of architectures that do
architecture-specific things. For example, you replaced avr32
dma-mapping.h except for dma_alloc_coherent, which seems to be can't
be generic.

BTW, it looks odd to add dma_debug to dma_map_single, etc but not
dma_alloc_coherent. ;)


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

* Re: [PATCH] asm-generic: add a dma-mapping.h file
  2009-05-22 12:12                                           ` FUJITA Tomonori
@ 2009-05-22 14:07                                             ` Arnd Bergmann
  2009-05-22 14:38                                               ` FUJITA Tomonori
  0 siblings, 1 reply; 39+ messages in thread
From: Arnd Bergmann @ 2009-05-22 14:07 UTC (permalink / raw)
  To: FUJITA Tomonori
  Cc: jgarzik, hancockrwd, htejun, alan, flar, schmitz, linux-kernel,
	linux-ide, takata, geert, linux-m68k, ysato, Grant Grundler

On Friday 22 May 2009, FUJITA Tomonori wrote:
> I don't think that this works for all architectures because a returned
> buffer of alloc_pages_node might not be DMA-capable. Needs to use the
> coherent_dma_mask here. See x86's dma_alloc_coherent and Alpha's
> pci-noop.c (there might be other examples).

Right, Grant also made the same comment.

> I think that having a generic header for simple mapping functions
> (dma_map_single, dma_map_page, dma_map_sg, etc) would be useful but
> I'm not sure if we can't have a generic version of
> dma_alloc_coherent.
>
> There are lots of architectures that do 
> architecture-specific things. For example, you replaced avr32
> dma-mapping.h except for dma_alloc_coherent, which seems to be can't
> be generic.

I agree that it won't be fully generic, because all architectures
with non-coherent DMA will have to do architecture specific setup
to get uncached mappings here. I believe that it can be generic
enough to support all architectures that have a cache-coherent PCI
bus, hence the #ifdef CONFIG_DMA_COHERENT around this function.

E.g. cris could use a one-line redirect to
asm-generic/dma-mapping-linear.h if it did not have the
special dma_get_cache_alignment function. I still would
like to find a better way to handle this one than to
redefine the function.

> BTW, it looks odd to add dma_debug to dma_map_single, etc but not
> dma_alloc_coherent. ;)

hehe, sure. I copied the dma_debug stuff from sh, the comments
from avr32 and the dma_alloc_coherent implementation from powerpc,
so I missed this one.

Thanks for the review.

	Arnd <><

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

* Re: [PATCH] asm-generic: add a dma-mapping.h file
  2009-05-22 14:07                                             ` Arnd Bergmann
@ 2009-05-22 14:38                                               ` FUJITA Tomonori
  2009-05-22 15:05                                                 ` Arnd Bergmann
  0 siblings, 1 reply; 39+ messages in thread
From: FUJITA Tomonori @ 2009-05-22 14:38 UTC (permalink / raw)
  To: arnd
  Cc: fujita.tomonori, jgarzik, hancockrwd, htejun, alan, flar, schmitz,
	linux-kernel, linux-ide, takata, geert, linux-m68k, ysato,
	grundler

On Fri, 22 May 2009 16:07:32 +0200
Arnd Bergmann <arnd@arndb.de> wrote:

> On Friday 22 May 2009, FUJITA Tomonori wrote:
> > I don't think that this works for all architectures because a returned
> > buffer of alloc_pages_node might not be DMA-capable. Needs to use the
> > coherent_dma_mask here. See x86's dma_alloc_coherent and Alpha's
> > pci-noop.c (there might be other examples).
> 
> Right, Grant also made the same comment.
> 
> > I think that having a generic header for simple mapping functions
> > (dma_map_single, dma_map_page, dma_map_sg, etc) would be useful but
> > I'm not sure if we can't have a generic version of
> > dma_alloc_coherent.
> >
> > There are lots of architectures that do 
> > architecture-specific things. For example, you replaced avr32
> > dma-mapping.h except for dma_alloc_coherent, which seems to be can't
> > be generic.
> 
> I agree that it won't be fully generic, because all architectures
> with non-coherent DMA will have to do architecture specific setup
> to get uncached mappings here. I believe that it can be generic
> enough to support all architectures that have a cache-coherent PCI
> bus, hence the #ifdef CONFIG_DMA_COHERENT around this function.

I'm not sure. And only mips internally uses CONFIG_DMA_COHERENT.

The reason why many architectures need architecture-specific
alloc_coherent() is not about coherent or not.


I like a new helper header file having only generic functions without
any ifdef.


> E.g. cris could use a one-line redirect to
> asm-generic/dma-mapping-linear.h if it did not have the
> special dma_get_cache_alignment function. I still would
> like to find a better way to handle this one than to
> redefine the function.
> 
> > BTW, it looks odd to add dma_debug to dma_map_single, etc but not
> > dma_alloc_coherent. ;)
> 
> hehe, sure. I copied the dma_debug stuff from sh, the comments
> from avr32 and the dma_alloc_coherent implementation from powerpc,
> so I missed this one.
> 
> Thanks for the review.
> 
> 	Arnd <><
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

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

* Re: [PATCH] asm-generic: add a dma-mapping.h file
  2009-05-22 14:38                                               ` FUJITA Tomonori
@ 2009-05-22 15:05                                                 ` Arnd Bergmann
  2009-05-26  4:36                                                   ` FUJITA Tomonori
  0 siblings, 1 reply; 39+ messages in thread
From: Arnd Bergmann @ 2009-05-22 15:05 UTC (permalink / raw)
  To: FUJITA Tomonori
  Cc: jgarzik, hancockrwd, htejun, alan, flar, schmitz, linux-kernel,
	linux-ide, takata, geert, linux-m68k, ysato, grundler

On Friday 22 May 2009, FUJITA Tomonori wrote:
> I'm not sure. And only mips internally uses CONFIG_DMA_COHERENT.
> 
> The reason why many architectures need architecture-specific
> alloc_coherent() is not about coherent or not.
> 
> I like a new helper header file having only generic functions without
> any ifdef.

Ok, fair enough. Fixing dma_alloc_coherent to handle
coherent_dma_mask and debug_dma correctly would also
make it even bigger, and it was already doing more than
you'd want from a commonly used inline function.
It may be useful to put it into kernel/dma-coherent.c
under an #ifdef, but I'll leave this one alone for now.

I'll leave dma_alloc_coherent and dma_free_coherent
as extern declarations then, and leave out the
simple dma_coherent_dev() and dma_cache_sync() that
all architectures would need to override.

dma_get_cache_alignment() is still less generic than
the other functions, as this is still architecture
specific. Should I leave that out as well then?

One more idea I had was to rename all the functions in
this file from dma_* to dma_linear_*. This would mean
that all architectures using it would still need to
do something like #define dma_map_sg dma_linear_map_sg
for each function they want to use but can easily chose
to provide their own ones for those they need different.

It might also help architectures that work with dma_ops,
which could then define their own
struct dma_ops dma_ops_linear = {
	.map_single = dma_linear_map_single,
	.map_sg = dma_linear_map_sg,
	...
};

Would you prefer me to do it this way, or just keep the
standard function names as in the current patch?

	Arnd <><

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

* Re: [PATCH] asm-generic: add a dma-mapping.h file
  2009-05-22 15:05                                                 ` Arnd Bergmann
@ 2009-05-26  4:36                                                   ` FUJITA Tomonori
  0 siblings, 0 replies; 39+ messages in thread
From: FUJITA Tomonori @ 2009-05-26  4:36 UTC (permalink / raw)
  To: arnd
  Cc: fujita.tomonori, jgarzik, hancockrwd, htejun, alan, flar, schmitz,
	linux-kernel, linux-ide, takata, geert, linux-m68k, ysato,
	grundler

On Fri, 22 May 2009 17:05:53 +0200
Arnd Bergmann <arnd@arndb.de> wrote:

> On Friday 22 May 2009, FUJITA Tomonori wrote:
> > I'm not sure. And only mips internally uses CONFIG_DMA_COHERENT.
> > 
> > The reason why many architectures need architecture-specific
> > alloc_coherent() is not about coherent or not.
> > 
> > I like a new helper header file having only generic functions without
> > any ifdef.
> 
> Ok, fair enough. Fixing dma_alloc_coherent to handle
> coherent_dma_mask and debug_dma correctly would also
> make it even bigger, and it was already doing more than
> you'd want from a commonly used inline function.
> It may be useful to put it into kernel/dma-coherent.c
> under an #ifdef, but I'll leave this one alone for now.

Adding #ifdef into kernel/dma-coherent.c is ugly.


> I'll leave dma_alloc_coherent and dma_free_coherent
> as extern declarations then, and leave out the
> simple dma_coherent_dev() and dma_cache_sync() that
> all architectures would need to override.

Right, needs to leave the functions that architectures need to
override.


> dma_get_cache_alignment() is still less generic than
> the other functions, as this is still architecture
> specific. Should I leave that out as well then?

Yes, I think that only adding generic functions is a better
approach. Overriding with #ifdef is really ugly.


> One more idea I had was to rename all the functions in
> this file from dma_* to dma_linear_*. This would mean
> that all architectures using it would still need to
> do something like #define dma_map_sg dma_linear_map_sg
> for each function they want to use but can easily chose
> to provide their own ones for those they need different.
> 
> It might also help architectures that work with dma_ops,
> which could then define their own
> struct dma_ops dma_ops_linear = {
> 	.map_single = dma_linear_map_single,
> 	.map_sg = dma_linear_map_sg,
> 	...
> };

To me, looks like this just makes things complicated needlessly. But
I'm not in a position to ACK or NACK this. it's better to ask
architecture maintainers.


> Would you prefer me to do it this way, or just keep the
> standard function names as in the current patch?

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

end of thread, other threads:[~2009-05-26  4:36 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20090511222702.352192505@arndb.de>
2009-05-11 22:38 ` [PATCH] ata: libata depends on HAS_DMA Arnd Bergmann
2009-05-12  0:58   ` Jeff Garzik
2009-05-12 12:40     ` Arnd Bergmann
2009-05-12 13:05       ` Arnd Bergmann
2009-05-12  8:06   ` Alan Cox
2009-05-12  9:23     ` Arnd Bergmann
2009-05-13  3:30       ` Brad Boyer
2009-05-13  4:12         ` Michael Schmitz
2009-05-13  4:34           ` Brad Boyer
2009-05-13  8:51             ` Alan Cox
2009-05-13  8:55               ` Geert Uytterhoeven
2009-05-13 23:57               ` Robert Hancock
2009-05-14  0:18                 ` FUJITA Tomonori
2009-05-15  5:31                   ` Tejun Heo
2009-05-15 11:16                     ` Arnd Bergmann
2009-05-15 11:21                       ` Tejun Heo
2009-05-15 11:55                         ` Arnd Bergmann
2009-05-17  9:00                           ` Robert Hancock
2009-05-17 19:38                             ` Arnd Bergmann
2009-05-17 20:05                               ` Jeff Garzik
2009-05-17 22:45                                 ` [PATCH] asm-generic: add a dma-mapping.h file Arnd Bergmann
2009-05-18  6:03                                   ` Geert Uytterhoeven
2009-05-18  8:28                                     ` Arnd Bergmann
2009-05-18 10:45                                   ` FUJITA Tomonori
2009-05-18 14:45                                     ` Arnd Bergmann
2009-05-18 22:44                                       ` FUJITA Tomonori
2009-05-19 16:22                                         ` Arnd Bergmann
2009-05-19 17:01                                           ` Grant Grundler
2009-05-19 17:40                                             ` Arnd Bergmann
2009-05-19 18:08                                               ` Grant Grundler
2009-05-22 12:12                                           ` FUJITA Tomonori
2009-05-22 14:07                                             ` Arnd Bergmann
2009-05-22 14:38                                               ` FUJITA Tomonori
2009-05-22 15:05                                                 ` Arnd Bergmann
2009-05-26  4:36                                                   ` FUJITA Tomonori
2009-05-18 22:54                                   ` Jeff Garzik
2009-05-18 23:22                                     ` FUJITA Tomonori
2009-05-18 10:45                       ` [PATCH] ata: libata depends on HAS_DMA FUJITA Tomonori
2009-05-13 10:39         ` Arnd Bergmann

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