]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/arm64/mm/mmu.c
Merge remote-tracking branch 'dt-rh/for-next'
[karo-tx-linux.git] / arch / arm64 / mm / mmu.c
index 502169d823c3737a310a010a4c5f6aa01529585f..c3e5df62671e6c4eb8c4a4502dd16f0162224256 100644 (file)
@@ -123,7 +123,9 @@ static void alloc_init_pte(pmd_t *pmd, unsigned long addr,
        pte_t *pte;
 
        if (pmd_none(*pmd) || pmd_sect(*pmd)) {
-               phys_addr_t pte_phys = pgtable_alloc();
+               phys_addr_t pte_phys;
+               BUG_ON(!pgtable_alloc);
+               pte_phys = pgtable_alloc();
                pte = pte_set_fixmap(pte_phys);
                if (pmd_sect(*pmd))
                        split_pmd(pmd, pte);
@@ -154,6 +156,26 @@ static void split_pud(pud_t *old_pud, pmd_t *pmd)
        } while (pmd++, i++, i < PTRS_PER_PMD);
 }
 
+#ifdef CONFIG_DEBUG_PAGEALLOC
+static bool block_mappings_allowed(phys_addr_t (*pgtable_alloc)(void))
+{
+
+       /*
+        * If debug_page_alloc is enabled we must map the linear map
+        * using pages. However, other mappings created by
+        * create_mapping_noalloc must use sections in some cases. Allow
+        * sections to be used in those cases, where no pgtable_alloc
+        * function is provided.
+        */
+       return !pgtable_alloc || !debug_pagealloc_enabled();
+}
+#else
+static bool block_mappings_allowed(phys_addr_t (*pgtable_alloc)(void))
+{
+       return true;
+}
+#endif
+
 static void alloc_init_pmd(pud_t *pud, unsigned long addr, unsigned long end,
                                  phys_addr_t phys, pgprot_t prot,
                                  phys_addr_t (*pgtable_alloc)(void))
@@ -165,7 +187,9 @@ static void alloc_init_pmd(pud_t *pud, unsigned long addr, unsigned long end,
         * Check for initial section mappings in the pgd/pud and remove them.
         */
        if (pud_none(*pud) || pud_sect(*pud)) {
-               phys_addr_t pmd_phys = pgtable_alloc();
+               phys_addr_t pmd_phys;
+               BUG_ON(!pgtable_alloc);
+               pmd_phys = pgtable_alloc();
                pmd = pmd_set_fixmap(pmd_phys);
                if (pud_sect(*pud)) {
                        /*
@@ -184,7 +208,8 @@ static void alloc_init_pmd(pud_t *pud, unsigned long addr, unsigned long end,
        do {
                next = pmd_addr_end(addr, end);
                /* try section mapping first */
-               if (((addr | next | phys) & ~SECTION_MASK) == 0) {
+               if (((addr | next | phys) & ~SECTION_MASK) == 0 &&
+                     block_mappings_allowed(pgtable_alloc)) {
                        pmd_t old_pmd =*pmd;
                        set_pmd(pmd, __pmd(phys |
                                           pgprot_val(mk_sect_prot(prot))));
@@ -230,7 +255,9 @@ static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
        unsigned long next;
 
        if (pgd_none(*pgd)) {
-               phys_addr_t pud_phys = pgtable_alloc();
+               phys_addr_t pud_phys;
+               BUG_ON(!pgtable_alloc);
+               pud_phys = pgtable_alloc();
                __pgd_populate(pgd, pud_phys, PUD_TYPE_TABLE);
        }
        BUG_ON(pgd_bad(*pgd));
@@ -242,7 +269,8 @@ static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
                /*
                 * For 4K granule only, attempt to put down a 1GB block
                 */
-               if (use_1G_block(addr, next, phys)) {
+               if (use_1G_block(addr, next, phys) &&
+                   block_mappings_allowed(pgtable_alloc)) {
                        pud_t old_pud = *pud;
                        set_pud(pud, __pud(phys |
                                           pgprot_val(mk_sect_prot(prot))));
@@ -319,7 +347,12 @@ static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,
        init_pgd(pgd_offset_raw(pgdir, virt), phys, virt, size, prot, alloc);
 }
 
-static void __init create_mapping(phys_addr_t phys, unsigned long virt,
+/*
+ * This function can only be used to modify existing table entries,
+ * without allocating new levels of table. Note that this permits the
+ * creation of new section or page entries.
+ */
+static void __init create_mapping_noalloc(phys_addr_t phys, unsigned long virt,
                                  phys_addr_t size, pgprot_t prot)
 {
        if (virt < VMALLOC_START) {
@@ -328,7 +361,7 @@ static void __init create_mapping(phys_addr_t phys, unsigned long virt,
                return;
        }
        __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot,
-                            early_pgtable_alloc);
+                            NULL);
 }
 
 void __init create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys,
@@ -714,7 +747,7 @@ void *__init fixmap_remap_fdt(phys_addr_t dt_phys)
        /*
         * Make sure that the FDT region can be mapped without the need to
         * allocate additional translation table pages, so that it is safe
-        * to call create_mapping() this early.
+        * to call create_mapping_noalloc() this early.
         *
         * On 64k pages, the FDT will be mapped using PTEs, so we need to
         * be in the same PMD as the rest of the fixmap.
@@ -730,8 +763,8 @@ void *__init fixmap_remap_fdt(phys_addr_t dt_phys)
        dt_virt = (void *)dt_virt_base + offset;
 
        /* map the first chunk so we can read the size from the header */
-       create_mapping(round_down(dt_phys, SWAPPER_BLOCK_SIZE), dt_virt_base,
-                      SWAPPER_BLOCK_SIZE, prot);
+       create_mapping_noalloc(round_down(dt_phys, SWAPPER_BLOCK_SIZE),
+                       dt_virt_base, SWAPPER_BLOCK_SIZE, prot);
 
        if (fdt_check_header(dt_virt) != 0)
                return NULL;
@@ -741,7 +774,7 @@ void *__init fixmap_remap_fdt(phys_addr_t dt_phys)
                return NULL;
 
        if (offset + size > SWAPPER_BLOCK_SIZE)
-               create_mapping(round_down(dt_phys, SWAPPER_BLOCK_SIZE), dt_virt_base,
+               create_mapping_noalloc(round_down(dt_phys, SWAPPER_BLOCK_SIZE), dt_virt_base,
                               round_up(offset + size, SWAPPER_BLOCK_SIZE), prot);
 
        memblock_reserve(dt_phys, size);