diff mbox

[01/10] ARM: change ARM_DMA_ZONE_SIZE into a variable

Message ID 1309919442-20451-1-git-send-email-nicolas.pitre@linaro.org (mailing list archive)
State New, archived
Headers show

Commit Message

Nicolas Pitre July 6, 2011, 2:30 a.m. UTC
Having this value defined at compile time prevents multiple machines with
conflicting definitions to coexist.  Move it to a variable in preparation
for having a per machine value selected at run time.  This is relevant
only when CONFIG_ZONE_DMA is selected.

Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org>
---
 arch/arm/include/asm/dma.h    |    7 ++++---
 arch/arm/include/asm/memory.h |    7 +++++--
 arch/arm/mm/init.c            |   20 +++++++++++++-------
 3 files changed, 22 insertions(+), 12 deletions(-)

Comments

Barry Song July 6, 2011, 2:48 a.m. UTC | #1
2011/7/6 Nicolas Pitre <nicolas.pitre@linaro.org>:
> Having this value defined at compile time prevents multiple machines with
> conflicting definitions to coexist.  Move it to a variable in preparation
> for having a per machine value selected at run time.  This is relevant
> only when CONFIG_ZONE_DMA is selected.
>
> Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org>

that is definitely good. i am not sure whether it will be better if
dma zone becomes a property in memory node of DT.

        memory {
                reg = <0x00000000 0x20000000>;
                dma_zone = <0x00000000 0x10000000>;
        };

> ---
>  arch/arm/include/asm/dma.h    |    7 ++++---
>  arch/arm/include/asm/memory.h |    7 +++++--
>  arch/arm/mm/init.c            |   20 +++++++++++++-------
>  3 files changed, 22 insertions(+), 12 deletions(-)
>
> diff --git a/arch/arm/include/asm/dma.h b/arch/arm/include/asm/dma.h
> index 4200554..1d34c11 100644
> --- a/arch/arm/include/asm/dma.h
> +++ b/arch/arm/include/asm/dma.h
> @@ -6,10 +6,11 @@
>  /*
>  * This is the maximum virtual address which can be DMA'd from.
>  */
> -#ifndef ARM_DMA_ZONE_SIZE
> -#define MAX_DMA_ADDRESS        0xffffffff
> +#ifndef CONFIG_ZONE_DMA
> +#define MAX_DMA_ADDRESS        0xffffffffUL
>  #else
> -#define MAX_DMA_ADDRESS        (PAGE_OFFSET + ARM_DMA_ZONE_SIZE)
> +extern unsigned long arm_dma_zone_size;
> +#define MAX_DMA_ADDRESS        (PAGE_OFFSET + arm_dma_zone_size)
>  #endif
>
>  #ifdef CONFIG_ISA_DMA_API
> diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
> index af44a8f..deb2eaa 100644
> --- a/arch/arm/include/asm/memory.h
> +++ b/arch/arm/include/asm/memory.h
> @@ -209,10 +209,13 @@ static inline unsigned long __phys_to_virt(unsigned long x)
>  * allocations.  This must be the smallest DMA mask in the system,
>  * so a successful GFP_DMA allocation will always satisfy this.
>  */
> -#ifndef ARM_DMA_ZONE_SIZE
> +#ifndef CONFIG_ZONE_DMA
>  #define ISA_DMA_THRESHOLD      (0xffffffffULL)
>  #else
> -#define ISA_DMA_THRESHOLD      (PHYS_OFFSET + ARM_DMA_ZONE_SIZE - 1)
> +#define ISA_DMA_THRESHOLD      ({ \
> +       extern unsigned long arm_dma_zone_size; \
> +       arm_dma_zone_size ? \
> +               (PHYS_OFFSET + arm_dma_zone_size - 1) : 0xffffffffULL; })
>  #endif
>
>  /*
> diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
> index c19571c..a14caff 100644
> --- a/arch/arm/mm/init.c
> +++ b/arch/arm/mm/init.c
> @@ -34,6 +34,15 @@
>
>  #include "mm.h"
>
> +#ifdef CONFIG_ZONE_DMA
> +#ifdef ARM_DMA_ZONE_SIZE
> +unsigned long arm_dma_zone_size = ARM_DMA_ZONE_SIZE;
> +#else
> +unsigned long arm_dma_zone_size __read_mostly;
> +#endif
> +EXPORT_SYMBOL(arm_dma_zone_size);
> +#endif
> +
>  static unsigned long phys_initrd_start __initdata = 0;
>  static unsigned long phys_initrd_size __initdata = 0;
>
> @@ -267,17 +276,14 @@ static void __init arm_bootmem_free(unsigned long min, unsigned long max_low,
>  #endif
>        }
>
> -#ifdef ARM_DMA_ZONE_SIZE
> -#ifndef CONFIG_ZONE_DMA
> -#error ARM_DMA_ZONE_SIZE set but no DMA zone to limit allocations
> -#endif
> -
> +#ifdef CONFIG_ZONE_DMA
>        /*
>         * Adjust the sizes according to any special requirements for
>         * this machine type.
>         */
> -       arm_adjust_dma_zone(zone_size, zhole_size,
> -               ARM_DMA_ZONE_SIZE >> PAGE_SHIFT);
> +       if (arm_dma_zone_size)
> +               arm_adjust_dma_zone(zone_size, zhole_size,
> +                       arm_dma_zone_size >> PAGE_SHIFT);
>  #endif
>
>        free_area_init_node(0, zone_size, min, zhole_size);
> --
> 1.7.4
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
Nicolas Pitre July 6, 2011, 3:12 a.m. UTC | #2
On Wed, 6 Jul 2011, Barry Song wrote:

