Re: [PATCH 15/18] ARC: mm: support 3 levels of page tables
On 8/11/21 5:24 AM, Mike Rapoport wrote: On Tue, Aug 10, 2021 at 05:42:55PM -0700, Vineet Gupta wrote: ARCv2 MMU is software walked and Linux implements 2 levels of paging: pgd/pte. Forthcoming hw will have multiple levels, so this change preps mm code for same. It is also fun to try multi levels even on soft-walked code to ensure generic mm code is robust to handle. overview 2 levels {pgd, pte} : pmd is folded but pmd_* macros are valid and operate on pgd 3 levels {pgd, pmd, pte}: - pud is folded and pud_* macros point to pgd - pmd_* macros operate on actual pmd code changes 1. #include 2. Define CONFIG_PGTABLE_LEVELS 3 3a. Define PMD_SHIFT, PMD_SIZE, PMD_MASK, pmd_t 3b. Define pmd_val() which actually deals with pmd (pmd_offset(), pmd_index() are provided by generic code) 3c. Define pmd_alloc_one() and pmd_free() to allocate pmd (pmd_populate/pmd_free already exist) 4. Define pud_none(), pud_bad() macros based on generic pud_val() which internally pertains to pgd now. 4b. define pud_populate() to just setup pgd Signed-off-by: Vineet Gupta --- arch/arc/Kconfig | 4 ++ arch/arc/include/asm/page.h | 11 + arch/arc/include/asm/pgalloc.h| 22 ++ arch/arc/include/asm/pgtable-levels.h | 63 --- arch/arc/include/asm/processor.h | 2 +- arch/arc/mm/fault.c | 4 ++ arch/arc/mm/tlb.c | 4 +- arch/arc/mm/tlbex.S | 9 8 files changed, 111 insertions(+), 8 deletions(-) diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index 59d5b2a179f6..43cb8aaf57a2 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -314,6 +314,10 @@ config ARC_HUGEPAGE_16M endchoice +config PGTABLE_LEVELS + int "Number of Page table levels" + default 2 + config ARC_COMPACT_IRQ_LEVELS depends on ISA_ARCOMPACT bool "Setup Timer IRQ as high Priority" diff --git a/arch/arc/include/asm/page.h b/arch/arc/include/asm/page.h index 313e6f543d2d..df3cc154ae4a 100644 --- a/arch/arc/include/asm/page.h +++ b/arch/arc/include/asm/page.h @@ -41,6 +41,17 @@ typedef struct { #define pgd_val(x)((x).pgd) #define __pgd(x) ((pgd_t) { (x) }) +#if CONFIG_PGTABLE_LEVELS > 2 + +typedef struct { + unsigned long pmd; +} pmd_t; + +#define pmd_val(x) ((x).pmd) +#define __pmd(x) ((pmd_t) { (x) }) + +#endif + typedef struct { #ifdef CONFIG_ARC_HAS_PAE40 unsigned long long pte; diff --git a/arch/arc/include/asm/pgalloc.h b/arch/arc/include/asm/pgalloc.h index 0cf73431eb89..01c2d84418ed 100644 --- a/arch/arc/include/asm/pgalloc.h +++ b/arch/arc/include/asm/pgalloc.h @@ -86,6 +86,28 @@ static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) } +#if CONFIG_PGTABLE_LEVELS > 2 + +static inline void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmdp) +{ + set_pud(pudp, __pud((unsigned long)pmdp)); +} + +static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) +{ + return (pmd_t *)__get_free_page( + GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_ZERO); +} + +static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) +{ + free_page((unsigned long)pmd); +} + +#define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tlb)->mm, pmd) + +#endif + /* * With software-only page-tables, addr-split for traversal is tweakable and * that directly governs how big tables would be at each level. diff --git a/arch/arc/include/asm/pgtable-levels.h b/arch/arc/include/asm/pgtable-levels.h index 8ece75335bb5..1c2f022d4ad0 100644 --- a/arch/arc/include/asm/pgtable-levels.h +++ b/arch/arc/include/asm/pgtable-levels.h @@ -10,6 +10,8 @@ #ifndef _ASM_ARC_PGTABLE_LEVELS_H #define _ASM_ARC_PGTABLE_LEVELS_H +#if CONFIG_PGTABLE_LEVELS == 2 + /* * 2 level paging setup for software walked MMUv3 (ARC700) and MMUv4 (HS) * @@ -37,16 +39,38 @@ #define PGDIR_SHIFT 21 #endif -#define PGDIR_SIZE BIT(PGDIR_SHIFT) /* vaddr span, not PDG sz */ -#define PGDIR_MASK (~(PGDIR_SIZE - 1)) +#else + +/* + * A default 3 level paging testing setup in software walked MMU + * MMUv4 (8K page): <4> : <7> : <8> : <13> + */ +#define PGDIR_SHIFT28 +#if CONFIG_PGTABLE_LEVELS > 2 +#define PMD_SHIFT 21 +#endif + +#endif +#define PGDIR_SIZE BIT(PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE - 1)) #define PTRS_PER_PGD BIT(32 - PGDIR_SHIFT) -#define PTRS_PER_PTE BIT(PGDIR_SHIFT - PAGE_SHIFT) +#if CONFIG_PGTABLE_LEVELS > 2 +#define PMD_SIZE BIT(PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE - 1)) +#define PTRS_PER_PMD BIT(PGDIR_SHIFT - PMD_SHIFT) Maybe move these into the previous #if CONFIG_PGTABLE_LEVELS > 2? I've kept them separate to distinguish the "configuration" parts which can be changed (for ARCv2 where this is not hardware enforced) fr
Re: [PATCH 15/18] ARC: mm: support 3 levels of page tables
On Tue, Aug 10, 2021 at 05:42:55PM -0700, Vineet Gupta wrote: > ARCv2 MMU is software walked and Linux implements 2 levels of paging: pgd/pte. > Forthcoming hw will have multiple levels, so this change preps mm code > for same. It is also fun to try multi levels even on soft-walked code to > ensure generic mm code is robust to handle. > > overview > > > 2 levels {pgd, pte} : pmd is folded but pmd_* macros are valid and operate on > pgd > 3 levels {pgd, pmd, pte}: > - pud is folded and pud_* macros point to pgd > - pmd_* macros operate on actual pmd > > code changes > > > 1. #include > > 2. Define CONFIG_PGTABLE_LEVELS 3 > > 3a. Define PMD_SHIFT, PMD_SIZE, PMD_MASK, pmd_t > 3b. Define pmd_val() which actually deals with pmd > (pmd_offset(), pmd_index() are provided by generic code) > 3c. Define pmd_alloc_one() and pmd_free() to allocate pmd > (pmd_populate/pmd_free already exist) > > 4. Define pud_none(), pud_bad() macros based on generic pud_val() which >internally pertains to pgd now. > 4b. define pud_populate() to just setup pgd > > Signed-off-by: Vineet Gupta > --- > arch/arc/Kconfig | 4 ++ > arch/arc/include/asm/page.h | 11 + > arch/arc/include/asm/pgalloc.h| 22 ++ > arch/arc/include/asm/pgtable-levels.h | 63 --- > arch/arc/include/asm/processor.h | 2 +- > arch/arc/mm/fault.c | 4 ++ > arch/arc/mm/tlb.c | 4 +- > arch/arc/mm/tlbex.S | 9 > 8 files changed, 111 insertions(+), 8 deletions(-) > > diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig > index 59d5b2a179f6..43cb8aaf57a2 100644 > --- a/arch/arc/Kconfig > +++ b/arch/arc/Kconfig > @@ -314,6 +314,10 @@ config ARC_HUGEPAGE_16M > > endchoice > > +config PGTABLE_LEVELS > + int "Number of Page table levels" > + default 2 > + > config ARC_COMPACT_IRQ_LEVELS > depends on ISA_ARCOMPACT > bool "Setup Timer IRQ as high Priority" > diff --git a/arch/arc/include/asm/page.h b/arch/arc/include/asm/page.h > index 313e6f543d2d..df3cc154ae4a 100644 > --- a/arch/arc/include/asm/page.h > +++ b/arch/arc/include/asm/page.h > @@ -41,6 +41,17 @@ typedef struct { > #define pgd_val(x) ((x).pgd) > #define __pgd(x) ((pgd_t) { (x) }) > > +#if CONFIG_PGTABLE_LEVELS > 2 > + > +typedef struct { > + unsigned long pmd; > +} pmd_t; > + > +#define pmd_val(x) ((x).pmd) > +#define __pmd(x) ((pmd_t) { (x) }) > + > +#endif > + > typedef struct { > #ifdef CONFIG_ARC_HAS_PAE40 > unsigned long long pte; > diff --git a/arch/arc/include/asm/pgalloc.h b/arch/arc/include/asm/pgalloc.h > index 0cf73431eb89..01c2d84418ed 100644 > --- a/arch/arc/include/asm/pgalloc.h > +++ b/arch/arc/include/asm/pgalloc.h > @@ -86,6 +86,28 @@ static inline void pgd_free(struct mm_struct *mm, pgd_t > *pgd) > } > > > +#if CONFIG_PGTABLE_LEVELS > 2 > + > +static inline void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t > *pmdp) > +{ > + set_pud(pudp, __pud((unsigned long)pmdp)); > +} > + > +static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) > +{ > + return (pmd_t *)__get_free_page( > + GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_ZERO); > +} > + > +static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) > +{ > + free_page((unsigned long)pmd); > +} > + > +#define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tlb)->mm, pmd) > + > +#endif > + > /* > * With software-only page-tables, addr-split for traversal is tweakable and > * that directly governs how big tables would be at each level. > diff --git a/arch/arc/include/asm/pgtable-levels.h > b/arch/arc/include/asm/pgtable-levels.h > index 8ece75335bb5..1c2f022d4ad0 100644 > --- a/arch/arc/include/asm/pgtable-levels.h > +++ b/arch/arc/include/asm/pgtable-levels.h > @@ -10,6 +10,8 @@ > #ifndef _ASM_ARC_PGTABLE_LEVELS_H > #define _ASM_ARC_PGTABLE_LEVELS_H > > +#if CONFIG_PGTABLE_LEVELS == 2 > + > /* > * 2 level paging setup for software walked MMUv3 (ARC700) and MMUv4 (HS) > * > @@ -37,16 +39,38 @@ > #define PGDIR_SHIFT 21 > #endif > > -#define PGDIR_SIZE BIT(PGDIR_SHIFT)/* vaddr span, not PDG > sz */ > -#define PGDIR_MASK (~(PGDIR_SIZE - 1)) > +#else > + > +/* > + * A default 3 level paging testing setup in software walked MMU > + * MMUv4 (8K page): <4> : <7> : <8> : <13> > + */ > +#define PGDIR_SHIFT 28 > +#if CONFIG_PGTABLE_LEVELS > 2 > +#define PMD_SHIFT21 > +#endif > + > +#endif > > +#define PGDIR_SIZE BIT(PGDIR_SHIFT) > +#define PGDIR_MASK (~(PGDIR_SIZE - 1)) > #define PTRS_PER_PGD BIT(32 - PGDIR_SHIFT) > > -#define PTRS_PER_PTE BIT(PGDIR_SHIFT - PAGE_SHIFT) > +#if CONFIG_PGTABLE_LEVELS > 2 > +#define PMD_SIZE BIT(PMD_SHIFT) > +#define PMD_MASK (~(PMD_SIZE - 1)) > +#define PTRS_PER_PMD BIT(PGDIR_SHIFT -
[PATCH 15/18] ARC: mm: support 3 levels of page tables
ARCv2 MMU is software walked and Linux implements 2 levels of paging: pgd/pte. Forthcoming hw will have multiple levels, so this change preps mm code for same. It is also fun to try multi levels even on soft-walked code to ensure generic mm code is robust to handle. overview 2 levels {pgd, pte} : pmd is folded but pmd_* macros are valid and operate on pgd 3 levels {pgd, pmd, pte}: - pud is folded and pud_* macros point to pgd - pmd_* macros operate on actual pmd code changes 1. #include 2. Define CONFIG_PGTABLE_LEVELS 3 3a. Define PMD_SHIFT, PMD_SIZE, PMD_MASK, pmd_t 3b. Define pmd_val() which actually deals with pmd (pmd_offset(), pmd_index() are provided by generic code) 3c. Define pmd_alloc_one() and pmd_free() to allocate pmd (pmd_populate/pmd_free already exist) 4. Define pud_none(), pud_bad() macros based on generic pud_val() which internally pertains to pgd now. 4b. define pud_populate() to just setup pgd Signed-off-by: Vineet Gupta --- arch/arc/Kconfig | 4 ++ arch/arc/include/asm/page.h | 11 + arch/arc/include/asm/pgalloc.h| 22 ++ arch/arc/include/asm/pgtable-levels.h | 63 --- arch/arc/include/asm/processor.h | 2 +- arch/arc/mm/fault.c | 4 ++ arch/arc/mm/tlb.c | 4 +- arch/arc/mm/tlbex.S | 9 8 files changed, 111 insertions(+), 8 deletions(-) diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index 59d5b2a179f6..43cb8aaf57a2 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -314,6 +314,10 @@ config ARC_HUGEPAGE_16M endchoice +config PGTABLE_LEVELS + int "Number of Page table levels" + default 2 + config ARC_COMPACT_IRQ_LEVELS depends on ISA_ARCOMPACT bool "Setup Timer IRQ as high Priority" diff --git a/arch/arc/include/asm/page.h b/arch/arc/include/asm/page.h index 313e6f543d2d..df3cc154ae4a 100644 --- a/arch/arc/include/asm/page.h +++ b/arch/arc/include/asm/page.h @@ -41,6 +41,17 @@ typedef struct { #define pgd_val(x) ((x).pgd) #define __pgd(x) ((pgd_t) { (x) }) +#if CONFIG_PGTABLE_LEVELS > 2 + +typedef struct { + unsigned long pmd; +} pmd_t; + +#define pmd_val(x) ((x).pmd) +#define __pmd(x) ((pmd_t) { (x) }) + +#endif + typedef struct { #ifdef CONFIG_ARC_HAS_PAE40 unsigned long long pte; diff --git a/arch/arc/include/asm/pgalloc.h b/arch/arc/include/asm/pgalloc.h index 0cf73431eb89..01c2d84418ed 100644 --- a/arch/arc/include/asm/pgalloc.h +++ b/arch/arc/include/asm/pgalloc.h @@ -86,6 +86,28 @@ static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) } +#if CONFIG_PGTABLE_LEVELS > 2 + +static inline void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmdp) +{ + set_pud(pudp, __pud((unsigned long)pmdp)); +} + +static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) +{ + return (pmd_t *)__get_free_page( + GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_ZERO); +} + +static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) +{ + free_page((unsigned long)pmd); +} + +#define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tlb)->mm, pmd) + +#endif + /* * With software-only page-tables, addr-split for traversal is tweakable and * that directly governs how big tables would be at each level. diff --git a/arch/arc/include/asm/pgtable-levels.h b/arch/arc/include/asm/pgtable-levels.h index 8ece75335bb5..1c2f022d4ad0 100644 --- a/arch/arc/include/asm/pgtable-levels.h +++ b/arch/arc/include/asm/pgtable-levels.h @@ -10,6 +10,8 @@ #ifndef _ASM_ARC_PGTABLE_LEVELS_H #define _ASM_ARC_PGTABLE_LEVELS_H +#if CONFIG_PGTABLE_LEVELS == 2 + /* * 2 level paging setup for software walked MMUv3 (ARC700) and MMUv4 (HS) * @@ -37,16 +39,38 @@ #define PGDIR_SHIFT21 #endif -#define PGDIR_SIZE BIT(PGDIR_SHIFT)/* vaddr span, not PDG sz */ -#define PGDIR_MASK (~(PGDIR_SIZE - 1)) +#else + +/* + * A default 3 level paging testing setup in software walked MMU + * MMUv4 (8K page): <4> : <7> : <8> : <13> + */ +#define PGDIR_SHIFT28 +#if CONFIG_PGTABLE_LEVELS > 2 +#define PMD_SHIFT 21 +#endif + +#endif +#define PGDIR_SIZE BIT(PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE - 1)) #define PTRS_PER_PGD BIT(32 - PGDIR_SHIFT) -#define PTRS_PER_PTE BIT(PGDIR_SHIFT - PAGE_SHIFT) +#if CONFIG_PGTABLE_LEVELS > 2 +#define PMD_SIZE BIT(PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE - 1)) +#define PTRS_PER_PMD BIT(PGDIR_SHIFT - PMD_SHIFT) +#endif + +#define PTRS_PER_PTE BIT(PMD_SHIFT - PAGE_SHIFT) #ifndef __ASSEMBLY__ +#if CONFIG_PGTABLE_LEVELS > 2 +#include +#else #include +#endif /* * 1st level paging: pgd @@ -57,9 +81,35 @@ #define pgd_ERROR(e) \ pr_crit("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e)) +