ARM: 7418/1: LPAE: fix access flag setup in mem_type_table
[linux-flexiantxendom0-3.2.10.git] / arch / arm / mm / mmu.c
index c614815..aa78de8 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/fs.h>
 #include <linux/vmalloc.h>
 
+#include <asm/cp15.h>
 #include <asm/cputype.h>
 #include <asm/sections.h>
 #include <asm/cachetype.h>
@@ -25,6 +26,7 @@
 #include <asm/smp_plat.h>
 #include <asm/tlb.h>
 #include <asm/highmem.h>
+#include <asm/system_info.h>
 #include <asm/traps.h>
 
 #include <asm/mach/arch.h>
@@ -151,6 +153,7 @@ static int __init early_nowrite(char *__unused)
 }
 early_param("nowb", early_nowrite);
 
+#ifndef CONFIG_ARM_LPAE
 static int __init early_ecc(char *p)
 {
        if (memcmp(p, "on", 2) == 0)
@@ -160,6 +163,7 @@ static int __init early_ecc(char *p)
        return 0;
 }
 early_param("ecc", early_ecc);
+#endif
 
 static int __init noalign_setup(char *__unused)
 {
@@ -229,10 +233,12 @@ static struct mem_type mem_types[] = {
                .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN,
                .domain    = DOMAIN_KERNEL,
        },
+#ifndef CONFIG_ARM_LPAE
        [MT_MINICLEAN] = {
                .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN | PMD_SECT_MINICACHE,
                .domain    = DOMAIN_KERNEL,
        },
+#endif
        [MT_LOW_VECTORS] = {
                .prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
                                L_PTE_RDONLY,
@@ -430,6 +436,7 @@ static void __init build_mem_type_table(void)
         * ARMv6 and above have extended page tables.
         */
        if (cpu_arch >= CPU_ARCH_ARMv6 && (cr & CR_XP)) {
+#ifndef CONFIG_ARM_LPAE
                /*
                 * Mark cache clean areas and XIP ROM read only
                 * from SVC mode and no access from userspace.
@@ -437,6 +444,7 @@ static void __init build_mem_type_table(void)
                mem_types[MT_ROM].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
                mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
                mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
+#endif
 
                if (is_smp()) {
                        /*
@@ -475,6 +483,19 @@ static void __init build_mem_type_table(void)
                mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_BUFFERABLE;
        }
 
+#ifdef CONFIG_ARM_LPAE
+       /*
+        * Do not generate access flag faults for the kernel mappings.
+        */
+       for (i = 0; i < ARRAY_SIZE(mem_types); i++) {
+               mem_types[i].prot_pte |= PTE_EXT_AF;
+               if (mem_types[i].prot_sect)
+                       mem_types[i].prot_sect |= PMD_SECT_AF;
+       }
+       kern_pgprot |= PTE_EXT_AF;
+       vecs_pgprot |= PTE_EXT_AF;
+#endif
+
        for (i = 0; i < 16; i++) {
                unsigned long v = pgprot_val(protection_map[i]);
                protection_map[i] = __pgprot(v | user_pgprot);
@@ -578,8 +599,10 @@ static void __init alloc_init_section(pud_t *pud, unsigned long addr,
        if (((addr | end | phys) & ~SECTION_MASK) == 0) {
                pmd_t *p = pmd;
 
+#ifndef CONFIG_ARM_LPAE
                if (addr & SECTION_SIZE)
                        pmd++;
+#endif
 
                do {
                        *pmd = __pmd(phys | type->prot_sect);
@@ -596,8 +619,8 @@ static void __init alloc_init_section(pud_t *pud, unsigned long addr,
        }
 }
 
-static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
-       unsigned long phys, const struct mem_type *type)
+static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
+       unsigned long end, unsigned long phys, const struct mem_type *type)
 {
        pud_t *pud = pud_offset(pgd, addr);
        unsigned long next;
@@ -609,6 +632,7 @@ static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
        } while (pud++, addr = next, addr != end);
 }
 
+#ifndef CONFIG_ARM_LPAE
 static void __init create_36bit_mapping(struct map_desc *md,
                                        const struct mem_type *type)
 {
@@ -668,6 +692,7 @@ static void __init create_36bit_mapping(struct map_desc *md,
                pgd += SUPERSECTION_SIZE >> PGDIR_SHIFT;
        } while (addr != end);
 }
+#endif /* !CONFIG_ARM_LPAE */
 
 /*
  * Create the page directory entries and any necessary
@@ -700,6 +725,7 @@ static void __init create_mapping(struct map_desc *md)
 
        type = &mem_types[md->type];
 
+#ifndef CONFIG_ARM_LPAE
        /*
         * Catch 36-bit addresses
         */
@@ -707,6 +733,7 @@ static void __init create_mapping(struct map_desc *md)
                create_36bit_mapping(md, type);
                return;
        }
+#endif
 
        addr = md->virtual & PAGE_MASK;
        phys = __pfn_to_phys(md->pfn);
@@ -749,7 +776,8 @@ void __init iotable_init(struct map_desc *io_desc, int nr)
                vm->addr = (void *)(md->virtual & PAGE_MASK);
                vm->size = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
                vm->phys_addr = __pfn_to_phys(md->pfn); 
-               vm->flags = VM_IOREMAP;
+               vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING; 
+               vm->flags |= VM_ARM_MTYPE(md->type);
                vm->caller = iotable_init;
                vm_area_add_early(vm++);
        }
@@ -796,6 +824,9 @@ void __init sanity_check_meminfo(void)
                struct membank *bank = &meminfo.bank[j];
                *bank = meminfo.bank[i];
 
+               if (bank->start > ULONG_MAX)
+                       highmem = 1;
+
 #ifdef CONFIG_HIGHMEM
                if (__va(bank->start) >= vmalloc_min ||
                    __va(bank->start) < (void *)PAGE_OFFSET)
@@ -807,7 +838,7 @@ void __init sanity_check_meminfo(void)
                 * Split those memory banks which are partially overlapping
                 * the vmalloc area greatly simplifying things later.
                 */
-               if (__va(bank->start) < vmalloc_min &&
+               if (!highmem && __va(bank->start) < vmalloc_min &&
                    bank->size > vmalloc_min - __va(bank->start)) {
                        if (meminfo.nr_banks >= NR_BANKS) {
                                printk(KERN_CRIT "NR_BANKS too low, "
@@ -828,6 +859,17 @@ void __init sanity_check_meminfo(void)
                bank->highmem = highmem;
 
                /*
+                * Highmem banks not allowed with !CONFIG_HIGHMEM.
+                */
+               if (highmem) {
+                       printk(KERN_NOTICE "Ignoring RAM at %.8llx-%.8llx "
+                              "(!CONFIG_HIGHMEM).\n",
+                              (unsigned long long)bank->start,
+                              (unsigned long long)bank->start + bank->size - 1);
+                       continue;
+               }
+
+               /*
                 * Check whether this memory bank would entirely overlap
                 * the vmalloc area.
                 */
@@ -919,7 +961,13 @@ static inline void prepare_page_table(void)
                pmd_clear(pmd_off_k(addr));
 }
 
+#ifdef CONFIG_ARM_LPAE
+/* the first page is reserved for pgd */
+#define SWAPPER_PG_DIR_SIZE    (PAGE_SIZE + \
+                                PTRS_PER_PGD * PTRS_PER_PMD * sizeof(pmd_t))
+#else
 #define SWAPPER_PG_DIR_SIZE    (PTRS_PER_PGD * sizeof(pgd_t))
+#endif
 
 /*
  * Reserve the special regions of memory
@@ -952,11 +1000,14 @@ static void __init devicemaps_init(struct machine_desc *mdesc)
 {
        struct map_desc map;
        unsigned long addr;
+       void *vectors;
 
        /*
         * Allocate the vector page early.
         */
-       vectors_page = early_alloc(PAGE_SIZE);
+       vectors = early_alloc(PAGE_SIZE);
+
+       early_trap_init(vectors);
 
        for (addr = VMALLOC_START; addr; addr += PMD_SIZE)
                pmd_clear(pmd_off_k(addr));
@@ -996,7 +1047,7 @@ static void __init devicemaps_init(struct machine_desc *mdesc)
         * location (0xffff0000).  If we aren't using high-vectors, also
         * create a mapping at the low-vectors virtual address.
         */
-       map.pfn = __phys_to_pfn(virt_to_phys(vectors_page));
+       map.pfn = __phys_to_pfn(virt_to_phys(vectors));
        map.virtual = 0xffff0000;
        map.length = PAGE_SIZE;
        map.type = MT_HIGH_VECTORS;