Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -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)
{
	/*
+6 −1
Original line number Diff line number Diff line
@@ -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,6 +158,10 @@ 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))
			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);
+1 −1
Original line number Diff line number Diff line
@@ -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))
+16 −4
Original line number Diff line number Diff line
@@ -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;