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