aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/mm/tlb-r4k.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/mm/tlb-r4k.c')
-rw-r--r--arch/mips/mm/tlb-r4k.c70
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
22extern void build_tlb_refill_handler(void); 22extern 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. */
60void local_flush_tlb_mm(struct mm_struct *mm) 65void 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
68void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, 80void 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();