diff options
Diffstat (limited to 'arch/arm/mm/mmu.c')
-rw-r--r-- | arch/arm/mm/mmu.c | 174 |
1 files changed, 59 insertions, 115 deletions
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 285894171186..6e1c4f6a2b3f 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c | |||
@@ -11,13 +11,12 @@ | |||
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/bootmem.h> | ||
15 | #include <linux/mman.h> | 14 | #include <linux/mman.h> |
16 | #include <linux/nodemask.h> | 15 | #include <linux/nodemask.h> |
16 | #include <linux/memblock.h> | ||
17 | #include <linux/sort.h> | 17 | #include <linux/sort.h> |
18 | 18 | ||
19 | #include <asm/cputype.h> | 19 | #include <asm/cputype.h> |
20 | #include <asm/mach-types.h> | ||
21 | #include <asm/sections.h> | 20 | #include <asm/sections.h> |
22 | #include <asm/cachetype.h> | 21 | #include <asm/cachetype.h> |
23 | #include <asm/setup.h> | 22 | #include <asm/setup.h> |
@@ -258,6 +257,19 @@ static struct mem_type mem_types[] = { | |||
258 | .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE, | 257 | .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE, |
259 | .domain = DOMAIN_KERNEL, | 258 | .domain = DOMAIN_KERNEL, |
260 | }, | 259 | }, |
260 | [MT_MEMORY_DTCM] = { | ||
261 | .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | | ||
262 | L_PTE_DIRTY | L_PTE_WRITE, | ||
263 | .prot_l1 = PMD_TYPE_TABLE, | ||
264 | .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN, | ||
265 | .domain = DOMAIN_KERNEL, | ||
266 | }, | ||
267 | [MT_MEMORY_ITCM] = { | ||
268 | .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | | ||
269 | L_PTE_USER | L_PTE_EXEC, | ||
270 | .prot_l1 = PMD_TYPE_TABLE, | ||
271 | .domain = DOMAIN_IO, | ||
272 | }, | ||
261 | }; | 273 | }; |
262 | 274 | ||
263 | const struct mem_type *get_mem_type(unsigned int type) | 275 | const struct mem_type *get_mem_type(unsigned int type) |
@@ -488,18 +500,28 @@ static void __init build_mem_type_table(void) | |||
488 | 500 | ||
489 | #define vectors_base() (vectors_high() ? 0xffff0000 : 0) | 501 | #define vectors_base() (vectors_high() ? 0xffff0000 : 0) |
490 | 502 | ||
491 | static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr, | 503 | static void __init *early_alloc(unsigned long sz) |
492 | unsigned long end, unsigned long pfn, | ||
493 | const struct mem_type *type) | ||
494 | { | 504 | { |
495 | pte_t *pte; | 505 | void *ptr = __va(memblock_alloc(sz, sz)); |
506 | memset(ptr, 0, sz); | ||
507 | return ptr; | ||
508 | } | ||
496 | 509 | ||
510 | static pte_t * __init early_pte_alloc(pmd_t *pmd, unsigned long addr, unsigned long prot) | ||
511 | { | ||
497 | if (pmd_none(*pmd)) { | 512 | if (pmd_none(*pmd)) { |
498 | pte = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * sizeof(pte_t)); | 513 | pte_t *pte = early_alloc(2 * PTRS_PER_PTE * sizeof(pte_t)); |
499 | __pmd_populate(pmd, __pa(pte) | type->prot_l1); | 514 | __pmd_populate(pmd, __pa(pte) | prot); |
500 | } | 515 | } |
516 | BUG_ON(pmd_bad(*pmd)); | ||
517 | return pte_offset_kernel(pmd, addr); | ||
518 | } | ||
501 | 519 | ||
502 | pte = pte_offset_kernel(pmd, addr); | 520 | static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr, |
521 | unsigned long end, unsigned long pfn, | ||
522 | const struct mem_type *type) | ||
523 | { | ||
524 | pte_t *pte = early_pte_alloc(pmd, addr, type->prot_l1); | ||
503 | do { | 525 | do { |
504 | set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)), 0); | 526 | set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)), 0); |
505 | pfn++; | 527 | pfn++; |
@@ -668,7 +690,7 @@ void __init iotable_init(struct map_desc *io_desc, int nr) | |||
668 | create_mapping(io_desc + i); | 690 | create_mapping(io_desc + i); |
669 | } | 691 | } |
670 | 692 | ||
671 | static unsigned long __initdata vmalloc_reserve = SZ_128M; | 693 | static void * __initdata vmalloc_min = (void *)(VMALLOC_END - SZ_128M); |
672 | 694 | ||
673 | /* | 695 | /* |
674 | * vmalloc=size forces the vmalloc area to be exactly 'size' | 696 | * vmalloc=size forces the vmalloc area to be exactly 'size' |
@@ -677,7 +699,7 @@ static unsigned long __initdata vmalloc_reserve = SZ_128M; | |||
677 | */ | 699 | */ |
678 | static int __init early_vmalloc(char *arg) | 700 | static int __init early_vmalloc(char *arg) |
679 | { | 701 | { |
680 | vmalloc_reserve = memparse(arg, NULL); | 702 | unsigned long vmalloc_reserve = memparse(arg, NULL); |
681 | 703 | ||
682 | if (vmalloc_reserve < SZ_16M) { | 704 | if (vmalloc_reserve < SZ_16M) { |
683 | vmalloc_reserve = SZ_16M; | 705 | vmalloc_reserve = SZ_16M; |
@@ -692,22 +714,26 @@ static int __init early_vmalloc(char *arg) | |||
692 | "vmalloc area is too big, limiting to %luMB\n", | 714 | "vmalloc area is too big, limiting to %luMB\n", |
693 | vmalloc_reserve >> 20); | 715 | vmalloc_reserve >> 20); |
694 | } | 716 | } |
717 | |||
718 | vmalloc_min = (void *)(VMALLOC_END - vmalloc_reserve); | ||
695 | return 0; | 719 | return 0; |
696 | } | 720 | } |
697 | early_param("vmalloc", early_vmalloc); | 721 | early_param("vmalloc", early_vmalloc); |
698 | 722 | ||
699 | #define VMALLOC_MIN (void *)(VMALLOC_END - vmalloc_reserve) | 723 | phys_addr_t lowmem_end_addr; |
700 | 724 | ||
701 | static void __init sanity_check_meminfo(void) | 725 | static void __init sanity_check_meminfo(void) |
702 | { | 726 | { |
703 | int i, j, highmem = 0; | 727 | int i, j, highmem = 0; |
704 | 728 | ||
729 | lowmem_end_addr = __pa(vmalloc_min - 1) + 1; | ||
730 | |||
705 | for (i = 0, j = 0; i < meminfo.nr_banks; i++) { | 731 | for (i = 0, j = 0; i < meminfo.nr_banks; i++) { |
706 | struct membank *bank = &meminfo.bank[j]; | 732 | struct membank *bank = &meminfo.bank[j]; |
707 | *bank = meminfo.bank[i]; | 733 | *bank = meminfo.bank[i]; |
708 | 734 | ||
709 | #ifdef CONFIG_HIGHMEM | 735 | #ifdef CONFIG_HIGHMEM |
710 | if (__va(bank->start) > VMALLOC_MIN || | 736 | if (__va(bank->start) > vmalloc_min || |
711 | __va(bank->start) < (void *)PAGE_OFFSET) | 737 | __va(bank->start) < (void *)PAGE_OFFSET) |
712 | highmem = 1; | 738 | highmem = 1; |
713 | 739 | ||
@@ -717,8 +743,8 @@ static void __init sanity_check_meminfo(void) | |||
717 | * Split those memory banks which are partially overlapping | 743 | * Split those memory banks which are partially overlapping |
718 | * the vmalloc area greatly simplifying things later. | 744 | * the vmalloc area greatly simplifying things later. |
719 | */ | 745 | */ |
720 | if (__va(bank->start) < VMALLOC_MIN && | 746 | if (__va(bank->start) < vmalloc_min && |
721 | bank->size > VMALLOC_MIN - __va(bank->start)) { | 747 | bank->size > vmalloc_min - __va(bank->start)) { |
722 | if (meminfo.nr_banks >= NR_BANKS) { | 748 | if (meminfo.nr_banks >= NR_BANKS) { |
723 | printk(KERN_CRIT "NR_BANKS too low, " | 749 | printk(KERN_CRIT "NR_BANKS too low, " |
724 | "ignoring high memory\n"); | 750 | "ignoring high memory\n"); |
@@ -727,12 +753,12 @@ static void __init sanity_check_meminfo(void) | |||
727 | (meminfo.nr_banks - i) * sizeof(*bank)); | 753 | (meminfo.nr_banks - i) * sizeof(*bank)); |
728 | meminfo.nr_banks++; | 754 | meminfo.nr_banks++; |
729 | i++; | 755 | i++; |
730 | bank[1].size -= VMALLOC_MIN - __va(bank->start); | 756 | bank[1].size -= vmalloc_min - __va(bank->start); |
731 | bank[1].start = __pa(VMALLOC_MIN - 1) + 1; | 757 | bank[1].start = __pa(vmalloc_min - 1) + 1; |
732 | bank[1].highmem = highmem = 1; | 758 | bank[1].highmem = highmem = 1; |
733 | j++; | 759 | j++; |
734 | } | 760 | } |
735 | bank->size = VMALLOC_MIN - __va(bank->start); | 761 | bank->size = vmalloc_min - __va(bank->start); |
736 | } | 762 | } |
737 | #else | 763 | #else |
738 | bank->highmem = highmem; | 764 | bank->highmem = highmem; |
@@ -741,7 +767,7 @@ static void __init sanity_check_meminfo(void) | |||
741 | * Check whether this memory bank would entirely overlap | 767 | * Check whether this memory bank would entirely overlap |
742 | * the vmalloc area. | 768 | * the vmalloc area. |
743 | */ | 769 | */ |
744 | if (__va(bank->start) >= VMALLOC_MIN || | 770 | if (__va(bank->start) >= vmalloc_min || |
745 | __va(bank->start) < (void *)PAGE_OFFSET) { | 771 | __va(bank->start) < (void *)PAGE_OFFSET) { |
746 | printk(KERN_NOTICE "Ignoring RAM at %.8lx-%.8lx " | 772 | printk(KERN_NOTICE "Ignoring RAM at %.8lx-%.8lx " |
747 | "(vmalloc region overlap).\n", | 773 | "(vmalloc region overlap).\n", |
@@ -753,9 +779,9 @@ static void __init sanity_check_meminfo(void) | |||
753 | * Check whether this memory bank would partially overlap | 779 | * Check whether this memory bank would partially overlap |
754 | * the vmalloc area. | 780 | * the vmalloc area. |
755 | */ | 781 | */ |
756 | if (__va(bank->start + bank->size) > VMALLOC_MIN || | 782 | if (__va(bank->start + bank->size) > vmalloc_min || |
757 | __va(bank->start + bank->size) < __va(bank->start)) { | 783 | __va(bank->start + bank->size) < __va(bank->start)) { |
758 | unsigned long newsize = VMALLOC_MIN - __va(bank->start); | 784 | unsigned long newsize = vmalloc_min - __va(bank->start); |
759 | printk(KERN_NOTICE "Truncating RAM at %.8lx-%.8lx " | 785 | printk(KERN_NOTICE "Truncating RAM at %.8lx-%.8lx " |
760 | "to -%.8lx (vmalloc region overlap).\n", | 786 | "to -%.8lx (vmalloc region overlap).\n", |
761 | bank->start, bank->start + bank->size - 1, | 787 | bank->start, bank->start + bank->size - 1, |
@@ -827,101 +853,23 @@ static inline void prepare_page_table(void) | |||
827 | } | 853 | } |
828 | 854 | ||
829 | /* | 855 | /* |
830 | * Reserve the various regions of node 0 | 856 | * Reserve the special regions of memory |
831 | */ | 857 | */ |
832 | void __init reserve_node_zero(pg_data_t *pgdat) | 858 | void __init arm_mm_memblock_reserve(void) |
833 | { | 859 | { |
834 | unsigned long res_size = 0; | ||
835 | |||
836 | /* | ||
837 | * Register the kernel text and data with bootmem. | ||
838 | * Note that this can only be in node 0. | ||
839 | */ | ||
840 | #ifdef CONFIG_XIP_KERNEL | ||
841 | reserve_bootmem_node(pgdat, __pa(_data), _end - _data, | ||
842 | BOOTMEM_DEFAULT); | ||
843 | #else | ||
844 | reserve_bootmem_node(pgdat, __pa(_stext), _end - _stext, | ||
845 | BOOTMEM_DEFAULT); | ||
846 | #endif | ||
847 | |||
848 | /* | 860 | /* |
849 | * Reserve the page tables. These are already in use, | 861 | * Reserve the page tables. These are already in use, |
850 | * and can only be in node 0. | 862 | * and can only be in node 0. |
851 | */ | 863 | */ |
852 | reserve_bootmem_node(pgdat, __pa(swapper_pg_dir), | 864 | memblock_reserve(__pa(swapper_pg_dir), PTRS_PER_PGD * sizeof(pgd_t)); |
853 | PTRS_PER_PGD * sizeof(pgd_t), BOOTMEM_DEFAULT); | ||
854 | |||
855 | /* | ||
856 | * Hmm... This should go elsewhere, but we really really need to | ||
857 | * stop things allocating the low memory; ideally we need a better | ||
858 | * implementation of GFP_DMA which does not assume that DMA-able | ||
859 | * memory starts at zero. | ||
860 | */ | ||
861 | if (machine_is_integrator() || machine_is_cintegrator()) | ||
862 | res_size = __pa(swapper_pg_dir) - PHYS_OFFSET; | ||
863 | |||
864 | /* | ||
865 | * These should likewise go elsewhere. They pre-reserve the | ||
866 | * screen memory region at the start of main system memory. | ||
867 | */ | ||
868 | if (machine_is_edb7211()) | ||
869 | res_size = 0x00020000; | ||
870 | if (machine_is_p720t()) | ||
871 | res_size = 0x00014000; | ||
872 | |||
873 | /* H1940, RX3715 and RX1950 need to reserve this for suspend */ | ||
874 | |||
875 | if (machine_is_h1940() || machine_is_rx3715() | ||
876 | || machine_is_rx1950()) { | ||
877 | reserve_bootmem_node(pgdat, 0x30003000, 0x1000, | ||
878 | BOOTMEM_DEFAULT); | ||
879 | reserve_bootmem_node(pgdat, 0x30081000, 0x1000, | ||
880 | BOOTMEM_DEFAULT); | ||
881 | } | ||
882 | |||
883 | if (machine_is_palmld() || machine_is_palmtx()) { | ||
884 | reserve_bootmem_node(pgdat, 0xa0000000, 0x1000, | ||
885 | BOOTMEM_EXCLUSIVE); | ||
886 | reserve_bootmem_node(pgdat, 0xa0200000, 0x1000, | ||
887 | BOOTMEM_EXCLUSIVE); | ||
888 | } | ||
889 | |||
890 | if (machine_is_treo680() || machine_is_centro()) { | ||
891 | reserve_bootmem_node(pgdat, 0xa0000000, 0x1000, | ||
892 | BOOTMEM_EXCLUSIVE); | ||
893 | reserve_bootmem_node(pgdat, 0xa2000000, 0x1000, | ||
894 | BOOTMEM_EXCLUSIVE); | ||
895 | } | ||
896 | |||
897 | if (machine_is_palmt5()) | ||
898 | reserve_bootmem_node(pgdat, 0xa0200000, 0x1000, | ||
899 | BOOTMEM_EXCLUSIVE); | ||
900 | |||
901 | /* | ||
902 | * U300 - This platform family can share physical memory | ||
903 | * between two ARM cpus, one running Linux and the other | ||
904 | * running another OS. | ||
905 | */ | ||
906 | if (machine_is_u300()) { | ||
907 | #ifdef CONFIG_MACH_U300_SINGLE_RAM | ||
908 | #if ((CONFIG_MACH_U300_ACCESS_MEM_SIZE & 1) == 1) && \ | ||
909 | CONFIG_MACH_U300_2MB_ALIGNMENT_FIX | ||
910 | res_size = 0x00100000; | ||
911 | #endif | ||
912 | #endif | ||
913 | } | ||
914 | 865 | ||
915 | #ifdef CONFIG_SA1111 | 866 | #ifdef CONFIG_SA1111 |
916 | /* | 867 | /* |
917 | * Because of the SA1111 DMA bug, we want to preserve our | 868 | * Because of the SA1111 DMA bug, we want to preserve our |
918 | * precious DMA-able memory... | 869 | * precious DMA-able memory... |
919 | */ | 870 | */ |
920 | res_size = __pa(swapper_pg_dir) - PHYS_OFFSET; | 871 | memblock_reserve(PHYS_OFFSET, __pa(swapper_pg_dir) - PHYS_OFFSET); |
921 | #endif | 872 | #endif |
922 | if (res_size) | ||
923 | reserve_bootmem_node(pgdat, PHYS_OFFSET, res_size, | ||
924 | BOOTMEM_DEFAULT); | ||
925 | } | 873 | } |
926 | 874 | ||
927 | /* | 875 | /* |
@@ -940,7 +888,7 @@ static void __init devicemaps_init(struct machine_desc *mdesc) | |||
940 | /* | 888 | /* |
941 | * Allocate the vector page early. | 889 | * Allocate the vector page early. |
942 | */ | 890 | */ |
943 | vectors = alloc_bootmem_low_pages(PAGE_SIZE); | 891 | vectors = early_alloc(PAGE_SIZE); |
944 | 892 | ||
945 | for (addr = VMALLOC_END; addr; addr += PGDIR_SIZE) | 893 | for (addr = VMALLOC_END; addr; addr += PGDIR_SIZE) |
946 | pmd_clear(pmd_off_k(addr)); | 894 | pmd_clear(pmd_off_k(addr)); |
@@ -1011,11 +959,8 @@ static void __init devicemaps_init(struct machine_desc *mdesc) | |||
1011 | static void __init kmap_init(void) | 959 | static void __init kmap_init(void) |
1012 | { | 960 | { |
1013 | #ifdef CONFIG_HIGHMEM | 961 | #ifdef CONFIG_HIGHMEM |
1014 | pmd_t *pmd = pmd_off_k(PKMAP_BASE); | 962 | pkmap_page_table = early_pte_alloc(pmd_off_k(PKMAP_BASE), |
1015 | pte_t *pte = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * sizeof(pte_t)); | 963 | PKMAP_BASE, _PAGE_KERNEL_TABLE); |
1016 | BUG_ON(!pmd_none(*pmd) || !pte); | ||
1017 | __pmd_populate(pmd, __pa(pte) | _PAGE_KERNEL_TABLE); | ||
1018 | pkmap_page_table = pte + PTRS_PER_PTE; | ||
1019 | #endif | 964 | #endif |
1020 | } | 965 | } |
1021 | 966 | ||
@@ -1066,17 +1011,16 @@ void __init paging_init(struct machine_desc *mdesc) | |||
1066 | sanity_check_meminfo(); | 1011 | sanity_check_meminfo(); |
1067 | prepare_page_table(); | 1012 | prepare_page_table(); |
1068 | map_lowmem(); | 1013 | map_lowmem(); |
1069 | bootmem_init(); | ||
1070 | devicemaps_init(mdesc); | 1014 | devicemaps_init(mdesc); |
1071 | kmap_init(); | 1015 | kmap_init(); |
1072 | 1016 | ||
1073 | top_pmd = pmd_off_k(0xffff0000); | 1017 | top_pmd = pmd_off_k(0xffff0000); |
1074 | 1018 | ||
1075 | /* | 1019 | /* allocate the zero page. */ |
1076 | * allocate the zero page. Note that this always succeeds and | 1020 | zero_page = early_alloc(PAGE_SIZE); |
1077 | * returns a zeroed result. | 1021 | |
1078 | */ | 1022 | bootmem_init(); |
1079 | zero_page = alloc_bootmem_low_pages(PAGE_SIZE); | 1023 | |
1080 | empty_zero_page = virt_to_page(zero_page); | 1024 | empty_zero_page = virt_to_page(zero_page); |
1081 | __flush_dcache_page(NULL, empty_zero_page); | 1025 | __flush_dcache_page(NULL, empty_zero_page); |
1082 | } | 1026 | } |