xref: /linux/arch/arm/kernel/smp_tlb.c (revision 6299e571b2d90dffcee7b58a9252f3ef29241922)
1 /*
2  *  linux/arch/arm/kernel/smp_tlb.c
3  *
4  *  Copyright (C) 2002 ARM Limited, All Rights Reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10 #include <linux/preempt.h>
11 #include <linux/smp.h>
12 
13 #include <asm/smp_plat.h>
14 #include <asm/tlbflush.h>
15 
16 /**********************************************************************/
17 
18 /*
19  * TLB operations
20  */
21 struct tlb_args {
22 	struct vm_area_struct *ta_vma;
23 	unsigned long ta_start;
24 	unsigned long ta_end;
25 };
26 
27 static inline void ipi_flush_tlb_all(void *ignored)
28 {
29 	local_flush_tlb_all();
30 }
31 
32 static inline void ipi_flush_tlb_mm(void *arg)
33 {
34 	struct mm_struct *mm = (struct mm_struct *)arg;
35 
36 	local_flush_tlb_mm(mm);
37 }
38 
39 static inline void ipi_flush_tlb_page(void *arg)
40 {
41 	struct tlb_args *ta = (struct tlb_args *)arg;
42 
43 	local_flush_tlb_page(ta->ta_vma, ta->ta_start);
44 }
45 
46 static inline void ipi_flush_tlb_kernel_page(void *arg)
47 {
48 	struct tlb_args *ta = (struct tlb_args *)arg;
49 
50 	local_flush_tlb_kernel_page(ta->ta_start);
51 }
52 
53 static inline void ipi_flush_tlb_range(void *arg)
54 {
55 	struct tlb_args *ta = (struct tlb_args *)arg;
56 
57 	local_flush_tlb_range(ta->ta_vma, ta->ta_start, ta->ta_end);
58 }
59 
60 static inline void ipi_flush_tlb_kernel_range(void *arg)
61 {
62 	struct tlb_args *ta = (struct tlb_args *)arg;
63 
64 	local_flush_tlb_kernel_range(ta->ta_start, ta->ta_end);
65 }
66 
67 static inline void ipi_flush_bp_all(void *ignored)
68 {
69 	local_flush_bp_all();
70 }
71 
72 void flush_tlb_all(void)
73 {
74 	if (tlb_ops_need_broadcast())
75 		on_each_cpu(ipi_flush_tlb_all, NULL, 1);
76 	else
77 		local_flush_tlb_all();
78 }
79 
80 void flush_tlb_mm(struct mm_struct *mm)
81 {
82 	if (tlb_ops_need_broadcast())
83 		on_each_cpu_mask(mm_cpumask(mm), ipi_flush_tlb_mm, mm, 1);
84 	else
85 		local_flush_tlb_mm(mm);
86 }
87 
88 void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
89 {
90 	if (tlb_ops_need_broadcast()) {
91 		struct tlb_args ta;
92 		ta.ta_vma = vma;
93 		ta.ta_start = uaddr;
94 		on_each_cpu_mask(mm_cpumask(vma->vm_mm), ipi_flush_tlb_page,
95 					&ta, 1);
96 	} else
97 		local_flush_tlb_page(vma, uaddr);
98 }
99 
100 void flush_tlb_kernel_page(unsigned long kaddr)
101 {
102 	if (tlb_ops_need_broadcast()) {
103 		struct tlb_args ta;
104 		ta.ta_start = kaddr;
105 		on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1);
106 	} else
107 		local_flush_tlb_kernel_page(kaddr);
108 }
109 
110 void flush_tlb_range(struct vm_area_struct *vma,
111                      unsigned long start, unsigned long end)
112 {
113 	if (tlb_ops_need_broadcast()) {
114 		struct tlb_args ta;
115 		ta.ta_vma = vma;
116 		ta.ta_start = start;
117 		ta.ta_end = end;
118 		on_each_cpu_mask(mm_cpumask(vma->vm_mm), ipi_flush_tlb_range,
119 					&ta, 1);
120 	} else
121 		local_flush_tlb_range(vma, start, end);
122 }
123 
124 void flush_tlb_kernel_range(unsigned long start, unsigned long end)
125 {
126 	if (tlb_ops_need_broadcast()) {
127 		struct tlb_args ta;
128 		ta.ta_start = start;
129 		ta.ta_end = end;
130 		on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1);
131 	} else
132 		local_flush_tlb_kernel_range(start, end);
133 }
134 
135 void flush_bp_all(void)
136 {
137 	if (tlb_ops_need_broadcast())
138 		on_each_cpu(ipi_flush_bp_all, NULL, 1);
139 	else
140 		local_flush_bp_all();
141 }
142