[PATCH] riscv: mm: execute local TLB flush after populating vmemmap

Alexandre Ghiti alex at ghiti.fr
Thu Apr 13 07:33:20 PDT 2023


Hi Vincent,

On 4/13/23 02:48, Vincent Chen wrote:
>
>
> On Wed, Mar 22, 2023 at 12:11 AM Alexandre Ghiti <alex at ghiti.fr> wrote:
>
>     Hi Vincent,
>
>     On 3/20/23 07:53, Vincent Chen wrote:
>     > The vmemmap_populate() creates VA to PA mapping for the VMEMMAP
>     area, where
>     > all "strcut page" are located once CONFIG_SPARSEMEM_VMEMMAP is
>     defined.
>     > These "struct page" are later initialized in the zone_sizes_init()
>     > function. However, during this process, no sfence.vma instruction is
>     > executed for this VMEMMAP area. This omission may cause the core
>     to fail to
>     > perform page table work because some data related to the address
>     > translation is invisible to the core. To solve this issue, here let
>     > zone_sizes_init() call local_flush_tlb_kernel_range() to execute a
>     > sfence.vma instruction for the VMEMMAP area, ensuring that all
>     data related
>     > to the address translation is visible to the core.
>     >
>     > Signed-off-by: Vincent Chen <vincent.chen at sifive.com>
>     > ---
>     >   arch/riscv/include/asm/tlbflush.h | 7 +++++++
>     >   arch/riscv/mm/init.c              | 3 +++
>     >   2 files changed, 10 insertions(+)
>     >
>     > diff --git a/arch/riscv/include/asm/tlbflush.h
>     b/arch/riscv/include/asm/tlbflush.h
>     > index 801019381dea..b7696974e3c6 100644
>     > --- a/arch/riscv/include/asm/tlbflush.h
>     > +++ b/arch/riscv/include/asm/tlbflush.h
>     > @@ -59,4 +59,11 @@ static inline void
>     flush_tlb_kernel_range(unsigned long start,
>     >       flush_tlb_all();
>     >   }
>     >
>     > +/* Flush a range of kernel pages without broadcasting */
>     > +static inline void local_flush_tlb_kernel_range(unsigned long
>     start,
>     > +                                             unsigned long end)
>     > +{
>     > +     local_flush_tlb_all();
>     > +}
>     > +
>     >   #endif /* _ASM_RISCV_TLBFLUSH_H */
>     > diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
>     > index 2c4a64e97aec..62eea656e341 100644
>     > --- a/arch/riscv/mm/init.c
>     > +++ b/arch/riscv/mm/init.c
>     > @@ -72,6 +72,9 @@ static void __init zone_sizes_init(void)
>     >   #endif
>     >       max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
>     >
>     > +#ifdef CONFIG_SPARSEMEM_VMEMMAP
>     > +     local_flush_tlb_kernel_range(VMEMMAP_START, VMEMMAP_END);
>     > +#endif
>     >       free_area_init(max_zone_pfns);
>     >   }
>     >
>
>     Just one nit: I would have added the flush to the vmemmap_populate
>     function instead, so that we don't flush uselessly when
>     !SPARSE_VMEMMAP
>     and we know exactly why we flush.
>
>
> Sorry for the late reply.
>
> To be honest, initially, I placed the TLB flush in the 
> vmemmap_populate function like you suggested. However, I later 
> discovered that this function could be called multiple times during 
> the booting process, causing the TLB flush to be executed multiple 
> times. To improve performance, I decided to move the TLB flush to the 
> zone_sizes_init function instead, as this is where the kernel first 
> accesses the VMEMMAP region after vmemmap_populate. This allows the 
> kernel to perform only one TLB flush for the region, but the tradeoff 
> is that the code readability is reduced. Do you think this tradeoff is 
> worth it? or Maybe I can add some comments in the vmemmap_populate 
> function to describe the purpose of this TLB flush. Is it OK with you?


I see, I did not know but it is indeed called many times. To me 
zone_sizes_init() is not the right place, what about adding this flush 
(with a comment) right after sparse_init() in misc_mem_init()? So that 
if someday we move zone_sizes_init(), we don't lose the flush!

Thanks,

Alex


>
>
>     Otherwise, you can add:
>
>     Reviewed-by: Alexandre Ghiti <alexghiti at rivosinc.com>
>
>     Thanks,
>
>     Alex
>



More information about the linux-riscv mailing list