> 2011/7/6 Nicolas Pitre <nicolas.pitre@linaro.org>:
> > Having this value defined at compile time prevents multiple machines with
> > conflicting definitions to coexist.  Move it to a variable in preparation
> > for having a per machine value selected at run time.  This is relevant
> > only when CONFIG_ZONE_DMA is selected.
> >
> > Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org>
> 
> that is definitely good. i am not sure whether it will be better if
> dma zone becomes a property in memory node of DT.

Certainly.  But one thing at a time.  This is the first step. Then, 
those machines that are converted to DT could more easily provide the 
information via this mechanism if they so desire.


Nicolas
Russell King - ARM Linux July 6, 2011, 11:04 p.m. UTC | #3
On Tue, Jul 05, 2011 at 10:30:33PM -0400, Nicolas Pitre wrote:
> +extern unsigned long arm_dma_zone_size;
> +#define MAX_DMA_ADDRESS	(PAGE_OFFSET + arm_dma_zone_size)
...
> -#ifndef ARM_DMA_ZONE_SIZE
> +#ifndef CONFIG_ZONE_DMA
>  #define ISA_DMA_THRESHOLD	(0xffffffffULL)
>  #else
> -#define ISA_DMA_THRESHOLD	(PHYS_OFFSET + ARM_DMA_ZONE_SIZE - 1)
> +#define ISA_DMA_THRESHOLD	({ \
> +	extern unsigned long arm_dma_zone_size; \
> +	arm_dma_zone_size ? \
> +		(PHYS_OFFSET + arm_dma_zone_size - 1) : 0xffffffffULL; })

These two usages do not agree.  With unrestricted DMA, both
MAX_DMA_ADDRESS and ISA_DMA_THRESHOLD should be 0xffffffff.  However,
you get that with arm_dma_zone_size=0 for ISA_DMA_THRESHOLD, which
then gives a MAX_DMA_ADDRESS of PAGE_OFFSET.  So this potentially
changes the behaviour of these macros.
Russell King - ARM Linux July 6, 2011, 11:09 p.m. UTC | #4
On Tue, Jul 05, 2011 at 11:12:16PM -0400, Nicolas Pitre wrote:
> On Wed, 6 Jul 2011, Barry Song wrote:
> 
> > 2011/7/6 Nicolas Pitre <nicolas.pitre@linaro.org>:
> > > Having this value defined at compile time prevents multiple machines with
> > > conflicting definitions to coexist.  Move it to a variable in preparation
> > > for having a per machine value selected at run time.  This is relevant
> > > only when CONFIG_ZONE_DMA is selected.
> > >
> > > Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org>
> > 
> > that is definitely good. i am not sure whether it will be better if
> > dma zone becomes a property in memory node of DT.
> 
> Certainly.  But one thing at a time.  This is the first step. Then, 
> those machines that are converted to DT could more easily provide the 
> information via this mechanism if they so desire.

