diff options
Diffstat (limited to 'arch/mips/mm/tlb-r4k.c')
-rw-r--r-- | arch/mips/mm/tlb-r4k.c | 70 |
1 files changed, 41 insertions, 29 deletions
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index 59d38bc05b69..8297970f0bb1 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c | |||
@@ -21,6 +21,12 @@ | |||
21 | 21 | ||
22 | extern void build_tlb_refill_handler(void); | 22 | extern void build_tlb_refill_handler(void); |
23 | 23 | ||
24 | /* | ||
25 | * Make sure all entries differ. If they're not different | ||
26 | * MIPS32 will take revenge ... | ||
27 | */ | ||
28 | #define UNIQUE_ENTRYHI(idx) (CKSEG0 + ((idx) << (PAGE_SHIFT + 1))) | ||
29 | |||
24 | /* CP0 hazard avoidance. */ | 30 | /* CP0 hazard avoidance. */ |
25 | #define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ | 31 | #define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ |
26 | "nop; nop; nop; nop; nop; nop;\n\t" \ | 32 | "nop; nop; nop; nop; nop; nop;\n\t" \ |
@@ -42,11 +48,8 @@ void local_flush_tlb_all(void) | |||
42 | 48 | ||
43 | /* Blast 'em all away. */ | 49 | /* Blast 'em all away. */ |
44 | while (entry < current_cpu_data.tlbsize) { | 50 | while (entry < current_cpu_data.tlbsize) { |
45 | /* | 51 | /* Make sure all entries differ. */ |
46 | * Make sure all entries differ. If they're not different | 52 | write_c0_entryhi(UNIQUE_ENTRYHI(entry)); |
47 | * MIPS32 will take revenge ... | ||
48 | */ | ||
49 | write_c0_entryhi(CKSEG0 + (entry << (PAGE_SHIFT + 1))); | ||
50 | write_c0_index(entry); | 53 | write_c0_index(entry); |
51 | mtc0_tlbw_hazard(); | 54 | mtc0_tlbw_hazard(); |
52 | tlb_write_indexed(); | 55 | tlb_write_indexed(); |
@@ -57,12 +60,21 @@ void local_flush_tlb_all(void) | |||
57 | local_irq_restore(flags); | 60 | local_irq_restore(flags); |
58 | } | 61 | } |
59 | 62 | ||
63 | /* All entries common to a mm share an asid. To effectively flush | ||
64 | these entries, we just bump the asid. */ | ||
60 | void local_flush_tlb_mm(struct mm_struct *mm) | 65 | void local_flush_tlb_mm(struct mm_struct *mm) |
61 | { | 66 | { |
62 | int cpu = smp_processor_id(); | 67 | int cpu; |
68 | |||
69 | preempt_disable(); | ||
63 | 70 | ||
64 | if (cpu_context(cpu, mm) != 0) | 71 | cpu = smp_processor_id(); |
65 | drop_mmu_context(mm,cpu); | 72 | |
73 | if (cpu_context(cpu, mm) != 0) { | ||
74 | drop_mmu_context(mm, cpu); | ||
75 | } | ||
76 | |||
77 | preempt_enable(); | ||
66 | } | 78 | } |
67 | 79 | ||
68 | void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, | 80 | void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, |
@@ -75,9 +87,9 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, | |||
75 | unsigned long flags; | 87 | unsigned long flags; |
76 | int size; | 88 | int size; |
77 | 89 | ||
78 | local_irq_save(flags); | ||
79 | size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; | 90 | size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; |
80 | size = (size + 1) >> 1; | 91 | size = (size + 1) >> 1; |
92 | local_irq_save(flags); | ||
81 | if (size <= current_cpu_data.tlbsize/2) { | 93 | if (size <= current_cpu_data.tlbsize/2) { |
82 | int oldpid = read_c0_entryhi(); | 94 | int oldpid = read_c0_entryhi(); |
83 | int newpid = cpu_asid(cpu, mm); | 95 | int newpid = cpu_asid(cpu, mm); |
@@ -99,8 +111,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, | |||
99 | if (idx < 0) | 111 | if (idx < 0) |
100 | continue; | 112 | continue; |
101 | /* Make sure all entries differ. */ | 113 | /* Make sure all entries differ. */ |
102 | write_c0_entryhi(CKSEG0 + | 114 | write_c0_entryhi(UNIQUE_ENTRYHI(idx)); |
103 | (idx << (PAGE_SHIFT + 1))); | ||
104 | mtc0_tlbw_hazard(); | 115 | mtc0_tlbw_hazard(); |
105 | tlb_write_indexed(); | 116 | tlb_write_indexed(); |
106 | } | 117 | } |
@@ -118,9 +129,9 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) | |||
118 | unsigned long flags; | 129 | unsigned long flags; |
119 | int size; | 130 | int size; |
120 | 131 | ||
121 | local_irq_save(flags); | ||
122 | size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; | 132 | size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; |
123 | size = (size + 1) >> 1; | 133 | size = (size + 1) >> 1; |
134 | local_irq_save(flags); | ||
124 | if (size <= current_cpu_data.tlbsize / 2) { | 135 | if (size <= current_cpu_data.tlbsize / 2) { |
125 | int pid = read_c0_entryhi(); | 136 | int pid = read_c0_entryhi(); |
126 | 137 | ||
@@ -142,7 +153,7 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) | |||
142 | if (idx < 0) | 153 | if (idx < 0) |
143 | continue; | 154 | continue; |
144 | /* Make sure all entries differ. */ | 155 | /* Make sure all entries differ. */ |
145 | write_c0_entryhi(CKSEG0 + (idx << (PAGE_SHIFT + 1))); | 156 | write_c0_entryhi(UNIQUE_ENTRYHI(idx)); |
146 | mtc0_tlbw_hazard(); | 157 | mtc0_tlbw_hazard(); |
147 | tlb_write_indexed(); | 158 | tlb_write_indexed(); |
148 | } | 159 | } |
@@ -176,7 +187,7 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) | |||
176 | if (idx < 0) | 187 | if (idx < 0) |
177 | goto finish; | 188 | goto finish; |
178 | /* Make sure all entries differ. */ | 189 | /* Make sure all entries differ. */ |
179 | write_c0_entryhi(CKSEG0 + (idx << (PAGE_SHIFT + 1))); | 190 | write_c0_entryhi(UNIQUE_ENTRYHI(idx)); |
180 | mtc0_tlbw_hazard(); | 191 | mtc0_tlbw_hazard(); |
181 | tlb_write_indexed(); | 192 | tlb_write_indexed(); |
182 | tlbw_use_hazard(); | 193 | tlbw_use_hazard(); |
@@ -197,8 +208,8 @@ void local_flush_tlb_one(unsigned long page) | |||
197 | int oldpid, idx; | 208 | int oldpid, idx; |
198 | 209 | ||
199 | local_irq_save(flags); | 210 | local_irq_save(flags); |
200 | page &= (PAGE_MASK << 1); | ||
201 | oldpid = read_c0_entryhi(); | 211 | oldpid = read_c0_entryhi(); |
212 | page &= (PAGE_MASK << 1); | ||
202 | write_c0_entryhi(page); | 213 | write_c0_entryhi(page); |
203 | mtc0_tlbw_hazard(); | 214 | mtc0_tlbw_hazard(); |
204 | tlb_probe(); | 215 | tlb_probe(); |
@@ -208,7 +219,7 @@ void local_flush_tlb_one(unsigned long page) | |||
208 | write_c0_entrylo1(0); | 219 | write_c0_entrylo1(0); |
209 | if (idx >= 0) { | 220 | if (idx >= 0) { |
210 | /* Make sure all entries differ. */ | 221 | /* Make sure all entries differ. */ |
211 | write_c0_entryhi(CKSEG0 + (idx << (PAGE_SHIFT + 1))); | 222 | write_c0_entryhi(UNIQUE_ENTRYHI(idx)); |
212 | mtc0_tlbw_hazard(); | 223 | mtc0_tlbw_hazard(); |
213 | tlb_write_indexed(); | 224 | tlb_write_indexed(); |
214 | tlbw_use_hazard(); | 225 | tlbw_use_hazard(); |
@@ -227,6 +238,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) | |||
227 | { | 238 | { |
228 | unsigned long flags; | 239 | unsigned long flags; |
229 | pgd_t *pgdp; | 240 | pgd_t *pgdp; |
241 | pud_t *pudp; | ||
230 | pmd_t *pmdp; | 242 | pmd_t *pmdp; |
231 | pte_t *ptep; | 243 | pte_t *ptep; |
232 | int idx, pid; | 244 | int idx, pid; |
@@ -237,35 +249,34 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) | |||
237 | if (current->active_mm != vma->vm_mm) | 249 | if (current->active_mm != vma->vm_mm) |
238 | return; | 250 | return; |
239 | 251 | ||
240 | pid = read_c0_entryhi() & ASID_MASK; | ||
241 | |||
242 | local_irq_save(flags); | 252 | local_irq_save(flags); |
253 | |||
254 | pid = read_c0_entryhi() & ASID_MASK; | ||
243 | address &= (PAGE_MASK << 1); | 255 | address &= (PAGE_MASK << 1); |
244 | write_c0_entryhi(address | pid); | 256 | write_c0_entryhi(address | pid); |
245 | pgdp = pgd_offset(vma->vm_mm, address); | 257 | pgdp = pgd_offset(vma->vm_mm, address); |
246 | mtc0_tlbw_hazard(); | 258 | mtc0_tlbw_hazard(); |
247 | tlb_probe(); | 259 | tlb_probe(); |
248 | BARRIER; | 260 | BARRIER; |
249 | pmdp = pmd_offset(pgdp, address); | 261 | pudp = pud_offset(pgdp, address); |
262 | pmdp = pmd_offset(pudp, address); | ||
250 | idx = read_c0_index(); | 263 | idx = read_c0_index(); |
251 | ptep = pte_offset_map(pmdp, address); | 264 | ptep = pte_offset_map(pmdp, address); |
252 | 265 | ||
253 | #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) | 266 | #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1) |
254 | write_c0_entrylo0(ptep->pte_high); | 267 | write_c0_entrylo0(ptep->pte_high); |
255 | ptep++; | 268 | ptep++; |
256 | write_c0_entrylo1(ptep->pte_high); | 269 | write_c0_entrylo1(ptep->pte_high); |
257 | #else | 270 | #else |
258 | write_c0_entrylo0(pte_val(*ptep++) >> 6); | 271 | write_c0_entrylo0(pte_val(*ptep++) >> 6); |
259 | write_c0_entrylo1(pte_val(*ptep) >> 6); | 272 | write_c0_entrylo1(pte_val(*ptep) >> 6); |
260 | #endif | 273 | #endif |
261 | write_c0_entryhi(address | pid); | ||
262 | mtc0_tlbw_hazard(); | 274 | mtc0_tlbw_hazard(); |
263 | if (idx < 0) | 275 | if (idx < 0) |
264 | tlb_write_random(); | 276 | tlb_write_random(); |
265 | else | 277 | else |
266 | tlb_write_indexed(); | 278 | tlb_write_indexed(); |
267 | tlbw_use_hazard(); | 279 | tlbw_use_hazard(); |
268 | write_c0_entryhi(pid); | ||
269 | local_irq_restore(flags); | 280 | local_irq_restore(flags); |
270 | } | 281 | } |
271 | 282 | ||
@@ -357,7 +368,8 @@ __init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1, | |||
357 | old_pagemask = read_c0_pagemask(); | 368 | old_pagemask = read_c0_pagemask(); |
358 | wired = read_c0_wired(); | 369 | wired = read_c0_wired(); |
359 | if (--temp_tlb_entry < wired) { | 370 | if (--temp_tlb_entry < wired) { |
360 | printk(KERN_WARNING "No TLB space left for add_temporary_entry\n"); | 371 | printk(KERN_WARNING |
372 | "No TLB space left for add_temporary_entry\n"); | ||
361 | ret = -ENOSPC; | 373 | ret = -ENOSPC; |
362 | goto out; | 374 | goto out; |
363 | } | 375 | } |
@@ -388,7 +400,7 @@ static void __init probe_tlb(unsigned long config) | |||
388 | * is not supported, we assume R4k style. Cpu probing already figured | 400 | * is not supported, we assume R4k style. Cpu probing already figured |
389 | * out the number of tlb entries. | 401 | * out the number of tlb entries. |
390 | */ | 402 | */ |
391 | if ((c->processor_id & 0xff0000) == PRID_COMP_LEGACY) | 403 | if ((c->processor_id & 0xff0000) == PRID_COMP_LEGACY) |
392 | return; | 404 | return; |
393 | 405 | ||
394 | reg = read_c0_config1(); | 406 | reg = read_c0_config1(); |