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

2021-08-11 Thread Vineet Gupta

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

2021-08-11 Thread Mike Rapoport
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

2021-08-10 Thread Vineet Gupta
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))
 
+