aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarkos Chandras <markos.chandras@imgtec.com>2014-11-17 04:31:07 -0500
committerRalf Baechle <ralf@linux-mips.org>2014-11-19 12:22:08 -0500
commit6a8dff6ab16c903b0d8ef5fbf21543f39bf5d675 (patch)
tree3faa8cc35a0550e326af511bce32ae69013b4830
parent58563817cfed0432e9a54476d5fc6c3aeba475e4 (diff)
MIPS: tlb-r4k: Add missing HTW stop/start sequences
HTW needs to stop and start again whenever the EntryHI register changes otherwise an inflight HTW operation might use the new EntryHI register for updating an old entry and that could lead to crashes or even a machine check exception. We fix this by ensuring the HTW has stop whenever the EntryHI register is about to change Signed-off-by: Markos Chandras <markos.chandras@imgtec.com> Cc: <stable@vger.kernel.org> # v3.17+ Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/8511/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/mm/tlb-r4k.c4
1 files changed, 4 insertions, 0 deletions
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
index fa6ebd4bc9e9..c3917e251f59 100644
--- a/arch/mips/mm/tlb-r4k.c
+++ b/arch/mips/mm/tlb-r4k.c
@@ -299,6 +299,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
299 299
300 local_irq_save(flags); 300 local_irq_save(flags);
301 301
302 htw_stop();
302 pid = read_c0_entryhi() & ASID_MASK; 303 pid = read_c0_entryhi() & ASID_MASK;
303 address &= (PAGE_MASK << 1); 304 address &= (PAGE_MASK << 1);
304 write_c0_entryhi(address | pid); 305 write_c0_entryhi(address | pid);
@@ -346,6 +347,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
346 tlb_write_indexed(); 347 tlb_write_indexed();
347 } 348 }
348 tlbw_use_hazard(); 349 tlbw_use_hazard();
350 htw_start();
349 flush_itlb_vm(vma); 351 flush_itlb_vm(vma);
350 local_irq_restore(flags); 352 local_irq_restore(flags);
351} 353}
@@ -422,6 +424,7 @@ __init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,
422 424
423 local_irq_save(flags); 425 local_irq_save(flags);
424 /* Save old context and create impossible VPN2 value */ 426 /* Save old context and create impossible VPN2 value */
427 htw_stop();
425 old_ctx = read_c0_entryhi(); 428 old_ctx = read_c0_entryhi();
426 old_pagemask = read_c0_pagemask(); 429 old_pagemask = read_c0_pagemask();
427 wired = read_c0_wired(); 430 wired = read_c0_wired();
@@ -443,6 +446,7 @@ __init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,
443 446
444 write_c0_entryhi(old_ctx); 447 write_c0_entryhi(old_ctx);
445 write_c0_pagemask(old_pagemask); 448 write_c0_pagemask(old_pagemask);
449 htw_start();
446out: 450out:
447 local_irq_restore(flags); 451 local_irq_restore(flags);
448 return ret; 452 return ret;