Unverified Commit 2bee1b58 authored by Mike Rapoport's avatar Mike Rapoport Committed by Paul Burton
Browse files

mips: add support for folded p4d page tables



Implement primitives necessary for the 4th level folding, add walks of p4d
level where appropriate, replace 5leve-fixup.h with pgtable-nop4d.h and
drop usage of __ARCH_USE_5LEVEL_HACK.

Signed-off-by: default avatarMike Rapoport <rppt@linux.ibm.com>
Signed-off-by: default avatarPaul Burton <paulburton@kernel.org>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: James Hogan <jhogan@kernel.org>
Cc: linux-mips@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-mm@kvack.org
Cc: Mike Rapoport <rppt@kernel.org>
parent 31168f03
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -70,7 +70,7 @@ enum fixed_addresses {
#include <asm-generic/fixmap.h>

#define kmap_get_fixmap_pte(vaddr)					\
	pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)), (vaddr))
	pte_offset_kernel(pmd_offset(pud_offset(p4d_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)), (vaddr)), (vaddr))

/*
 * Called from pgtable_init()
+2 −2
Original line number Diff line number Diff line
@@ -96,9 +96,9 @@ static inline void pud_free(struct mm_struct *mm, pud_t *pud)
	free_pages((unsigned long)pud, PUD_ORDER);
}

static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud)
static inline void p4d_populate(struct mm_struct *mm, p4d_t *p4d, pud_t *pud)
{
	set_pgd(pgd, __pgd((unsigned long)pud));
	set_p4d(p4d, __p4d((unsigned long)pud));
}

#define __pud_free_tlb(tlb, x, addr)	pud_free((tlb)->mm, x)
+0 −1
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@
#include <asm/cachectl.h>
#include <asm/fixmap.h>

#define __ARCH_USE_5LEVEL_HACK
#include <asm-generic/pgtable-nopmd.h>

#ifdef CONFIG_HIGHMEM
+19 −18
Original line number Diff line number Diff line
@@ -17,13 +17,12 @@
#include <asm/cachectl.h>
#include <asm/fixmap.h>

#define __ARCH_USE_5LEVEL_HACK
#if CONFIG_PGTABLE_LEVELS == 2
#include <asm-generic/pgtable-nopmd.h>
#elif CONFIG_PGTABLE_LEVELS == 3
#include <asm-generic/pgtable-nopud.h>
#else
#include <asm-generic/5level-fixup.h>
#include <asm-generic/pgtable-nop4d.h>
#endif

/*
@@ -188,47 +187,49 @@ extern pud_t invalid_pud_table[PTRS_PER_PUD];
/*
 * Empty pgd entries point to the invalid_pud_table.
 */
static inline int pgd_none(pgd_t pgd)
static inline int p4d_none(p4d_t p4d)
{
	return pgd_val(pgd) == (unsigned long)invalid_pud_table;
	return p4d_val(p4d) == (unsigned long)invalid_pud_table;
}

static inline int pgd_bad(pgd_t pgd)
static inline int p4d_bad(p4d_t p4d)
{
	if (unlikely(pgd_val(pgd) & ~PAGE_MASK))
	if (unlikely(p4d_val(p4d) & ~PAGE_MASK))
		return 1;

	return 0;
}

static inline int pgd_present(pgd_t pgd)
static inline int p4d_present(p4d_t p4d)
{
	return pgd_val(pgd) != (unsigned long)invalid_pud_table;
	return p4d_val(p4d) != (unsigned long)invalid_pud_table;
}

static inline void pgd_clear(pgd_t *pgdp)
static inline void p4d_clear(p4d_t *p4dp)
{
	pgd_val(*pgdp) = (unsigned long)invalid_pud_table;
	p4d_val(*p4dp) = (unsigned long)invalid_pud_table;
}

#define pud_index(address)	(((address) >> PUD_SHIFT) & (PTRS_PER_PUD - 1))

static inline unsigned long pgd_page_vaddr(pgd_t pgd)
static inline unsigned long p4d_page_vaddr(p4d_t p4d)
{
	return pgd_val(pgd);
	return p4d_val(p4d);
}