Actually, putting that information into DT is probably not right -
you're describing something which is specific to Linux, not something
which is due to hardware.

What I mean is that the DMA zone is a Linux specific thing.  Another OS
could have a different way of dealing with the DMA restrictions (it
may be possible to allocate memory within a certain set of bounds.)

What is hardware specific is that the DMA devices can only address a
limited range of memory.  IMHO it's that which should be described in
DT, not that we'll have a DMA zone of X bytes in size.
Nicolas Pitre July 7, 2011, 2:50 a.m. UTC | #5
On Thu, 7 Jul 2011, Russell King - ARM Linux wrote:

> On Tue, Jul 05, 2011 at 11:12:16PM -0400, Nicolas Pitre wrote:
> > On Wed, 6 Jul 2011, Barry Song wrote:
> > 
> > > 2011/7/6 Nicolas Pitre <nicolas.pitre@linaro.org>:
> > > > Having this value defined at compile time prevents multiple machines with
> > > > conflicting definitions to coexist.  Move it to a variable in preparation
> > > > for having a per machine value selected at run time.  This is relevant
> > > > only when CONFIG_ZONE_DMA is selected.
> > > >
> > > > Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org>
> > > 
> > > that is definitely good. i am not sure whether it will be better if
> > > dma zone becomes a property in memory node of DT.
> > 
> > Certainly.  But one thing at a time.  This is the first step. Then, 
> > those machines that are converted to DT could more easily provide the 
> > information via this mechanism if they so desire.
> 
> Actually, putting that information into DT is probably not right -
> you're describing something which is specific to Linux, not something
> which is due to hardware.
> 
> What I mean is that the DMA zone is a Linux specific thing.  Another OS
> could have a different way of dealing with the DMA restrictions (it
> may be possible to allocate memory within a certain set of bounds.)
> 
> What is hardware specific is that the DMA devices can only address a
> limited range of memory.  IMHO it's that which should be described in
> DT, not that we'll have a DMA zone of X bytes in size.

I think that we all agree on the principle.  I certainly never intended 
to suggest that the DMA zone size be stored as is in the device tree.


Nicolas
Arnd Bergmann July 7, 2011, 4:17 p.m. UTC | #6
On Thursday 07 July 2011, Nicolas Pitre wrote:
> > What is hardware specific is that the DMA devices can only address a
> > limited range of memory.  IMHO it's that which should be described in
> > DT, not that we'll have a DMA zone of X bytes in size.
> 
> I think that we all agree on the principle.  I certainly never intended 
> to suggest that the DMA zone size be stored as is in the device tree.

There is a way to specify DMA address ranges in the device tree, though
I forgot the exact format. It comes down to saying the device sees
memory range XXX to YYY as its local address AAA to BBB. We could use
that information at boot time to determine what the largest range
of memory is that is visible by all devices (and hope that it's at
the start of physical memory).

	Arnd
Grant Likely July 7, 2011, 6:15 p.m. UTC | #7
On Thu, Jul 07, 2011 at 06:17:11PM +0200, Arnd Bergmann wrote:
> On Thursday 07 July 2011, Nicolas Pitre wrote:
> > > What is hardware specific is that the DMA devices can only address a
> > > limited range of memory.  IMHO it's that which should be described in
> > > DT, not that we'll have a DMA zone of X bytes in size.
> > 
> > I think that we all agree on the principle.  I certainly never intended 
> > to suggest that the DMA zone size be stored as is in the device tree.
> 
> There is a way to specify DMA address ranges in the device tree, though
> I forgot the exact format. It comes down to saying the device sees
> memory range XXX to YYY as its local address AAA to BBB. We could use
> that information at boot time to determine what the largest range
> of memory is that is visible by all devices (and hope that it's at
> the start of physical memory).

