Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/mips/mm/tlb-r3k.c
10817 views
1
/*
2
* r2300.c: R2000 and R3000 specific mmu/cache code.
3
*
4
* Copyright (C) 1996 David S. Miller ([email protected])
5
*
6
* with a lot of changes to make this thing work for R3000s
7
* Tx39XX R4k style caches added. HK
8
* Copyright (C) 1998, 1999, 2000 Harald Koerfgen
9
* Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
10
* Copyright (C) 2002 Ralf Baechle
11
* Copyright (C) 2002 Maciej W. Rozycki
12
*/
13
#include <linux/init.h>
14
#include <linux/kernel.h>
15
#include <linux/sched.h>
16
#include <linux/smp.h>
17
#include <linux/mm.h>
18
19
#include <asm/page.h>
20
#include <asm/pgtable.h>
21
#include <asm/mmu_context.h>
22
#include <asm/system.h>
23
#include <asm/isadep.h>
24
#include <asm/io.h>
25
#include <asm/bootinfo.h>
26
#include <asm/cpu.h>
27
28
#undef DEBUG_TLB
29
30
extern void build_tlb_refill_handler(void);
31
32
/* CP0 hazard avoidance. */
33
#define BARRIER \
34
__asm__ __volatile__( \
35
".set push\n\t" \
36
".set noreorder\n\t" \
37
"nop\n\t" \
38
".set pop\n\t")
39
40
int r3k_have_wired_reg; /* should be in cpu_data? */
41
42
/* TLB operations. */
43
void local_flush_tlb_all(void)
44
{
45
unsigned long flags;
46
unsigned long old_ctx;
47
int entry;
48
49
#ifdef DEBUG_TLB
50
printk("[tlball]");
51
#endif
52
53
local_irq_save(flags);
54
old_ctx = read_c0_entryhi() & ASID_MASK;
55
write_c0_entrylo0(0);
56
entry = r3k_have_wired_reg ? read_c0_wired() : 8;
57
for (; entry < current_cpu_data.tlbsize; entry++) {
58
write_c0_index(entry << 8);
59
write_c0_entryhi((entry | 0x80000) << 12);
60
BARRIER;
61
tlb_write_indexed();
62
}
63
write_c0_entryhi(old_ctx);
64
local_irq_restore(flags);
65
}
66
67
void local_flush_tlb_mm(struct mm_struct *mm)
68
{
69
int cpu = smp_processor_id();
70
71
if (cpu_context(cpu, mm) != 0) {
72
#ifdef DEBUG_TLB
73
printk("[tlbmm<%lu>]", (unsigned long)cpu_context(cpu, mm));
74
#endif
75
drop_mmu_context(mm, cpu);
76
}
77
}
78
79
void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
80
unsigned long end)
81
{
82
struct mm_struct *mm = vma->vm_mm;
83
int cpu = smp_processor_id();
84
85
if (cpu_context(cpu, mm) != 0) {
86
unsigned long size, flags;
87
88
#ifdef DEBUG_TLB
89
printk("[tlbrange<%lu,0x%08lx,0x%08lx>]",
90
cpu_context(cpu, mm) & ASID_MASK, start, end);
91
#endif
92
local_irq_save(flags);
93
size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
94
if (size <= current_cpu_data.tlbsize) {
95
int oldpid = read_c0_entryhi() & ASID_MASK;
96
int newpid = cpu_context(cpu, mm) & ASID_MASK;
97
98
start &= PAGE_MASK;
99
end += PAGE_SIZE - 1;
100
end &= PAGE_MASK;
101
while (start < end) {
102
int idx;
103
104
write_c0_entryhi(start | newpid);
105
start += PAGE_SIZE; /* BARRIER */
106
tlb_probe();
107
idx = read_c0_index();
108
write_c0_entrylo0(0);
109
write_c0_entryhi(KSEG0);
110
if (idx < 0) /* BARRIER */
111
continue;
112
tlb_write_indexed();
113
}
114
write_c0_entryhi(oldpid);
115
} else {
116
drop_mmu_context(mm, cpu);
117
}
118
local_irq_restore(flags);
119
}
120
}
121
122
void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
123
{
124
unsigned long size, flags;
125
126
#ifdef DEBUG_TLB
127
printk("[tlbrange<%lu,0x%08lx,0x%08lx>]", start, end);
128
#endif
129
local_irq_save(flags);
130
size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
131
if (size <= current_cpu_data.tlbsize) {
132
int pid = read_c0_entryhi();
133
134
start &= PAGE_MASK;
135
end += PAGE_SIZE - 1;
136
end &= PAGE_MASK;
137
138
while (start < end) {
139
int idx;
140
141
write_c0_entryhi(start);
142
start += PAGE_SIZE; /* BARRIER */
143
tlb_probe();
144
idx = read_c0_index();
145
write_c0_entrylo0(0);
146
write_c0_entryhi(KSEG0);
147
if (idx < 0) /* BARRIER */
148
continue;
149
tlb_write_indexed();
150
}
151
write_c0_entryhi(pid);
152
} else {
153
local_flush_tlb_all();
154
}
155
local_irq_restore(flags);
156
}
157
158
void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
159
{
160
int cpu = smp_processor_id();
161
162
if (!vma || cpu_context(cpu, vma->vm_mm) != 0) {
163
unsigned long flags;
164
int oldpid, newpid, idx;
165
166
#ifdef DEBUG_TLB
167
printk("[tlbpage<%lu,0x%08lx>]", cpu_context(cpu, vma->vm_mm), page);
168
#endif
169
newpid = cpu_context(cpu, vma->vm_mm) & ASID_MASK;
170
page &= PAGE_MASK;
171
local_irq_save(flags);
172
oldpid = read_c0_entryhi() & ASID_MASK;
173
write_c0_entryhi(page | newpid);
174
BARRIER;
175
tlb_probe();
176
idx = read_c0_index();
177
write_c0_entrylo0(0);
178
write_c0_entryhi(KSEG0);
179
if (idx < 0) /* BARRIER */
180
goto finish;
181
tlb_write_indexed();
182
183
finish:
184
write_c0_entryhi(oldpid);
185
local_irq_restore(flags);
186
}
187
}
188
189
void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte)
190
{
191
unsigned long flags;
192
int idx, pid;
193
194
/*
195
* Handle debugger faulting in for debugee.
196
*/
197
if (current->active_mm != vma->vm_mm)
198
return;
199
200
pid = read_c0_entryhi() & ASID_MASK;
201
202
#ifdef DEBUG_TLB
203
if ((pid != (cpu_context(cpu, vma->vm_mm) & ASID_MASK)) || (cpu_context(cpu, vma->vm_mm) == 0)) {
204
printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%lu tlbpid=%d\n",
205
(cpu_context(cpu, vma->vm_mm)), pid);
206
}
207
#endif
208
209
local_irq_save(flags);
210
address &= PAGE_MASK;
211
write_c0_entryhi(address | pid);
212
BARRIER;
213
tlb_probe();
214
idx = read_c0_index();
215
write_c0_entrylo0(pte_val(pte));
216
write_c0_entryhi(address | pid);
217
if (idx < 0) { /* BARRIER */
218
tlb_write_random();
219
} else {
220
tlb_write_indexed();
221
}
222
write_c0_entryhi(pid);
223
local_irq_restore(flags);
224
}
225
226
void __init add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
227
unsigned long entryhi, unsigned long pagemask)
228
{
229
unsigned long flags;
230
unsigned long old_ctx;
231
static unsigned long wired = 0;
232
233
if (r3k_have_wired_reg) { /* TX39XX */
234
unsigned long old_pagemask;
235
unsigned long w;
236
237
#ifdef DEBUG_TLB
238
printk("[tlbwired<entry lo0 %8x, hi %8x\n, pagemask %8x>]\n",
239
entrylo0, entryhi, pagemask);
240
#endif
241
242
local_irq_save(flags);
243
/* Save old context and create impossible VPN2 value */
244
old_ctx = read_c0_entryhi() & ASID_MASK;
245
old_pagemask = read_c0_pagemask();
246
w = read_c0_wired();
247
write_c0_wired(w + 1);
248
write_c0_index(w << 8);
249
write_c0_pagemask(pagemask);
250
write_c0_entryhi(entryhi);
251
write_c0_entrylo0(entrylo0);
252
BARRIER;
253
tlb_write_indexed();
254
255
write_c0_entryhi(old_ctx);
256
write_c0_pagemask(old_pagemask);
257
local_flush_tlb_all();
258
local_irq_restore(flags);
259
260
} else if (wired < 8) {
261
#ifdef DEBUG_TLB
262
printk("[tlbwired<entry lo0 %8x, hi %8x\n>]\n",
263
entrylo0, entryhi);
264
#endif
265
266
local_irq_save(flags);
267
old_ctx = read_c0_entryhi() & ASID_MASK;
268
write_c0_entrylo0(entrylo0);
269
write_c0_entryhi(entryhi);
270
write_c0_index(wired);
271
wired++; /* BARRIER */
272
tlb_write_indexed();
273
write_c0_entryhi(old_ctx);
274
local_flush_tlb_all();
275
local_irq_restore(flags);
276
}
277
}
278
279
void __cpuinit tlb_init(void)
280
{
281
local_flush_tlb_all();
282
283
build_tlb_refill_handler();
284
}
285
286