33#include <linux/mm.h>
44#include <linux/smp.h>
55#include <linux/sched.h>
6+ #include <linux/hugetlb.h>
67#include <asm/sbi.h>
78#include <asm/mmu_context.h>
89
910static inline void local_flush_tlb_all_asid (unsigned long asid )
1011{
11- __asm__ __volatile__ ("sfence.vma x0, %0"
12- :
13- : "r" (asid )
14- : "memory" );
12+ if (asid != FLUSH_TLB_NO_ASID )
13+ __asm__ __volatile__ ("sfence.vma x0, %0"
14+ :
15+ : "r" (asid )
16+ : "memory" );
17+ else
18+ local_flush_tlb_all ();
1519}
1620
1721static inline void local_flush_tlb_page_asid (unsigned long addr ,
1822 unsigned long asid )
1923{
20- __asm__ __volatile__ ("sfence.vma %0, %1"
21- :
22- : "r" (addr ), "r" (asid )
23- : "memory" );
24+ if (asid != FLUSH_TLB_NO_ASID )
25+ __asm__ __volatile__ ("sfence.vma %0, %1"
26+ :
27+ : "r" (addr ), "r" (asid )
28+ : "memory" );
29+ else
30+ local_flush_tlb_page (addr );
2431}
2532
26- static inline void local_flush_tlb_range (unsigned long start ,
27- unsigned long size , unsigned long stride )
33+ /*
34+ * Flush entire TLB if number of entries to be flushed is greater
35+ * than the threshold below.
36+ */
37+ static unsigned long tlb_flush_all_threshold __read_mostly = 64 ;
38+
39+ static void local_flush_tlb_range_threshold_asid (unsigned long start ,
40+ unsigned long size ,
41+ unsigned long stride ,
42+ unsigned long asid )
2843{
29- if (size <= stride )
30- local_flush_tlb_page (start );
31- else
32- local_flush_tlb_all ();
44+ unsigned long nr_ptes_in_range = DIV_ROUND_UP (size , stride );
45+ int i ;
46+
47+ if (nr_ptes_in_range > tlb_flush_all_threshold ) {
48+ local_flush_tlb_all_asid (asid );
49+ return ;
50+ }
51+
52+ for (i = 0 ; i < nr_ptes_in_range ; ++ i ) {
53+ local_flush_tlb_page_asid (start , asid );
54+ start += stride ;
55+ }
3356}
3457
3558static inline void local_flush_tlb_range_asid (unsigned long start ,
3659 unsigned long size , unsigned long stride , unsigned long asid )
3760{
3861 if (size <= stride )
3962 local_flush_tlb_page_asid (start , asid );
40- else
63+ else if ( size == FLUSH_TLB_MAX_SIZE )
4164 local_flush_tlb_all_asid (asid );
65+ else
66+ local_flush_tlb_range_threshold_asid (start , size , stride , asid );
4267}
4368
4469static void __ipi_flush_tlb_all (void * info )
@@ -51,7 +76,7 @@ void flush_tlb_all(void)
5176 if (riscv_use_ipi_for_rfence ())
5277 on_each_cpu (__ipi_flush_tlb_all , NULL , 1 );
5378 else
54- sbi_remote_sfence_vma (NULL , 0 , -1 );
79+ sbi_remote_sfence_vma_asid (NULL , 0 , FLUSH_TLB_MAX_SIZE , FLUSH_TLB_NO_ASID );
5580}
5681
5782struct flush_tlb_range_data {
@@ -68,68 +93,62 @@ static void __ipi_flush_tlb_range_asid(void *info)
6893 local_flush_tlb_range_asid (d -> start , d -> size , d -> stride , d -> asid );
6994}
7095
71- static void __ipi_flush_tlb_range (void * info )
72- {
73- struct flush_tlb_range_data * d = info ;
74-
75- local_flush_tlb_range (d -> start , d -> size , d -> stride );
76- }
77-
7896static void __flush_tlb_range (struct mm_struct * mm , unsigned long start ,
7997 unsigned long size , unsigned long stride )
8098{
8199 struct flush_tlb_range_data ftd ;
82- struct cpumask * cmask = mm_cpumask ( mm ) ;
83- unsigned int cpuid ;
100+ const struct cpumask * cmask ;
101+ unsigned long asid = FLUSH_TLB_NO_ASID ;
84102 bool broadcast ;
85103
86- if (cpumask_empty ( cmask ))
87- return ;
104+ if (mm ) {
105+ unsigned int cpuid ;
88106
89- cpuid = get_cpu ();
90- /* check if the tlbflush needs to be sent to other CPUs */
91- broadcast = cpumask_any_but (cmask , cpuid ) < nr_cpu_ids ;
92- if (static_branch_unlikely (& use_asid_allocator )) {
93- unsigned long asid = atomic_long_read (& mm -> context .id ) & asid_mask ;
94-
95- if (broadcast ) {
96- if (riscv_use_ipi_for_rfence ()) {
97- ftd .asid = asid ;
98- ftd .start = start ;
99- ftd .size = size ;
100- ftd .stride = stride ;
101- on_each_cpu_mask (cmask ,
102- __ipi_flush_tlb_range_asid ,
103- & ftd , 1 );
104- } else
105- sbi_remote_sfence_vma_asid (cmask ,
106- start , size , asid );
107- } else {
108- local_flush_tlb_range_asid (start , size , stride , asid );
109- }
107+ cmask = mm_cpumask (mm );
108+ if (cpumask_empty (cmask ))
109+ return ;
110+
111+ cpuid = get_cpu ();
112+ /* check if the tlbflush needs to be sent to other CPUs */
113+ broadcast = cpumask_any_but (cmask , cpuid ) < nr_cpu_ids ;
114+
115+ if (static_branch_unlikely (& use_asid_allocator ))
116+ asid = atomic_long_read (& mm -> context .id ) & asid_mask ;
110117 } else {
111- if (broadcast ) {
112- if (riscv_use_ipi_for_rfence ()) {
113- ftd .asid = 0 ;
114- ftd .start = start ;
115- ftd .size = size ;
116- ftd .stride = stride ;
117- on_each_cpu_mask (cmask ,
118- __ipi_flush_tlb_range ,
119- & ftd , 1 );
120- } else
121- sbi_remote_sfence_vma (cmask , start , size );
122- } else {
123- local_flush_tlb_range (start , size , stride );
124- }
118+ cmask = cpu_online_mask ;
119+ broadcast = true;
125120 }
126121
127- put_cpu ();
122+ if (broadcast ) {
123+ if (riscv_use_ipi_for_rfence ()) {
124+ ftd .asid = asid ;
125+ ftd .start = start ;
126+ ftd .size = size ;
127+ ftd .stride = stride ;
128+ on_each_cpu_mask (cmask ,
129+ __ipi_flush_tlb_range_asid ,
130+ & ftd , 1 );
131+ } else
132+ sbi_remote_sfence_vma_asid (cmask ,
133+ start , size , asid );
134+ } else {
135+ local_flush_tlb_range_asid (start , size , stride , asid );
136+ }
137+
138+ if (mm )
139+ put_cpu ();
128140}
129141
130142void flush_tlb_mm (struct mm_struct * mm )
131143{
132- __flush_tlb_range (mm , 0 , -1 , PAGE_SIZE );
144+ __flush_tlb_range (mm , 0 , FLUSH_TLB_MAX_SIZE , PAGE_SIZE );
145+ }
146+
147+ void flush_tlb_mm_range (struct mm_struct * mm ,
148+ unsigned long start , unsigned long end ,
149+ unsigned int page_size )
150+ {
151+ __flush_tlb_range (mm , start , end - start , page_size );
133152}
134153
135154void flush_tlb_page (struct vm_area_struct * vma , unsigned long addr )
@@ -140,8 +159,40 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
140159void flush_tlb_range (struct vm_area_struct * vma , unsigned long start ,
141160 unsigned long end )
142161{
143- __flush_tlb_range (vma -> vm_mm , start , end - start , PAGE_SIZE );
162+ unsigned long stride_size ;
163+
164+ if (!is_vm_hugetlb_page (vma )) {
165+ stride_size = PAGE_SIZE ;
166+ } else {
167+ stride_size = huge_page_size (hstate_vma (vma ));
168+
169+ /*
170+ * As stated in the privileged specification, every PTE in a
171+ * NAPOT region must be invalidated, so reset the stride in that
172+ * case.
173+ */
174+ if (has_svnapot ()) {
175+ if (stride_size >= PGDIR_SIZE )
176+ stride_size = PGDIR_SIZE ;
177+ else if (stride_size >= P4D_SIZE )
178+ stride_size = P4D_SIZE ;
179+ else if (stride_size >= PUD_SIZE )
180+ stride_size = PUD_SIZE ;
181+ else if (stride_size >= PMD_SIZE )
182+ stride_size = PMD_SIZE ;
183+ else
184+ stride_size = PAGE_SIZE ;
185+ }
186+ }
187+
188+ __flush_tlb_range (vma -> vm_mm , start , end - start , stride_size );
189+ }
190+
191+ void flush_tlb_kernel_range (unsigned long start , unsigned long end )
192+ {
193+ __flush_tlb_range (NULL , start , end - start , PAGE_SIZE );
144194}
195+
145196#ifdef CONFIG_TRANSPARENT_HUGEPAGE
146197void flush_pmd_tlb_range (struct vm_area_struct * vma , unsigned long start ,
147198 unsigned long end )
0 commit comments