It's called dma-ranges, and it has the same syntax as the ranges
property.  See section 2.3.9 on page 30 in ePAPR:

http://www.power.org/resources/downloads/Power_ePAPR_APPROVED_v1.0.pdf

This describes the hardware constraints, not the DMA zone size or
any software decisions like that.

g.
Russell King - ARM Linux July 8, 2011, 8:59 a.m. UTC | #8
On Thu, Jul 07, 2011 at 11:08:38AM -0600, John Linn wrote:
> If I'm following this right....
> 
> We have a hole at the start of physical memory (when it's at 0) so that
> DMA can't DMA into it.  Sounds like that won't work for us?

That depends what you mean by that.

If you're saying that your physical RAM starts at some non-zero address,
then that isn't a problem.  We have lots of ARM platforms where that is
true.

If you're saying that the first N MB of RAM can't be DMA'd to, then that
is a problem as the kernel has no way to be told about that restriction.
The best we can manage is to avoid freeing that memory into the normal
allocation pools.

We do have a very small number of platforms where that's true, but we
'work around' that by having the kernel occupy that space.  If N MB is
less than sizeof(kernel) + 32K then you haven't lost much.
John Linn July 8, 2011, 1:58 p.m. UTC | #9
> -----Original Message-----
> From: Russell King - ARM Linux [mailto:linux@arm.linux.org.uk]
> Sent: Friday, July 08, 2011 3:00 AM
> To: John Linn
> Cc: Arnd Bergmann; linux-arm-kernel@lists.infradead.org; Nicolas
Pitre;
> grant.likely@secretlab.ca; Barry Song
> Subject: Re: [PATCH 01/10] ARM: change ARM_DMA_ZONE_SIZE into a
> variable
> 
> On Thu, Jul 07, 2011 at 11:08:38AM -0600, John Linn wrote:
> > If I'm following this right....
> >
> > We have a hole at the start of physical memory (when it's at 0) so
> that
> > DMA can't DMA into it.  Sounds like that won't work for us?
> 
> That depends what you mean by that.
> 
> If you're saying that your physical RAM starts at some non-zero
> address,
> then that isn't a problem.  We have lots of ARM platforms where that
is
> true.
> 
> If you're saying that the first N MB of RAM can't be DMA'd to, then
> that
> is a problem as the kernel has no way to be told about that
> restriction.
> The best we can manage is to avoid freeing that memory into the normal
> allocation pools.

Yes that is what I'm saying. Catalin and I had some conversation about
this
previously (my apologies if I just didn't get it Catalin).

> 
> We do have a very small number of platforms where that's true, but we
> 'work around' that by having the kernel occupy that space.  If N MB is
> less than sizeof(kernel) + 32K then you haven't lost much.

It's only at addresses 0 - 512K that's not DMA-able.  I am using a DMA
zone (with a hole at the front) to avoid this problem right now but
maybe I'm not really understanding it and it's not working correctly.
Testing looks good with the DMA zone.

I didn't like the other solution since we had to add another exception
where the kernel frees it's memory (not to free it).  But maybe this is
really the right solution as Catalin had tried to explain to me.

Thanks for the input,
John


Please ignore any legal footer at the bottom of this email, this problem
is still being worked.


  

This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.
Russell King - ARM Linux July 8, 2011, 4:23 p.m. UTC | #10
On Fri, Jul 08, 2011 at 07:58:03AM -0600, John Linn wrote:
> It's only at addresses 0 - 512K that's not DMA-able.  I am using a DMA
> zone (with a hole at the front) to avoid this problem right now but
> maybe I'm not really understanding it and it's not working correctly.
> Testing looks good with the DMA zone.

That's more or less what we do with Integrator platforms.  It's very
unlikely that a kernel will ever be smaller than 512K, so if you place
it at 32K as normal, avoid freeing the .init text/data, and keep the
first 32K reserved (the second 16K will be reserved for the swapper
page table in any case) then you'll keep that memory away from anything
that might hand it out for DMA purposes.

See free_initmem() for the integrator stuff avoiding .init freeing, and
integrator_reserve() to keep the first 16K reserved.
diff mbox

Patch

diff --git a/arch/arm/include/asm/dma.h b/arch/arm/include/asm/dma.h
index 4200554..1d34c11 100644
--- a/arch/arm/include/asm/dma.h
+++ b/arch/arm/include/asm/dma.h
@@ -6,10 +6,11 @@ 
 /*
  * This is the maximum virtual address which can be DMA'd from.
  */
-#ifndef ARM_DMA_ZONE_SIZE
-#define MAX_DMA_ADDRESS	0xffffffff
+#ifndef CONFIG_ZONE_DMA
+#define MAX_DMA_ADDRESS	0xffffffffUL
 #else
-#define MAX_DMA_ADDRESS	(PAGE_OFFSET + ARM_DMA_ZONE_SIZE)
+extern unsigned long arm_dma_zone_size;
+#define MAX_DMA_ADDRESS	(PAGE_OFFSET + arm_dma_zone_size)
 #endif
 
 #ifdef CONFIG_ISA_DMA_API
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index af44a8f..deb2eaa 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -209,10 +209,13 @@  static inline unsigned long __phys_to_virt(unsigned long x)
  * allocations.  This must be the smallest DMA mask in the system,
  * so a successful GFP_DMA allocation will always satisfy this.
  */
-#ifndef ARM_DMA_ZONE_SIZE
+#ifndef CONFIG_ZONE_DMA
 #define ISA_DMA_THRESHOLD	(0xffffffffULL)
 #else
-#define ISA_DMA_THRESHOLD	(PHYS_OFFSET + ARM_DMA_ZONE_SIZE - 1)
+#define ISA_DMA_THRESHOLD	({ \
+	extern unsigned long arm_dma_zone_size; \
+	arm_dma_zone_size ? \
+		(PHYS_OFFSET + arm_dma_zone_size - 1) : 0xffffffffULL; })
 #endif
 
 /*
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index c19571c..a14caff 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -34,6 +34,15 @@ 
 
 #include "mm.h"
 
+#ifdef CONFIG_ZONE_DMA
+#ifdef ARM_DMA_ZONE_SIZE
+unsigned long arm_dma_zone_size = ARM_DMA_ZONE_SIZE;
+#else
+unsigned long arm_dma_zone_size __read_mostly;
+#endif
+EXPORT_SYMBOL(arm_dma_zone_size);
+#endif
+
 static unsigned long phys_initrd_start __initdata = 0;
 static unsigned long phys_initrd_size __initdata = 0;
 
@@ -267,17 +276,14 @@  static void __init arm_bootmem_free(unsigned long min, unsigned long max_low,
 #endif
 	}
 
-#ifdef ARM_DMA_ZONE_SIZE
-#ifndef CONFIG_ZONE_DMA
-#error ARM_DMA_ZONE_SIZE set but no DMA zone to limit allocations
-#endif
-
+#ifdef CONFIG_ZONE_DMA
 	/*
 	 * Adjust the sizes according to any special requirements for
 	 * this machine type.
 	 */
-	arm_adjust_dma_zone(zone_size, zhole_size,
-		ARM_DMA_ZONE_SIZE >> PAGE_SHIFT);
+	if (arm_dma_zone_size)
+		arm_adjust_dma_zone(zone_size, zhole_size,
+			arm_dma_zone_size >> PAGE_SHIFT);
 #endif
 
 	free_area_init_node(0, zone_size, min, zhole_size);