#define pgd_phys(pgd)		virt_to_phys((void *)pgd_val(pgd))
#define pgd_page(pgd)		(pfn_to_page(pgd_phys(pgd) >> PAGE_SHIFT))
#define p4d_phys(p4d)		virt_to_phys((void *)p4d_val(p4d))
#define p4d_page(p4d)		(pfn_to_page(p4d_phys(p4d) >> PAGE_SHIFT))

static inline pud_t *pud_offset(pgd_t *pgd, unsigned long address)
#define p4d_index(address)	(((address) >> P4D_SHIFT) & (PTRS_PER_P4D - 1))

static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address)
{
	return (pud_t *)pgd_page_vaddr(*pgd) + pud_index(address);
	return (pud_t *)p4d_page_vaddr(*p4d) + pud_index(address);
}

static inline void set_pgd(pgd_t *pgd, pgd_t pgdval)
static inline void set_p4d(p4d_t *p4d, p4d_t p4dval)
{
	*pgd = pgdval;
	*p4d = p4dval;
}

#endif
+12 −4
Original line number Diff line number Diff line
@@ -136,6 +136,7 @@ pgd_t *kvm_pgd_alloc(void)
static pte_t *kvm_mips_walk_pgd(pgd_t *pgd, struct kvm_mmu_memory_cache *cache,
				unsigned long addr)
{
	p4d_t *p4d;
	pud_t *pud;
	pmd_t *pmd;

@@ -145,7 +146,8 @@ static pte_t *kvm_mips_walk_pgd(pgd_t *pgd, struct kvm_mmu_memory_cache *cache,
		BUG();
		return NULL;
	}
	pud = pud_offset(pgd, addr);
	p4d = p4d_offset(pgd, addr);
	pud = pud_offset(p4d, addr);
	if (pud_none(*pud)) {
		pmd_t *new_pmd;

@@ -258,6 +260,7 @@ static bool kvm_mips_flush_gpa_pud(pud_t *pud, unsigned long start_gpa,
static bool kvm_mips_flush_gpa_pgd(pgd_t *pgd, unsigned long start_gpa,
				   unsigned long end_gpa)
{
	p4d_t *p4d;
	pud_t *pud;
	unsigned long end = ~0ul;
	int i_min = pgd_index(start_gpa);
@@ -269,7 +272,8 @@ static bool kvm_mips_flush_gpa_pgd(pgd_t *pgd, unsigned long start_gpa,
		if (!pgd_present(pgd[i]))
			continue;

		pud = pud_offset(pgd + i, 0);
		p4d = p4d_offset(pgd, 0);
		pud = pud_offset(p4d + i, 0);
		if (i == i_max)
			end = end_gpa;

@@ -378,6 +382,7 @@ static int kvm_mips_##name##_pgd(pgd_t *pgd, unsigned long start, \
				 unsigned long end)			\
{									\
	int ret = 0;							\
	p4d_t *p4d;							\
	pud_t *pud;							\
	unsigned long cur_end = ~0ul;					\
	int i_min = pgd_index(start);					\
@@ -388,7 +393,8 @@ static int kvm_mips_##name##_pgd(pgd_t *pgd, unsigned long start, \
		if (!pgd_present(pgd[i]))				\
			continue;					\
									\
		pud = pud_offset(pgd + i, 0);				\
		p4d = p4d_offset(pgd, 0);				\
		pud = pud_offset(p4d + i, 0);				\
		if (i == i_max)						\
			cur_end = end;					\
									\
@@ -916,6 +922,7 @@ static bool kvm_mips_flush_gva_pud(pud_t *pud, unsigned long start_gva,
static bool kvm_mips_flush_gva_pgd(pgd_t *pgd, unsigned long start_gva,
				   unsigned long end_gva)
{
	p4d_t *p4d;
	pud_t *pud;
	unsigned long end = ~0ul;
	int i_min = pgd_index(start_gva);
@@ -927,7 +934,8 @@ static bool kvm_mips_flush_gva_pgd(pgd_t *pgd, unsigned long start_gva,
		if (!pgd_present(pgd[i]))
			continue;

		pud = pud_offset(pgd + i, 0);
		p4d = p4d_offset(pgd, 0);
		pud = pud_offset(p4d + i, 0);
		if (i == i_max)
			end = end_gva;

Loading