| From: Dmitry Korotin <dkorotin@wavecomp.com> |
| Date: Mon, 24 Jun 2019 19:05:27 +0000 |
| Subject: MIPS: Add missing EHB in mtc0 -> mfc0 sequence. |
| |
| commit 0b24cae4d535045f4c9e177aa228d4e97bad212c upstream. |
| |
| Add a missing EHB (Execution Hazard Barrier) in mtc0 -> mfc0 sequence. |
| Without this execution hazard barrier it's possible for the value read |
| back from the KScratch register to be the value from before the mtc0. |
| |
| Reproducible on P5600 & P6600. |
| |
| The hazard is documented in the MIPS Architecture Reference Manual Vol. |
| III: MIPS32/microMIPS32 Privileged Resource Architecture (MD00088), rev |
| 6.03 table 8.1 which includes: |
| |
| Producer | Consumer | Hazard |
| ----------|----------|---------------------------- |
| mtc0 | mfc0 | any coprocessor 0 register |
| |
| Signed-off-by: Dmitry Korotin <dkorotin@wavecomp.com> |
| [paul.burton@mips.com: |
| - Commit message tweaks. |
| - Add Fixes tags. |
| - Mark for stable back to v3.15 where P5600 support was introduced.] |
| Signed-off-by: Paul Burton <paul.burton@mips.com> |
| Fixes: 3d8bfdd03072 ("MIPS: Use C0_KScratch (if present) to hold PGD pointer.") |
| Fixes: 829dcc0a956a ("MIPS: Add MIPS P5600 probe support") |
| Cc: linux-mips@vger.kernel.org |
| [bwh: Backported to 3.16: adjust context] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| arch/mips/mm/tlbex.c | 29 ++++++++++++++++++++--------- |
| 1 file changed, 20 insertions(+), 9 deletions(-) |
| |
| --- a/arch/mips/mm/tlbex.c |
| +++ b/arch/mips/mm/tlbex.c |
| @@ -374,6 +374,7 @@ static struct work_registers build_get_w |
| static void build_restore_work_registers(u32 **p) |
| { |
| if (scratch_reg >= 0) { |
| + uasm_i_ehb(p); |
| UASM_i_MFC0(p, 1, c0_kscratch(), scratch_reg); |
| return; |
| } |
| @@ -665,10 +666,12 @@ static void build_restore_pagemask(u32 * |
| uasm_i_mtc0(p, 0, C0_PAGEMASK); |
| uasm_il_b(p, r, lid); |
| } |
| - if (scratch_reg >= 0) |
| + if (scratch_reg >= 0) { |
| + uasm_i_ehb(p); |
| UASM_i_MFC0(p, 1, c0_kscratch(), scratch_reg); |
| - else |
| + } else { |
| UASM_i_LW(p, 1, scratchpad_offset(0), 0); |
| + } |
| } else { |
| /* Reset default page size */ |
| if (PM_DEFAULT_MASK >> 16) { |
| @@ -906,10 +909,12 @@ build_get_pgd_vmalloc64(u32 **p, struct |
| uasm_i_jr(p, ptr); |
| |
| if (mode == refill_scratch) { |
| - if (scratch_reg >= 0) |
| + if (scratch_reg >= 0) { |
| + uasm_i_ehb(p); |
| UASM_i_MFC0(p, 1, c0_kscratch(), scratch_reg); |
| - else |
| + } else { |
| UASM_i_LW(p, 1, scratchpad_offset(0), 0); |
| + } |
| } else { |
| uasm_i_nop(p); |
| } |
| @@ -1215,6 +1220,7 @@ build_fast_tlb_refill_handler (u32 **p, |
| UASM_i_MTC0(p, odd, C0_ENTRYLO1); /* load it */ |
| |
| if (c0_scratch_reg >= 0) { |
| + uasm_i_ehb(p); |
| UASM_i_MFC0(p, scratch, c0_kscratch(), c0_scratch_reg); |
| build_tlb_write_entry(p, l, r, tlb_random); |
| uasm_l_leave(l, *p); |
| @@ -1466,12 +1472,14 @@ static void build_setup_pgd(void) |
| uasm_i_dinsm(&p, a0, 0, 29, 64 - 29); |
| uasm_l_tlbl_goaround1(&l, p); |
| UASM_i_SLL(&p, a0, a0, 11); |
| - uasm_i_jr(&p, 31); |
| UASM_i_MTC0(&p, a0, C0_CONTEXT); |
| + uasm_i_jr(&p, 31); |
| + uasm_i_ehb(&p); |
| } else { |
| /* PGD in c0_KScratch */ |
| - uasm_i_jr(&p, 31); |
| UASM_i_MTC0(&p, a0, c0_kscratch(), pgd_reg); |
| + uasm_i_jr(&p, 31); |
| + uasm_i_ehb(&p); |
| } |
| #else |
| #ifdef CONFIG_SMP |
| @@ -1485,13 +1493,16 @@ static void build_setup_pgd(void) |
| UASM_i_LA_mostly(&p, a2, pgdc); |
| UASM_i_SW(&p, a0, uasm_rel_lo(pgdc), a2); |
| #endif /* SMP */ |
| - uasm_i_jr(&p, 31); |
| |
| /* if pgd_reg is allocated, save PGD also to scratch register */ |
| - if (pgd_reg != -1) |
| + if (pgd_reg != -1) { |
| UASM_i_MTC0(&p, a0, c0_kscratch(), pgd_reg); |
| - else |
| + uasm_i_jr(&p, 31); |
| + uasm_i_ehb(&p); |
| + } else { |
| + uasm_i_jr(&p, 31); |
| uasm_i_nop(&p); |
| + } |
| #endif |
| if (p >= tlbmiss_handler_setup_pgd_end) |
| panic("tlbmiss_handler_setup_pgd space exceeded"); |