3
3
#include <linux/mm.h>
4
4
#include <linux/smp.h>
5
5
#include <linux/sched.h>
6
+ #include <linux/hugetlb.h>
6
7
#include <asm/sbi.h>
7
8
#include <asm/mmu_context.h>
8
9
9
10
static inline void local_flush_tlb_all_asid (unsigned long asid )
10
11
{
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 ();
15
19
}
16
20
17
21
static inline void local_flush_tlb_page_asid (unsigned long addr ,
18
22
unsigned long asid )
19
23
{
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 );
24
31
}
25
32
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 )
28
43
{
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
+ }
33
56
}
34
57
35
58
static inline void local_flush_tlb_range_asid (unsigned long start ,
36
59
unsigned long size , unsigned long stride , unsigned long asid )
37
60
{
38
61
if (size <= stride )
39
62
local_flush_tlb_page_asid (start , asid );
40
- else
63
+ else if ( size == FLUSH_TLB_MAX_SIZE )
41
64
local_flush_tlb_all_asid (asid );
65
+ else
66
+ local_flush_tlb_range_threshold_asid (start , size , stride , asid );
42
67
}
43
68
44
69
static void __ipi_flush_tlb_all (void * info )
@@ -51,7 +76,7 @@ void flush_tlb_all(void)
51
76
if (riscv_use_ipi_for_rfence ())
52
77
on_each_cpu (__ipi_flush_tlb_all , NULL , 1 );
53
78
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 );
55
80
}
56
81
57
82
struct flush_tlb_range_data {
@@ -68,68 +93,62 @@ static void __ipi_flush_tlb_range_asid(void *info)
68
93
local_flush_tlb_range_asid (d -> start , d -> size , d -> stride , d -> asid );
69
94
}
70
95
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
-
78
96
static void __flush_tlb_range (struct mm_struct * mm , unsigned long start ,
79
97
unsigned long size , unsigned long stride )
80
98
{
81
99
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 ;
84
102
bool broadcast ;
85
103
86
- if (cpumask_empty ( cmask ))
87
- return ;
104
+ if (mm ) {
105
+ unsigned int cpuid ;
88
106
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 ;
110
117
} 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;
125
120
}
126
121
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 ();
128
140
}
129
141
130
142
void flush_tlb_mm (struct mm_struct * mm )
131
143
{
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 );
133
152
}
134
153
135
154
void 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)
140
159
void flush_tlb_range (struct vm_area_struct * vma , unsigned long start ,
141
160
unsigned long end )
142
161
{
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 );
144
194
}
195
+
145
196
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
146
197
void flush_pmd_tlb_range (struct vm_area_struct * vma , unsigned long start ,
147
198
unsigned long end )
0 commit comments