Merge branches 'cleanup', 'fixes', 'misc', 'omap-barrier' and 'uaccess' into for...
[linux-2.6-microblaze.git] / arch / arm / mm / mmu.c
index 6ca7d9a..7cd1514 100644 (file)
@@ -291,13 +291,13 @@ static struct mem_type mem_types[] = {
                .prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
                                L_PTE_RDONLY,
                .prot_l1   = PMD_TYPE_TABLE,
-               .domain    = DOMAIN_USER,
+               .domain    = DOMAIN_VECTORS,
        },
        [MT_HIGH_VECTORS] = {
                .prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
                                L_PTE_USER | L_PTE_RDONLY,
                .prot_l1   = PMD_TYPE_TABLE,
-               .domain    = DOMAIN_USER,
+               .domain    = DOMAIN_VECTORS,
        },
        [MT_MEMORY_RWX] = {
                .prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY,
@@ -357,6 +357,47 @@ const struct mem_type *get_mem_type(unsigned int type)
 }
 EXPORT_SYMBOL(get_mem_type);
 
+static pte_t *(*pte_offset_fixmap)(pmd_t *dir, unsigned long addr);
+
+static pte_t bm_pte[PTRS_PER_PTE + PTE_HWTABLE_PTRS]
+       __aligned(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE) __initdata;
+
+static pte_t * __init pte_offset_early_fixmap(pmd_t *dir, unsigned long addr)
+{
+       return &bm_pte[pte_index(addr)];
+}
+
+static pte_t *pte_offset_late_fixmap(pmd_t *dir, unsigned long addr)
+{
+       return pte_offset_kernel(dir, addr);
+}
+
+static inline pmd_t * __init fixmap_pmd(unsigned long addr)
+{
+       pgd_t *pgd = pgd_offset_k(addr);
+       pud_t *pud = pud_offset(pgd, addr);
+       pmd_t *pmd = pmd_offset(pud, addr);
+
+       return pmd;
+}
+
+void __init early_fixmap_init(void)
+{
+       pmd_t *pmd;
+
+       /*
+        * The early fixmap range spans multiple pmds, for which
+        * we are not prepared:
+        */
+       BUILD_BUG_ON((__fix_to_virt(__end_of_permanent_fixed_addresses) >> PMD_SHIFT)
+                    != FIXADDR_TOP >> PMD_SHIFT);
+
+       pmd = fixmap_pmd(FIXADDR_TOP);
+       pmd_populate_kernel(&init_mm, pmd, bm_pte);
+
+       pte_offset_fixmap = pte_offset_early_fixmap;
+}
+
 /*
  * To avoid TLB flush broadcasts, this uses local_flush_tlb_kernel_range().
  * As a result, this can only be called with preemption disabled, as under
@@ -365,7 +406,7 @@ EXPORT_SYMBOL(get_mem_type);
 void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot)
 {
        unsigned long vaddr = __fix_to_virt(idx);
-       pte_t *pte = pte_offset_kernel(pmd_off_k(vaddr), vaddr);
+       pte_t *pte = pte_offset_fixmap(pmd_off_k(vaddr), vaddr);
 
        /* Make sure fixmap region does not exceed available allocation. */
        BUILD_BUG_ON(FIXADDR_START + (__end_of_fixed_addresses * PAGE_SIZE) >
@@ -855,7 +896,7 @@ static void __init create_mapping(struct map_desc *md)
        }
 
        if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
