[PATCH 15/18] ARC: mm: support 3 levels of page tables

Vineet Gupta vgupta at kernel.org
Wed Aug 11 15:15:32 PDT 2021


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 <asm-generic/pgtable-nopud.h>
>>
>> 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 <vgupta at kernel.org>
>> ---
>>   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_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) from the 
pieces which remain the same. So PMD_SHIFT can be changed for a quick 
hack say but the PMD_{SIZE,MASK} etc are invariants.

-Vineet



More information about the linux-snps-arc mailing list