summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2010-10-27 19:57:38 +0100
committerRussell King <rmk+kernel@arm.linux.org.uk>2010-10-28 13:54:45 +0100
commit8df6516864462cb7a6f87d5a46df68fb0faebbb5 (patch)
tree2db5634fa29b20bf6e64ce9446aef5a5e51b9c54
parentf25b4b4c89ff118df72421dd2cb080a6380896ac (diff)
ARM: memblock: setup lowmem mappings using memblock
Use memblock information to setup lowmem mappings rather than the membank array. This allows platforms to manipulate the memblock information during initialization to reserve (and remove) memory from the kernel's view of memory - and thus allowing platforms to setup their own private mappings for this memory without causing problems with multiple aliasing mappings: size = min(size, SZ_2M); base = memblock_alloc(size, min(align, SZ_2M)); memblock_free(base, size); memblock_remove(base, size); This is needed because multiple mappings of regions with differing attributes (sharability, type, cache) are not permitted with ARMv6 and above. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/mm/mmu.c49
1 files changed, 29 insertions, 20 deletions
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 5222d385096..72ad3e1f56c 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -744,11 +744,14 @@ static int __init early_vmalloc(char *arg)
}
early_param("vmalloc", early_vmalloc);
+static phys_addr_t lowmem_limit __initdata = 0;
+
static void __init sanity_check_meminfo(void)
{
int i, j, highmem = 0;
- memblock_set_current_limit(__pa(vmalloc_min - 1) + 1);
+ lowmem_limit = __pa(vmalloc_min - 1) + 1;
+ memblock_set_current_limit(lowmem_limit);
for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
struct membank *bank = &meminfo.bank[j];
@@ -849,6 +852,7 @@ static void __init sanity_check_meminfo(void)
static inline void prepare_page_table(void)
{
unsigned long addr;
+ phys_addr_t end;
/*
* Clear out all the mappings below the kernel image.
@@ -864,10 +868,17 @@ static inline void prepare_page_table(void)
pmd_clear(pmd_off_k(addr));
/*
+ * Find the end of the first block of lowmem.
+ */
+ end = memblock.memory.regions[0].base + memblock.memory.regions[0].size;
+ if (end >= lowmem_limit)
+ end = lowmem_limit;
+
+ /*
* Clear out all the kernel space mappings, except for the first
* memory bank, up to the end of the vmalloc region.
*/
- for (addr = __phys_to_virt(bank_phys_end(&meminfo.bank[0]));
+ for (addr = __phys_to_virt(end);
addr < VMALLOC_END; addr += PGDIR_SIZE)
pmd_clear(pmd_off_k(addr));
}
@@ -984,29 +995,27 @@ static void __init kmap_init(void)
#endif
}
-static inline void map_memory_bank(struct membank *bank)
-{
- struct map_desc map;
-
- map.pfn = bank_pfn_start(bank);
- map.virtual = __phys_to_virt(bank_phys_start(bank));
- map.length = bank_phys_size(bank);
- map.type = MT_MEMORY;
-
- create_mapping(&map);
-}
-
static void __init map_lowmem(void)
{
- struct meminfo *mi = &meminfo;
- int i;
+ struct memblock_region *reg;
/* Map all the lowmem memory banks. */
- for (i = 0; i < mi->nr_banks; i++) {
- struct membank *bank = &mi->bank[i];
+ for_each_memblock(memory, reg) {
+ phys_addr_t start = reg->base;
+ phys_addr_t end = start + reg->size;
+ struct map_desc map;
+
+ if (end > lowmem_limit)
+ end = lowmem_limit;
+ if (start >= end)
+ break;
+
+ map.pfn = __phys_to_pfn(start);
+ map.virtual = __phys_to_virt(start);
+ map.length = end - start;
+ map.type = MT_MEMORY;
- if (!bank->highmem)
- map_memory_bank(bank);
+ create_mapping(&map);
}
}