|
@@ -195,7 +195,30 @@ static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
|
|
|
|
|
|
do {
|
|
|
next = pud_addr_end(addr, end);
|
|
|
- alloc_init_pmd(pud, addr, next, phys);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * For 4K granule only, attempt to put down a 1GB block
|
|
|
+ */
|
|
|
+ if ((PAGE_SHIFT == 12) &&
|
|
|
+ ((addr | next | phys) & ~PUD_MASK) == 0) {
|
|
|
+ pud_t old_pud = *pud;
|
|
|
+ set_pud(pud, __pud(phys | PROT_SECT_NORMAL_EXEC));
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If we have an old value for a pud, it will
|
|
|
+ * be pointing to a pmd table that we no longer
|
|
|
+ * need (from swapper_pg_dir).
|
|
|
+ *
|
|
|
+ * Look up the old pmd table and free it.
|
|
|
+ */
|
|
|
+ if (!pud_none(old_pud)) {
|
|
|
+ phys_addr_t table = __pa(pmd_offset(&old_pud, 0));
|
|
|
+ memblock_free(table, PAGE_SIZE);
|
|
|
+ flush_tlb_all();
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ alloc_init_pmd(pud, addr, next, phys);
|
|
|
+ }
|
|
|
phys += next - addr;
|
|
|
} while (pud++, addr = next, addr != end);
|
|
|
}
|
|
@@ -338,6 +361,9 @@ int kern_addr_valid(unsigned long addr)
|
|
|
if (pud_none(*pud))
|
|
|
return 0;
|
|
|
|
|
|
+ if (pud_sect(*pud))
|
|
|
+ return pfn_valid(pud_pfn(*pud));
|
|
|
+
|
|
|
pmd = pmd_offset(pud, addr);
|
|
|
if (pmd_none(*pmd))
|
|
|
return 0;
|