Skip to content

Commit 1031398

Browse files
paulburtonralfbaechle
authored andcommitted
MIPS: Mask out limit field when calculating wired entry count
Since MIPSr6 the Wired register is split into 2 fields, with the upper 16 bits of the register indicating a limit on the value that the wired entry count in the bottom 16 bits of the register can take. This means that simply reading the wired register doesn't get us a valid TLB entry index any longer, and we instead need to retrieve only the lower 16 bits of the register. Introduce a new num_wired_entries() function which does this on MIPSr6 or higher and simply returns the value of the wired register on older architecture revisions, and make use of it when reading the number of wired entries. Since commit e710d66 ("MIPS: tlb-r4k: If there are wired entries, don't use TLBINVF") we have been using a non-zero number of wired entries to determine whether we should avoid use of the tlbinvf instruction (which would invalidate wired entries) and instead loop over TLB entries in local_flush_tlb_all(). This loop begins with the number of wired entries, or before this patch some large bogus TLB index on MIPSr6 systems. Thus since the aforementioned commit some MIPSr6 systems with FTLBs have been prone to leaving stale address translations in the FTLB & crashing in various weird & wonderful ways when we later observe the wrong memory. Signed-off-by: Paul Burton <[email protected]> Cc: Matt Redfearn <[email protected]> Cc: [email protected] Patchwork: https://patchwork.linux-mips.org/patch/14557/ Signed-off-by: Ralf Baechle <[email protected]>
1 parent 9c76358 commit 1031398

File tree

4 files changed

+24
-5
lines changed

4 files changed

+24
-5
lines changed

arch/mips/include/asm/mipsregs.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,12 @@
214214
#error Bad page size configuration for hugetlbfs!
215215
#endif
216216

217+
/*
218+
* Wired register bits
219+
*/
220+
#define MIPSR6_WIRED_LIMIT (_ULCAST_(0xffff) << 16)
221+
#define MIPSR6_WIRED_WIRED (_ULCAST_(0xffff) << 0)
222+
217223
/*
218224
* Values used for computation of new tlb entries
219225
*/

arch/mips/include/asm/tlb.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#ifndef __ASM_TLB_H
22
#define __ASM_TLB_H
33

4+
#include <asm/cpu-features.h>
5+
#include <asm/mipsregs.h>
6+
47
/*
58
* MIPS doesn't need any special per-pte or per-vma handling, except
69
* we need to flush cache for area to be unmapped.
@@ -22,6 +25,16 @@
2225
((CKSEG0 + ((idx) << (PAGE_SHIFT + 1))) | \
2326
(cpu_has_tlbinv ? MIPS_ENTRYHI_EHINV : 0))
2427

28+
static inline unsigned int num_wired_entries(void)
29+
{
30+
unsigned int wired = read_c0_wired();
31+
32+
if (cpu_has_mips_r6)
33+
wired &= MIPSR6_WIRED_WIRED;
34+
35+
return wired;
36+
}
37+
2538
#include <asm-generic/tlb.h>
2639

2740
#endif /* __ASM_TLB_H */

arch/mips/mm/init.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ static void *__kmap_pgprot(struct page *page, unsigned long addr, pgprot_t prot)
118118
writex_c0_entrylo1(entrylo);
119119
}
120120
#endif
121-
tlbidx = read_c0_wired();
121+
tlbidx = num_wired_entries();
122122
write_c0_wired(tlbidx + 1);
123123
write_c0_index(tlbidx);
124124
mtc0_tlbw_hazard();
@@ -147,7 +147,7 @@ void kunmap_coherent(void)
147147

148148
local_irq_save(flags);
149149
old_ctx = read_c0_entryhi();
150-
wired = read_c0_wired() - 1;
150+
wired = num_wired_entries() - 1;
151151
write_c0_wired(wired);
152152
write_c0_index(wired);
153153
write_c0_entryhi(UNIQUE_ENTRYHI(wired));

arch/mips/mm/tlb-r4k.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ void local_flush_tlb_all(void)
6565
write_c0_entrylo0(0);
6666
write_c0_entrylo1(0);
6767

68-
entry = read_c0_wired();
68+
entry = num_wired_entries();
6969

7070
/*
7171
* Blast 'em all away.
@@ -385,7 +385,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
385385
old_ctx = read_c0_entryhi();
386386
htw_stop();
387387
old_pagemask = read_c0_pagemask();
388-
wired = read_c0_wired();
388+
wired = num_wired_entries();
389389
write_c0_wired(wired + 1);
390390
write_c0_index(wired);
391391
tlbw_use_hazard(); /* What is the hazard here? */
@@ -449,7 +449,7 @@ __init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1,
449449
htw_stop();
450450
old_ctx = read_c0_entryhi();
451451
old_pagemask = read_c0_pagemask();
452-
wired = read_c0_wired();
452+
wired = num_wired_entries();
453453
if (--temp_tlb_entry < wired) {
454454
printk(KERN_WARNING
455455
"No TLB space left for add_temporary_entry\n");

0 commit comments

Comments
 (0)