Commit 18da2369 authored by Heiko Carstens's avatar Heiko Carstens Committed by Martin Schwidefsky

s390/mm,vmem: use 2GB frames for identity mapping

Use 2GB frames for indentity mapping if EDAT2 is
available to reduce TLB pressure.
Signed-off-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 26d29d06
...@@ -345,6 +345,8 @@ extern unsigned long MODULES_END; ...@@ -345,6 +345,8 @@ extern unsigned long MODULES_END;
#define _REGION3_ENTRY (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_LENGTH) #define _REGION3_ENTRY (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_LENGTH)
#define _REGION3_ENTRY_EMPTY (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_INV) #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 */ /* Bits in the segment table entry */
#define _SEGMENT_ENTRY_ORIGIN ~0x7ffUL/* segment table origin */ #define _SEGMENT_ENTRY_ORIGIN ~0x7ffUL/* segment table origin */
#define _SEGMENT_ENTRY_RO 0x200 /* page protection bit */ #define _SEGMENT_ENTRY_RO 0x200 /* page protection bit */
...@@ -444,6 +446,7 @@ static inline int pgd_bad(pgd_t pgd) { return 0; } ...@@ -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_present(pud_t pud) { return 1; }
static inline int pud_none(pud_t pud) { return 0; } 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; } static inline int pud_bad(pud_t pud) { return 0; }
#else /* CONFIG_64BIT */ #else /* CONFIG_64BIT */
...@@ -489,6 +492,13 @@ static inline int pud_none(pud_t pud) ...@@ -489,6 +492,13 @@ static inline int pud_none(pud_t pud)
return (pud_val(pud) & _REGION_ENTRY_INV) != 0UL; 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) static inline int pud_bad(pud_t pud)
{ {
/* /*
......
...@@ -150,6 +150,7 @@ static void walk_pmd_level(struct seq_file *m, struct pg_state *st, ...@@ -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, static void walk_pud_level(struct seq_file *m, struct pg_state *st,
pgd_t *pgd, unsigned long addr) pgd_t *pgd, unsigned long addr)
{ {
unsigned int prot;
pud_t *pud; pud_t *pud;
int i; int i;
...@@ -157,7 +158,11 @@ static void walk_pud_level(struct seq_file *m, struct pg_state *st, ...@@ -157,7 +158,11 @@ static void walk_pud_level(struct seq_file *m, struct pg_state *st,
st->current_address = addr; st->current_address = addr;
pud = pud_offset(pgd, addr); pud = pud_offset(pgd, addr);
if (!pud_none(*pud)) 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 else
note_page(m, st, _PAGE_INVALID, 2); note_page(m, st, _PAGE_INVALID, 2);
addr += PUD_SIZE; addr += PUD_SIZE;
......
...@@ -19,7 +19,7 @@ static pte_t *walk_page_table(unsigned long addr) ...@@ -19,7 +19,7 @@ static pte_t *walk_page_table(unsigned long addr)
if (pgd_none(*pgdp)) if (pgd_none(*pgdp))
return NULL; return NULL;
pudp = pud_offset(pgdp, addr); pudp = pud_offset(pgdp, addr);
if (pud_none(*pudp)) if (pud_none(*pudp) || pud_large(*pudp))
return NULL; return NULL;
pmdp = pmd_offset(pudp, addr); pmdp = pmd_offset(pudp, addr);
if (pmd_none(*pmdp) || pmd_large(*pmdp)) if (pmd_none(*pmdp) || pmd_large(*pmdp))
......
...@@ -89,6 +89,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro) ...@@ -89,6 +89,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
int ret = -ENOMEM; int ret = -ENOMEM;
while (address < end) { while (address < end) {
pte = mk_pte_phys(address, __pgprot(ro ? _PAGE_RO : 0));
pg_dir = pgd_offset_k(address); pg_dir = pgd_offset_k(address);
if (pgd_none(*pg_dir)) { if (pgd_none(*pg_dir)) {
pu_dir = vmem_pud_alloc(); pu_dir = vmem_pud_alloc();
...@@ -96,18 +97,24 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro) ...@@ -96,18 +97,24 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
goto out; goto out;
pgd_populate(&init_mm, pg_dir, pu_dir); pgd_populate(&init_mm, pg_dir, pu_dir);
} }
pu_dir = pud_offset(pg_dir, address); 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)) { if (pud_none(*pu_dir)) {
pm_dir = vmem_pmd_alloc(); pm_dir = vmem_pmd_alloc();
if (!pm_dir) if (!pm_dir)
goto out; goto out;
pud_populate(&init_mm, pu_dir, pm_dir); 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); pm_dir = pmd_offset(pu_dir, address);
#if defined(CONFIG_64BIT) && !defined(CONFIG_DEBUG_PAGEALLOC) #if defined(CONFIG_64BIT) && !defined(CONFIG_DEBUG_PAGEALLOC)
if (MACHINE_HAS_EDAT1 && pmd_none(*pm_dir) && address && if (MACHINE_HAS_EDAT1 && pmd_none(*pm_dir) && address &&
!(address & ~PMD_MASK) && (address + PMD_SIZE <= end)) { !(address & ~PMD_MASK) && (address + PMD_SIZE <= end)) {
...@@ -160,6 +167,11 @@ static void vmem_remove_range(unsigned long start, unsigned long size) ...@@ -160,6 +167,11 @@ static void vmem_remove_range(unsigned long start, unsigned long size)
address += PUD_SIZE; address += PUD_SIZE;
continue; continue;
} }
if (pud_large(*pu_dir)) {
pud_clear(pu_dir);
address += PUD_SIZE;
continue;
}
pm_dir = pmd_offset(pu_dir, address); pm_dir = pmd_offset(pu_dir, address);
if (pmd_none(*pm_dir)) { if (pmd_none(*pm_dir)) {
address += PMD_SIZE; address += PMD_SIZE;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment