]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
s390/mm,vmem: use 2GB frames for identity mapping
authorHeiko Carstens <heiko.carstens@de.ibm.com>
Mon, 8 Oct 2012 07:18:26 +0000 (09:18 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Tue, 6 Nov 2012 21:40:28 +0000 (22:40 +0100)
Use 2GB frames for indentity mapping if EDAT2 is
available to reduce TLB pressure.

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/include/asm/pgtable.h
arch/s390/mm/dump_pagetables.c
arch/s390/mm/pageattr.c
arch/s390/mm/vmem.c

index 2d3b7cb2600593f102b23dc8094fe384aa151b28..0eefb9e192d18898b48ef254df1008ff4480bf34 100644 (file)
@@ -345,6 +345,8 @@ extern unsigned long MODULES_END;
 #define _REGION3_ENTRY         (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_LENGTH)
 #define _REGION3_ENTRY_EMPTY   (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_INV)
 
+#define _REGION3_ENTRY_LARGE   0x400   /* RTTE-format control, large page  */
+
 /* Bits in the segment table entry */
 #define _SEGMENT_ENTRY_ORIGIN  ~0x7ffUL/* segment table origin             */
 #define _SEGMENT_ENTRY_RO      0x200   /* page protection bit              */
@@ -444,6 +446,7 @@ static inline int pgd_bad(pgd_t pgd)     { return 0; }
 
 static inline int pud_present(pud_t pud) { return 1; }
 static inline int pud_none(pud_t pud)   { return 0; }
+static inline int pud_large(pud_t pud)  { return 0; }
 static inline int pud_bad(pud_t pud)    { return 0; }
 
 #else /* CONFIG_64BIT */
@@ -489,6 +492,13 @@ static inline int pud_none(pud_t pud)
        return (pud_val(pud) & _REGION_ENTRY_INV) != 0UL;
 }
 
+static inline int pud_large(pud_t pud)
+{
+       if ((pud_val(pud) & _REGION_ENTRY_TYPE_MASK) != _REGION_ENTRY_TYPE_R3)
+               return 0;
+       return !!(pud_val(pud) & _REGION3_ENTRY_LARGE);
+}
+
 static inline int pud_bad(pud_t pud)
 {
        /*
index cbc6668acb85e8dd5b6100410a1fcd887e97df1d..04e4892247d2081f1087897613d0028149133a72 100644 (file)
@@ -150,6 +150,7 @@ static void walk_pmd_level(struct seq_file *m, struct pg_state *st,
 static void walk_pud_level(struct seq_file *m, struct pg_state *st,
                           pgd_t *pgd, unsigned long addr)
 {
+       unsigned int prot;
        pud_t *pud;
        int i;
 
@@ -157,7 +158,11 @@ static void walk_pud_level(struct seq_file *m, struct pg_state *st,
                st->current_address = addr;
                pud = pud_offset(pgd, addr);
                if (!pud_none(*pud))
-                       walk_pmd_level(m, st, pud, addr);
+                       if (pud_large(*pud)) {
+                               prot = pud_val(*pud) & _PAGE_RO;
+                               note_page(m, st, prot, 2);
+                       } else
+                               walk_pmd_level(m, st, pud, addr);
                else
                        note_page(m, st, _PAGE_INVALID, 2);
                addr += PUD_SIZE;
index 00be01c4b4f3fc3ee8242ea1e7b6921bfc6afc2a..c7ec7c2e46b0864d7010bce697c2df0f0691cf26 100644 (file)
@@ -19,7 +19,7 @@ static pte_t *walk_page_table(unsigned long addr)
        if (pgd_none(*pgdp))
                return NULL;
        pudp = pud_offset(pgdp, addr);
-       if (pud_none(*pudp))
+       if (pud_none(*pudp) || pud_large(*pudp))
                return NULL;
        pmdp = pmd_offset(pudp, addr);
        if (pmd_none(*pmdp) || pmd_large(*pmdp))
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;