From 3835d69a6c7048a28d0aea3cb8403d5e83a0f867 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 6 Jul 2011 10:39:34 +0100 Subject: ARM: vmlinux.lds: move init sections between text and data sections Place the init sections between the text and data sections. This means all code is grouped together at the beginning of the kernel image, and all data is at the end of the image. This avoids problems with the 24-bit branch instruction relocations becoming invalid with large initramfs images. Acked-by: Nicolas Pitre Tested-by: Stephen Boyd Signed-off-by: Russell King --- arch/arm/mm/init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/arm/mm/init.c') diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index c19571c40a2..b8e89124315 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -639,8 +639,8 @@ void __init mem_init(void) " pkmap : 0x%08lx - 0x%08lx (%4ld MB)\n" #endif " modules : 0x%08lx - 0x%08lx (%4ld MB)\n" - " .init : 0x%p" " - 0x%p" " (%4d kB)\n" " .text : 0x%p" " - 0x%p" " (%4d kB)\n" + " .init : 0x%p" " - 0x%p" " (%4d kB)\n" " .data : 0x%p" " - 0x%p" " (%4d kB)\n" " .bss : 0x%p" " - 0x%p" " (%4d kB)\n", @@ -662,8 +662,8 @@ void __init mem_init(void) #endif MLM(MODULES_VADDR, MODULES_END), - MLK_ROUNDUP(__init_begin, __init_end), MLK_ROUNDUP(_text, _etext), + MLK_ROUNDUP(__init_begin, __init_end), MLK_ROUNDUP(_sdata, _edata), MLK_ROUNDUP(__bss_start, __bss_stop)); -- cgit v1.2.3-70-g09d2 From 54d525735140e930d87c5afd1b0b3393ffdac021 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 7 Jul 2011 18:43:36 +0100 Subject: ARM: 6996/1: mm: Poison freed init memory Poisoning __init marked memory can be useful when tracking down obscure memory corruption bugs. Therefore, poison init memory with 0xe7fddef0 to catch bugs earlier. The poison value is an undefined instruction in ARM mode and branch to an undefined instruction in Thumb mode. Signed-off-by: Stephen Boyd Acked-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/mm/init.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'arch/arm/mm/init.c') diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 2c2cce9cd8c..fdc87f9bda5 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -416,6 +416,17 @@ static inline int free_area(unsigned long pfn, unsigned long end, char *s) return pages; } +/* + * Poison init memory with an undefined instruction (ARM) or a branch to an + * undefined instruction (Thumb). + */ +static inline void poison_init_mem(void *s, size_t count) +{ + u32 *p = (u32 *)s; + while ((count = count - 4)) + *p++ = 0xe7fddef0; +} + static inline void free_memmap(unsigned long start_pfn, unsigned long end_pfn) { @@ -696,11 +707,13 @@ void free_initmem(void) #ifdef CONFIG_HAVE_TCM extern char __tcm_start, __tcm_end; + poison_init_mem(&__tcm_start, &__tcm_end - &__tcm_start); totalram_pages += free_area(__phys_to_pfn(__pa(&__tcm_start)), __phys_to_pfn(__pa(&__tcm_end)), "TCM link"); #endif + poison_init_mem(__init_begin, __init_end - __init_begin); if (!machine_is_integrator() && !machine_is_cintegrator()) totalram_pages += free_area(__phys_to_pfn(__pa(__init_begin)), __phys_to_pfn(__pa(__init_end)), @@ -713,10 +726,12 @@ static int keep_initrd; void free_initrd_mem(unsigned long start, unsigned long end) { - if (!keep_initrd) + if (!keep_initrd) { + poison_init_mem((void *)start, PAGE_ALIGN(end) - start); totalram_pages += free_area(__phys_to_pfn(__pa(start)), __phys_to_pfn(__pa(end)), "initrd"); + } } static int __init keepinitrd_setup(char *__unused) -- cgit v1.2.3-70-g09d2 From 022ae537b23cb14a391565e9ad9e9945f4b17138 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 8 Jul 2011 21:26:59 +0100 Subject: ARM: dma: replace ISA_DMA_THRESHOLD with a variable ISA_DMA_THRESHOLD has been unused by non-arch code, so lets now get rid of it from ARM by replacing it with arm_dma_zone_mask. Move dma_supported() and dma_set_mask() out of line, and have dma_supported() check this new variable instead. Signed-off-by: Russell King --- arch/arm/include/asm/dma-mapping.h | 29 ++--------------------------- arch/arm/include/asm/memory.h | 12 ------------ arch/arm/mm/dma-mapping.c | 35 ++++++++++++++++++++++++++++++++--- arch/arm/mm/init.c | 10 ++++++++++ arch/arm/mm/mm.h | 6 ++++++ 5 files changed, 50 insertions(+), 42 deletions(-) (limited to 'arch/arm/mm/init.c') diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index 94662f4c9ea..7a21d0bf713 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -115,33 +115,8 @@ static inline void __dma_page_dev_to_cpu(struct page *page, unsigned long off, ___dma_page_dev_to_cpu(page, off, size, dir); } -/* - * 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. - * - * FIXME: This should really be a platform specific issue - we should - * return false if GFP_DMA allocations may not satisfy the supplied 'mask'. - */ -static inline int dma_supported(struct device *dev, u64 mask) -{ - if (mask < ISA_DMA_THRESHOLD) - 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; - -#ifndef CONFIG_DMABOUNCE - *dev->dma_mask = dma_mask; -#endif - - return 0; -} +extern int dma_supported(struct device *, u64); +extern int dma_set_mask(struct device *, u64); /* * DMA errors are defined by all-bits-set in the DMA address. diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index af44a8fb348..b8de516e600 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -203,18 +203,6 @@ static inline unsigned long __phys_to_virt(unsigned long x) #define PHYS_OFFSET PLAT_PHYS_OFFSET #endif -/* - * The DMA mask corresponding to the maximum bus address allocatable - * using GFP_DMA. The default here places no restriction on DMA - * 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 -#define ISA_DMA_THRESHOLD (0xffffffffULL) -#else -#define ISA_DMA_THRESHOLD (PHYS_OFFSET + ARM_DMA_ZONE_SIZE - 1) -#endif - /* * PFNs are used to describe any physical page; this means * PFN 0 == physical address 0. diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 82a093cee09..0a0a1e7c20d 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -25,9 +25,11 @@ #include #include +#include "mm.h" + static u64 get_coherent_dma_mask(struct device *dev) { - u64 mask = ISA_DMA_THRESHOLD; + u64 mask = (u64)arm_dma_limit; if (dev) { mask = dev->coherent_dma_mask; @@ -41,10 +43,10 @@ static u64 get_coherent_dma_mask(struct device *dev) return 0; } - if ((~mask) & ISA_DMA_THRESHOLD) { + if ((~mask) & (u64)arm_dma_limit) { dev_warn(dev, "coherent DMA mask %#llx is smaller " "than system GFP_DMA mask %#llx\n", - mask, (unsigned long long)ISA_DMA_THRESHOLD); + mask, (u64)arm_dma_limit); return 0; } } @@ -657,6 +659,33 @@ void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, } EXPORT_SYMBOL(dma_sync_sg_for_device); +/* + * 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. + */ +int dma_supported(struct device *dev, u64 mask) +{ + if (mask < (u64)arm_dma_limit) + return 0; + return 1; +} +EXPORT_SYMBOL(dma_supported); + +int dma_set_mask(struct device *dev, u64 dma_mask) +{ + if (!dev->dma_mask || !dma_supported(dev, dma_mask)) + return -EIO; + +#ifndef CONFIG_DMABOUNCE + *dev->dma_mask = dma_mask; +#endif + + return 0; +} +EXPORT_SYMBOL(dma_set_mask); + #define PREALLOC_DMA_DEBUG_ENTRIES 4096 static int __init dma_debug_do_init(void) diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index c19571c40a2..17d6cd0c57e 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -212,6 +212,14 @@ static void __init arm_bootmem_init(unsigned long start_pfn, } #ifdef CONFIG_ZONE_DMA +/* + * The DMA mask corresponding to the maximum bus address allocatable + * using GFP_DMA. The default here places no restriction on DMA + * allocations. This must be the smallest DMA mask in the system, + * so a successful GFP_DMA allocation will always satisfy this. + */ +u32 arm_dma_limit; + static void __init arm_adjust_dma_zone(unsigned long *size, unsigned long *hole, unsigned long dma_size) { @@ -278,6 +286,8 @@ static void __init arm_bootmem_free(unsigned long min, unsigned long max_low, */ arm_adjust_dma_zone(zone_size, zhole_size, ARM_DMA_ZONE_SIZE >> PAGE_SHIFT); + + arm_dma_limit = PHYS_OFFSET + ARM_DMA_ZONE_SIZE - 1; #endif free_area_init_node(0, zone_size, min, zhole_size); diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h index 5b3d7d54365..010566799c8 100644 --- a/arch/arm/mm/mm.h +++ b/arch/arm/mm/mm.h @@ -23,5 +23,11 @@ extern void __flush_dcache_page(struct address_space *mapping, struct page *page #endif +#ifdef CONFIG_ZONE_DMA +extern u32 arm_dma_limit; +#else +#define arm_dma_limit ((u32)~0) +#endif + void __init bootmem_init(void); void arm_mm_memblock_reserve(void); -- cgit v1.2.3-70-g09d2 From 650320181a08b64d4421c65c639cf47ad8cc2cd6 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Mon, 18 Jul 2011 15:05:10 -0400 Subject: ARM: change ARM_DMA_ZONE_SIZE into a variable 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 --- arch/arm/include/asm/dma.h | 9 ++++++--- arch/arm/mm/init.c | 25 ++++++++++++++++--------- 2 files changed, 22 insertions(+), 12 deletions(-) (limited to 'arch/arm/mm/init.c') diff --git a/arch/arm/include/asm/dma.h b/arch/arm/include/asm/dma.h index 42005542932..fcf15de8cad 100644 --- a/arch/arm/include/asm/dma.h +++ b/arch/arm/include/asm/dma.h @@ -6,10 +6,13 @@ /* * 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) +#define MAX_DMA_ADDRESS ({ \ + extern unsigned long arm_dma_zone_size; \ + arm_dma_zone_size ? \ + (PAGE_OFFSET + arm_dma_zone_size) : 0xffffffffUL; }) #endif #ifdef CONFIG_ISA_DMA_API diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 17d6cd0c57e..4a8a01e0c3a 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -212,6 +213,14 @@ static void __init arm_bootmem_init(unsigned long start_pfn, } #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); + /* * The DMA mask corresponding to the maximum bus address allocatable * using GFP_DMA. The default here places no restriction on DMA @@ -275,19 +284,17 @@ 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); - - arm_dma_limit = PHYS_OFFSET + ARM_DMA_ZONE_SIZE - 1; + if (arm_dma_zone_size) { + arm_adjust_dma_zone(zone_size, zhole_size, + arm_dma_zone_size >> PAGE_SHIFT); + arm_dma_limit = PHYS_OFFSET + arm_dma_zone_size - 1; + } else + arm_dma_limit = 0xffffffff; #endif free_area_init_node(0, zone_size, min, zhole_size); -- cgit v1.2.3-70-g09d2 From fb89fcfb151698776be6c900aec8161b01990e92 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Mon, 18 Jul 2011 15:17:15 -0400 Subject: ARM: ARM_DMA_ZONE_SIZE is no more One less dependency on mach/memory.h. Signed-off-by: Nicolas Pitre --- arch/arm/include/asm/dma.h | 2 -- arch/arm/mm/init.c | 5 ----- 2 files changed, 7 deletions(-) (limited to 'arch/arm/mm/init.c') diff --git a/arch/arm/include/asm/dma.h b/arch/arm/include/asm/dma.h index fcf15de8cad..628670e9d7c 100644 --- a/arch/arm/include/asm/dma.h +++ b/arch/arm/include/asm/dma.h @@ -1,8 +1,6 @@ #ifndef __ASM_ARM_DMA_H #define __ASM_ARM_DMA_H -#include - /* * This is the maximum virtual address which can be DMA'd from. */ diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 4a8a01e0c3a..90a38c6baca 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -214,11 +213,7 @@ static void __init arm_bootmem_init(unsigned long start_pfn, #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); /* -- cgit v1.2.3-70-g09d2