Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+29 -20
+29 -20
arch/arm/mm/mmu.c
··· 744 744 } 745 745 early_param("vmalloc", early_vmalloc); 746 746 747 + static phys_addr_t lowmem_limit __initdata = 0; 748 + 747 749 static void __init sanity_check_meminfo(void) 748 750 { 749 751 int i, j, highmem = 0; 750 752 751 - memblock_set_current_limit(__pa(vmalloc_min - 1) + 1); 753 + lowmem_limit = __pa(vmalloc_min - 1) + 1; 754 + memblock_set_current_limit(lowmem_limit); 752 755 753 756 for (i = 0, j = 0; i < meminfo.nr_banks; i++) { 754 757 struct membank *bank = &meminfo.bank[j]; ··· 852 849 static inline void prepare_page_table(void) 853 850 { 854 851 unsigned long addr; 852 + phys_addr_t end; 855 853 856 854 /* 857 855 * Clear out all the mappings below the kernel image. ··· 868 864 pmd_clear(pmd_off_k(addr)); 869 865 870 866 /* 867 + * Find the end of the first block of lowmem. 868 + */ 869 + end = memblock.memory.regions[0].base + memblock.memory.regions[0].size; 870 + if (end >= lowmem_limit) 871 + end = lowmem_limit; 872 + 873 + /* 871 874 * Clear out all the kernel space mappings, except for the first 872 875 * memory bank, up to the end of the vmalloc region. 873 876 */ 874 - for (addr = __phys_to_virt(bank_phys_end(&meminfo.bank[0])); 877 + for (addr = __phys_to_virt(end); 875 878 addr < VMALLOC_END; addr += PGDIR_SIZE) 876 879 pmd_clear(pmd_off_k(addr)); 877 880 } ··· 995 984 #endif 996 985 } 997 986 998 - static inline void map_memory_bank(struct membank *bank) 999 - { 1000 - struct map_desc map; 1001 - 1002 - map.pfn = bank_pfn_start(bank); 1003 - map.virtual = __phys_to_virt(bank_phys_start(bank)); 1004 - map.length = bank_phys_size(bank); 1005 - map.type = MT_MEMORY; 1006 - 1007 - create_mapping(&map); 1008 - } 1009 - 1010 987 static void __init map_lowmem(void) 1011 988 { 1012 - struct meminfo *mi = &meminfo; 1013 - int i; 989 + struct memblock_region *reg; 1014 990 1015 991 /* Map all the lowmem memory banks. */ 1016 - for (i = 0; i < mi->nr_banks; i++) { 1017 - struct membank *bank = &mi->bank[i]; 992 + for_each_memblock(memory, reg) { 993 + phys_addr_t start = reg->base; 994 + phys_addr_t end = start + reg->size; 995 + struct map_desc map; 1018 996 1019 - if (!bank->highmem) 1020 - map_memory_bank(bank); 997 + if (end > lowmem_limit) 998 + end = lowmem_limit; 999 + if (start >= end) 1000 + break; 1001 + 1002 + map.pfn = __phys_to_pfn(start); 1003 + map.virtual = __phys_to_virt(start); 1004 + map.length = end - start; 1005 + map.type = MT_MEMORY; 1006 + 1007 + create_mapping(&map); 1021 1008 } 1022 1009 } 1023 1010