-           md->virtual >= PAGE_OFFSET &&
+           md->virtual >= PAGE_OFFSET && md->virtual < FIXADDR_START &&
            (md->virtual < VMALLOC_START || md->virtual >= VMALLOC_END)) {
                pr_warn("BUG: mapping for 0x%08llx at 0x%08lx out of vmalloc space\n",
                        (long long)__pfn_to_phys((u64)md->pfn), md->virtual);
@@ -1072,6 +1113,7 @@ void __init sanity_check_meminfo(void)
        int highmem = 0;
        phys_addr_t vmalloc_limit = __pa(vmalloc_min - 1) + 1;
        struct memblock_region *reg;
+       bool should_use_highmem = false;
 
        for_each_memblock(memory, reg) {
                phys_addr_t block_start = reg->base;
@@ -1090,6 +1132,7 @@ void __init sanity_check_meminfo(void)
                                pr_notice("Ignoring RAM at %pa-%pa (!CONFIG_HIGHMEM)\n",
                                          &block_start, &block_end);
                                memblock_remove(reg->base, reg->size);
+                               should_use_highmem = true;
                                continue;
                        }
 
@@ -1100,6 +1143,7 @@ void __init sanity_check_meminfo(void)
                                          &block_start, &block_end, &vmalloc_limit);
                                memblock_remove(vmalloc_limit, overlap_size);
                                block_end = vmalloc_limit;
+                               should_use_highmem = true;
                        }
                }
 
@@ -1134,6 +1178,9 @@ void __init sanity_check_meminfo(void)
                }
        }
 
+       if (should_use_highmem)
+               pr_notice("Consider using a HIGHMEM enabled kernel.\n");
+
        high_memory = __va(arm_lowmem_limit - 1) + 1;
 
        /*
@@ -1213,10 +1260,10 @@ void __init arm_mm_memblock_reserve(void)
 
 /*
  * Set up the device mappings.  Since we clear out the page tables for all
- * mappings above VMALLOC_START, we will remove any debug device mappings.
- * This means you have to be careful how you debug this function, or any
- * called function.  This means you can't use any function or debugging
- * method which may touch any device, otherwise the kernel _will_ crash.
+ * mappings above VMALLOC_START, except early fixmap, we might remove debug
+ * device mappings.  This means earlycon can be used to debug this function
+ * Any other function or debugging method which may touch any device _will_
+ * crash the kernel.
  */
 static void __init devicemaps_init(const struct machine_desc *mdesc)
 {
@@ -1231,7 +1278,10 @@ static void __init devicemaps_init(const struct machine_desc *mdesc)
 
        early_trap_init(vectors);
 
-       for (addr = VMALLOC_START; addr; addr += PMD_SIZE)
+       /*
+        * Clear page table except top pmd used by early fixmaps
+        */
+       for (addr = VMALLOC_START; addr < (FIXADDR_TOP & PMD_MASK); addr += PMD_SIZE)
                pmd_clear(pmd_off_k(addr));
 
        /*
@@ -1483,6 +1533,35 @@ void __init early_paging_init(const struct machine_desc *mdesc)
 
 #endif
 
+static void __init early_fixmap_shutdown(void)
+{
+       int i;
+       unsigned long va = fix_to_virt(__end_of_permanent_fixed_addresses - 1);
+
+       pte_offset_fixmap = pte_offset_late_fixmap;
+       pmd_clear(fixmap_pmd(va));
+       local_flush_tlb_kernel_page(va);
+
+       for (i = 0; i < __end_of_permanent_fixed_addresses; i++) {
+               pte_t *pte;
+               struct map_desc map;
+
+               map.virtual = fix_to_virt(i);
+               pte = pte_offset_early_fixmap(pmd_off_k(map.virtual), map.virtual);
+
+               /* Only i/o device mappings are supported ATM */
+               if (pte_none(*pte) ||
+                   (pte_val(*pte) & L_PTE_MT_MASK) != L_PTE_MT_DEV_SHARED)
+                       continue;
+
+               map.pfn = pte_pfn(*pte);
+               map.type = MT_DEVICE;
+               map.length = PAGE_SIZE;
+
+               create_mapping(&map);
+       }
+}
+
 /*
  * paging_init() sets up the page tables, initialises the zone memory
  * maps, and sets up the zero page, bad page and bad page tables.
@@ -1494,7 +1573,9 @@ void __init paging_init(const struct machine_desc *mdesc)
        build_mem_type_table();
        prepare_page_table();
        map_lowmem();
+       memblock_set_current_limit(arm_lowmem_limit);
        dma_contiguous_remap();
+       early_fixmap_shutdown();
        devicemaps_init(mdesc);
        kmap_init();
        tcm_init();