[PATCH v3 20/34] riscv: Implement the new page table range API
Palmer Dabbelt
palmer at dabbelt.com
Tue Mar 14 22:23:43 PDT 2023
On Tue, 28 Feb 2023 13:37:23 PST (-0800), willy at infradead.org wrote:
> Add set_ptes(), update_mmu_cache_range() and flush_dcache_folio().
> Change the PG_dcache_clean flag from being per-page to per-folio.
>
> Signed-off-by: Matthew Wilcox (Oracle) <willy at infradead.org>
> Reviewed-by: Alexandre Ghiti <alexghiti at rivosinc.com>
> Cc: Paul Walmsley <paul.walmsley at sifive.com>
> Cc: Palmer Dabbelt <palmer at dabbelt.com>
> Cc: Albert Ou <aou at eecs.berkeley.edu>
> Cc: linux-riscv at lists.infradead.org
> ---
> arch/riscv/include/asm/cacheflush.h | 19 +++++++++----------
> arch/riscv/include/asm/pgtable.h | 26 +++++++++++++++++++-------
> arch/riscv/mm/cacheflush.c | 11 ++---------
> 3 files changed, 30 insertions(+), 26 deletions(-)
>
> diff --git a/arch/riscv/include/asm/cacheflush.h b/arch/riscv/include/asm/cacheflush.h
> index 03e3b95ae6da..10e5e96f09b5 100644
> --- a/arch/riscv/include/asm/cacheflush.h
> +++ b/arch/riscv/include/asm/cacheflush.h
> @@ -15,20 +15,19 @@ static inline void local_flush_icache_all(void)
>
> #define PG_dcache_clean PG_arch_1
>
> -static inline void flush_dcache_page(struct page *page)
> +static inline void flush_dcache_folio(struct folio *folio)
> {
> - /*
> - * HugeTLB pages are always fully mapped and only head page will be
> - * set PG_dcache_clean (see comments in flush_icache_pte()).
> - */
> - if (PageHuge(page))
> - page = compound_head(page);
> -
> - if (test_bit(PG_dcache_clean, &page->flags))
> - clear_bit(PG_dcache_clean, &page->flags);
> + if (test_bit(PG_dcache_clean, &folio->flags))
> + clear_bit(PG_dcache_clean, &folio->flags);
> }
> +#define flush_dcache_folio flush_dcache_folio
> #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
>
> +static inline void flush_dcache_page(struct page *page)
> +{
> + flush_dcache_folio(page_folio(page));
> +}
> +
> /*
> * RISC-V doesn't have an instruction to flush parts of the instruction cache,
> * so instead we just flush the whole thing.
> diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
> index b516f3b59616..3a3a776fc047 100644
> --- a/arch/riscv/include/asm/pgtable.h
> +++ b/arch/riscv/include/asm/pgtable.h
> @@ -405,8 +405,8 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
>
>
> /* Commit new configuration to MMU hardware */
> -static inline void update_mmu_cache(struct vm_area_struct *vma,
> - unsigned long address, pte_t *ptep)
> +static inline void update_mmu_cache_range(struct vm_area_struct *vma,
> + unsigned long address, pte_t *ptep, unsigned int nr)
> {
> /*
> * The kernel assumes that TLBs don't cache invalid entries, but
> @@ -415,8 +415,11 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
> * Relying on flush_tlb_fix_spurious_fault would suffice, but
> * the extra traps reduce performance. So, eagerly SFENCE.VMA.
> */
> - local_flush_tlb_page(address);
> + while (nr--)
> + local_flush_tlb_page(address + nr * PAGE_SIZE);
> }
> +#define update_mmu_cache(vma, addr, ptep) \
> + update_mmu_cache_range(vma, addr, ptep, 1)
>
> #define __HAVE_ARCH_UPDATE_MMU_TLB
> #define update_mmu_tlb update_mmu_cache
> @@ -456,12 +459,21 @@ static inline void __set_pte_at(struct mm_struct *mm,
> set_pte(ptep, pteval);
> }
>
> -static inline void set_pte_at(struct mm_struct *mm,
> - unsigned long addr, pte_t *ptep, pte_t pteval)
> +static inline void set_ptes(struct mm_struct *mm, unsigned long addr,
> + pte_t *ptep, pte_t pteval, unsigned int nr)
> {
> - page_table_check_ptes_set(mm, addr, ptep, pteval, 1);
> - __set_pte_at(mm, addr, ptep, pteval);
> + page_table_check_ptes_set(mm, addr, ptep, pteval, nr);
> +
> + for (;;) {
> + __set_pte_at(mm, addr, ptep, pteval);
> + if (--nr == 0)
> + break;
> + ptep++;
> + addr += PAGE_SIZE;
> + pte_val(pteval) += 1 << _PAGE_PFN_SHIFT;
> + }
> }
> +#define set_pte_at(mm, addr, ptep, pte) set_ptes(mm, addr, ptep, pte, 1)
>
> static inline void pte_clear(struct mm_struct *mm,
> unsigned long addr, pte_t *ptep)
> diff --git a/arch/riscv/mm/cacheflush.c b/arch/riscv/mm/cacheflush.c
> index fcd6145fbead..e36a851e5788 100644
> --- a/arch/riscv/mm/cacheflush.c
> +++ b/arch/riscv/mm/cacheflush.c
> @@ -81,16 +81,9 @@ void flush_icache_mm(struct mm_struct *mm, bool local)
> #ifdef CONFIG_MMU
> void flush_icache_pte(pte_t pte)
> {
> - struct page *page = pte_page(pte);
> + struct folio *folio = page_folio(pte_page(pte));
>
> - /*
> - * HugeTLB pages are always fully mapped, so only setting head page's
> - * PG_dcache_clean flag is enough.
> - */
> - if (PageHuge(page))
> - page = compound_head(page);
> -
> - if (!test_bit(PG_dcache_clean, &page->flags)) {
> + if (!test_bit(PG_dcache_clean, &folio->flags)) {
> flush_icache_all();
> set_bit(PG_dcache_clean, &page->flags);
> }
Acked-by: Palmer Dabbelt <palmer at rivosinc.com>
More information about the linux-riscv
mailing list