[PATCH v10 6/7] RISC-V: Use IPIs for remote TLB flush when possible
Atish Patra
atishp at atishpatra.org
Thu Nov 3 00:00:56 PDT 2022
On Tue, Nov 1, 2022 at 7:34 AM Anup Patel <apatel at ventanamicro.com> wrote:
>
> If we have specialized interrupt controller (such as AIA IMSIC) which
> allows supervisor mode to directly inject IPIs without any assistance
> from M-mode or HS-mode then using such specialized interrupt controller,
> we can do remote TLB flushes directly from supervisor mode instead of
> using the SBI RFENCE calls.
>
> This patch extends remote TLB flush functions to use supervisor mode
> IPIs whenever direct supervisor mode IPIs.are supported by interrupt
> controller.
>
> Signed-off-by: Anup Patel <apatel at ventanamicro.com>
> ---
> arch/riscv/mm/tlbflush.c | 93 +++++++++++++++++++++++++++++++++-------
> 1 file changed, 78 insertions(+), 15 deletions(-)
>
> diff --git a/arch/riscv/mm/tlbflush.c b/arch/riscv/mm/tlbflush.c
> index 37ed760d007c..27a7db8eb2c4 100644
> --- a/arch/riscv/mm/tlbflush.c
> +++ b/arch/riscv/mm/tlbflush.c
> @@ -23,14 +23,62 @@ static inline void local_flush_tlb_page_asid(unsigned long addr,
> : "memory");
> }
>
> +static inline void local_flush_tlb_range(unsigned long start,
> + unsigned long size, unsigned long stride)
> +{
> + if (size <= stride)
> + local_flush_tlb_page(start);
> + else
> + local_flush_tlb_all();
> +}
> +
> +static inline void local_flush_tlb_range_asid(unsigned long start,
> + unsigned long size, unsigned long stride, unsigned long asid)
> +{
> + if (size <= stride)
> + local_flush_tlb_page_asid(start, asid);
> + else
> + local_flush_tlb_all_asid(asid);
> +}
> +
> +static void __ipi_flush_tlb_all(void *info)
> +{
> + local_flush_tlb_all();
> +}
> +
> void flush_tlb_all(void)
> {
> - sbi_remote_sfence_vma(NULL, 0, -1);
> + if (riscv_use_ipi_for_rfence())
> + on_each_cpu(__ipi_flush_tlb_all, NULL, 1);
> + else
> + sbi_remote_sfence_vma(NULL, 0, -1);
> +}
> +
> +struct flush_tlb_range_data {
> + unsigned long asid;
> + unsigned long start;
> + unsigned long size;
> + unsigned long stride;
> +};
> +
> +static void __ipi_flush_tlb_range_asid(void *info)
> +{
> + struct flush_tlb_range_data *d = info;
> +
> + local_flush_tlb_range_asid(d->start, d->size, d->stride, d->asid);
> +}
> +
> +static void __ipi_flush_tlb_range(void *info)
> +{
> + struct flush_tlb_range_data *d = info;
> +
> + local_flush_tlb_range(d->start, d->size, d->stride);
> }
>
> -static void __sbi_tlb_flush_range(struct mm_struct *mm, unsigned long start,
> - unsigned long size, unsigned long stride)
> +static void __flush_tlb_range(struct mm_struct *mm, unsigned long start,
> + unsigned long size, unsigned long stride)
> {
> + struct flush_tlb_range_data ftd;
> struct cpumask *cmask = mm_cpumask(mm);
> unsigned int cpuid;
> bool broadcast;
> @@ -45,19 +93,34 @@ static void __sbi_tlb_flush_range(struct mm_struct *mm, unsigned long start,
> unsigned long asid = atomic_long_read(&mm->context.id);
>
> if (broadcast) {
> - sbi_remote_sfence_vma_asid(cmask, start, size, asid);
> - } else if (size <= stride) {
> - local_flush_tlb_page_asid(start, asid);
> + if (riscv_use_ipi_for_rfence()) {
> + ftd.asid = asid;
> + ftd.start = start;
> + ftd.size = size;
> + ftd.stride = stride;
> + on_each_cpu_mask(cmask,
> + __ipi_flush_tlb_range_asid,
> + &ftd, 1);
> + } else
> + sbi_remote_sfence_vma_asid(cmask,
> + start, size, asid);
> } else {
> - local_flush_tlb_all_asid(asid);
> + local_flush_tlb_range_asid(start, size, stride, asid);
> }
> } else {
> if (broadcast) {
> - sbi_remote_sfence_vma(cmask, start, size);
> - } else if (size <= stride) {
> - local_flush_tlb_page(start);
> + if (riscv_use_ipi_for_rfence()) {
> + ftd.asid = 0;
> + ftd.start = start;
> + ftd.size = size;
> + ftd.stride = stride;
> + on_each_cpu_mask(cmask,
> + __ipi_flush_tlb_range,
> + &ftd, 1);
> + } else
> + sbi_remote_sfence_vma(cmask, start, size);
> } else {
> - local_flush_tlb_all();
> + local_flush_tlb_range(start, size, stride);
> }
> }
>
> @@ -66,23 +129,23 @@ static void __sbi_tlb_flush_range(struct mm_struct *mm, unsigned long start,
>
> void flush_tlb_mm(struct mm_struct *mm)
> {
> - __sbi_tlb_flush_range(mm, 0, -1, PAGE_SIZE);
> + __flush_tlb_range(mm, 0, -1, PAGE_SIZE);
> }
>
> void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
> {
> - __sbi_tlb_flush_range(vma->vm_mm, addr, PAGE_SIZE, PAGE_SIZE);
> + __flush_tlb_range(vma->vm_mm, addr, PAGE_SIZE, PAGE_SIZE);
> }
>
> void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
> unsigned long end)
> {
> - __sbi_tlb_flush_range(vma->vm_mm, start, end - start, PAGE_SIZE);
> + __flush_tlb_range(vma->vm_mm, start, end - start, PAGE_SIZE);
> }
> #ifdef CONFIG_TRANSPARENT_HUGEPAGE
> void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start,
> unsigned long end)
> {
> - __sbi_tlb_flush_range(vma->vm_mm, start, end - start, PMD_SIZE);
> + __flush_tlb_range(vma->vm_mm, start, end - start, PMD_SIZE);
> }
> #endif
> --
> 2.34.1
>
LGTM.
Reviewed-by: Atish Patra <atishp at rivosinc.com>
--
Regards,
Atish
More information about the linux-riscv
mailing list