]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/s390/mm/vmem.c
s390/mm,vmem: use 2GB frames for identity mapping
[karo-tx-linux.git] / arch / s390 / mm / vmem.c
index 387c7c60b5b8d65a50bec087a54288a1cc913519..bf37a094a46bc8dc24b8bc1491b5f68a9ee7bb59 100644 (file)
@@ -89,6 +89,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
        int ret = -ENOMEM;
 
        while (address < end) {
+               pte = mk_pte_phys(address, __pgprot(ro ? _PAGE_RO : 0));
                pg_dir = pgd_offset_k(address);
                if (pgd_none(*pg_dir)) {
                        pu_dir = vmem_pud_alloc();
@@ -96,18 +97,24 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
                                goto out;
                        pgd_populate(&init_mm, pg_dir, pu_dir);
                }
-
                pu_dir = pud_offset(pg_dir, address);
+#if defined(CONFIG_64BIT) && !defined(CONFIG_DEBUG_PAGEALLOC)
+               if (MACHINE_HAS_EDAT2 && pud_none(*pu_dir) && address &&
+                   !(address & ~PUD_MASK) && (address + PUD_SIZE <= end)) {
+                       pte_val(pte) |= _REGION3_ENTRY_LARGE;
+                       pte_val(pte) |= _REGION_ENTRY_TYPE_R3;
+                       pud_val(*pu_dir) = pte_val(pte);
+                       address += PUD_SIZE;
+                       continue;
+               }
+#endif
                if (pud_none(*pu_dir)) {
                        pm_dir = vmem_pmd_alloc();
                        if (!pm_dir)
                                goto out;
                        pud_populate(&init_mm, pu_dir, pm_dir);
                }
-
-               pte = mk_pte_phys(address, __pgprot(ro ? _PAGE_RO : 0));
                pm_dir = pmd_offset(pu_dir, address);
-
 #if defined(CONFIG_64BIT) && !defined(CONFIG_DEBUG_PAGEALLOC)
                if (MACHINE_HAS_EDAT1 && pmd_none(*pm_dir) && address &&
                    !(address & ~PMD_MASK) && (address + PMD_SIZE <= end)) {
@@ -160,6 +167,11 @@ static void vmem_remove_range(unsigned long start, unsigned long size)
                        address += PUD_SIZE;
                        continue;
                }
+               if (pud_large(*pu_dir)) {
+                       pud_clear(pu_dir);
+                       address += PUD_SIZE;
+                       continue;
+               }
                pm_dir = pmd_offset(pu_dir, address);
                if (pmd_none(*pm_dir)) {
                        address += PMD_SIZE;