Commit 5637bc50 authored by Mike Rapoport's avatar Mike Rapoport Committed by David S. Miller
Browse files

sparc64: add support for folded p4d page tables



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

Signed-off-by: default avatarMike Rapoport <rppt@linux.ibm.com>
Acked-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9167bd96
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -16,12 +16,12 @@

extern struct kmem_cache *pgtable_cache;

static inline void __pgd_populate(pgd_t *pgd, pud_t *pud)
static inline void __p4d_populate(p4d_t *p4d, pud_t *pud)
{
	pgd_set(pgd, pud);
	p4d_set(p4d, pud);
}

#define pgd_populate(MM, PGD, PUD)	__pgd_populate(PGD, PUD)
#define p4d_populate(MM, P4D, PUD)	__p4d_populate(P4D, PUD)

static inline pgd_t *pgd_alloc(struct mm_struct *mm)
{
+12 −12
Original line number Diff line number Diff line
@@ -13,7 +13,7 @@
 * the SpitFire page tables.
 */

#include <asm-generic/5level-fixup.h>
#include <asm-generic/pgtable-nop4d.h>
#include <linux/compiler.h>
#include <linux/const.h>
#include <asm/types.h>
@@ -810,9 +810,9 @@ static inline int pmd_present(pmd_t pmd)

#define pud_bad(pud)			(pud_val(pud) & ~PAGE_MASK)

#define pgd_none(pgd)			(!pgd_val(pgd))
#define p4d_none(p4d)			(!p4d_val(p4d))

#define pgd_bad(pgd)			(pgd_val(pgd) & ~PAGE_MASK)
#define p4d_bad(p4d)			(p4d_val(p4d) & ~PAGE_MASK)

#ifdef CONFIG_TRANSPARENT_HUGEPAGE
void set_pmd_at(struct mm_struct *mm, unsigned long addr,
@@ -859,13 +859,13 @@ static inline unsigned long pud_page_vaddr(pud_t pud)
#define pmd_clear(pmdp)			(pmd_val(*(pmdp)) = 0UL)
#define pud_present(pud)		(pud_val(pud) != 0U)
#define pud_clear(pudp)			(pud_val(*(pudp)) = 0UL)
#define pgd_page_vaddr(pgd)		\
	((unsigned long) __va(pgd_val(pgd)))
#define pgd_present(pgd)		(pgd_val(pgd) != 0U)
#define pgd_clear(pgdp)			(pgd_val(*(pgdp)) = 0UL)
#define p4d_page_vaddr(p4d)		\
	((unsigned long) __va(p4d_val(p4d)))
#define p4d_present(p4d)		(p4d_val(p4d) != 0U)
#define p4d_clear(p4dp)			(p4d_val(*(p4dp)) = 0UL)

/* only used by the stubbed out hugetlb gup code, should never be called */
#define pgd_page(pgd)			NULL
#define p4d_page(p4d)			NULL

static inline unsigned long pud_large(pud_t pud)
{
@@ -884,8 +884,8 @@ static inline unsigned long pud_pfn(pud_t pud)
/* Same in both SUN4V and SUN4U.  */
#define pte_none(pte) 			(!pte_val(pte))

#define pgd_set(pgdp, pudp)	\
	(pgd_val(*(pgdp)) = (__pa((unsigned long) (pudp))))
#define p4d_set(p4dp, pudp)	\
	(p4d_val(*(p4dp)) = (__pa((unsigned long) (pudp))))

/* to find an entry in a page-table-directory. */
#define pgd_index(address)	(((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
@@ -896,8 +896,8 @@ static inline unsigned long pud_pfn(pud_t pud)

/* Find an entry in the third-level page table.. */
#define pud_index(address)	(((address) >> PUD_SHIFT) & (PTRS_PER_PUD - 1))
#define pud_offset(pgdp, address)	\
	((pud_t *) pgd_page_vaddr(*(pgdp)) + pud_index(address))
#define pud_offset(p4dp, address)	\
	((pud_t *) p4d_page_vaddr(*(p4dp)) + pud_index(address))

/* Find an entry in the second-level page table.. */
#define pmd_offset(pudp, address)	\
+5 −1
Original line number Diff line number Diff line
@@ -299,6 +299,7 @@ static void flush_signal_insns(unsigned long address)
	unsigned long pstate, paddr;
	pte_t *ptep, pte;
	pgd_t *pgdp;
	p4d_t *p4dp;
	pud_t *pudp;
	pmd_t *pmdp;

@@ -318,7 +319,10 @@ static void flush_signal_insns(unsigned long address)
	pgdp = pgd_offset(current->mm, address);
	if (pgd_none(*pgdp))
		goto out_irqs_on;
	pudp = pud_offset(pgdp, address);
	p4dp = p4d_offset(pgdp, address);
	if (p4d_none(*p4dp))
		goto out_irqs_on;
	pudp = pud_offset(p4dp, address);
	if (pud_none(*pudp))
		goto out_irqs_on;
	pmdp = pmd_offset(pudp, address);
+12 −1
Original line number Diff line number Diff line
@@ -1621,6 +1621,7 @@ static int __init pcpu_cpu_distance(unsigned int from, unsigned int to)
static void __init pcpu_populate_pte(unsigned long addr)
{
	pgd_t *pgd = pgd_offset_k(addr);
	p4d_t *p4d;
	pud_t *pud;
	pmd_t *pmd;

@@ -1633,7 +1634,17 @@ static void __init pcpu_populate_pte(unsigned long addr)
		pgd_populate(&init_mm, pgd, new);
	}

	pud = pud_offset(pgd, addr);
	p4d = p4d_offset(pgd, addr);
	if (p4d_none(*p4d)) {
		pud_t *new;

		new = memblock_alloc_from(PAGE_SIZE, PAGE_SIZE, PAGE_SIZE);
		if (!new)
			goto err_alloc;
		p4d_populate(&init_mm, p4d, new);
	}

	pud = pud_offset(p4d, addr);
	if (pud_none(*pud)) {
		pmd_t *new;

+5 −1
Original line number Diff line number Diff line
@@ -80,6 +80,7 @@ static void __kprobes bad_kernel_pc(struct pt_regs *regs, unsigned long vaddr)
static unsigned int get_user_insn(unsigned long tpc)
{
	pgd_t *pgdp = pgd_offset(current->mm, tpc);
	p4d_t *p4dp;
	pud_t *pudp;
	pmd_t *pmdp;
	pte_t *ptep, pte;
@@ -88,7 +89,10 @@ static unsigned int get_user_insn(unsigned long tpc)

	if (pgd_none(*pgdp) || unlikely(pgd_bad(*pgdp)))
		goto out;
	pudp = pud_offset(pgdp, tpc);
	p4dp = p4d_offset(pgdp, tpc);
	if (p4d_none(*p4dp) || unlikely(p4d_bad(*p4dp)))
		goto out;
	pudp = pud_offset(p4dp, tpc);
	if (pud_none(*pudp) || unlikely(pud_bad(*pudp)))
		goto out;

Loading