aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mm
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/arm/mm
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/arm/mm')
-rw-r--r--arch/arm/mm/Kconfig411
-rw-r--r--arch/arm/mm/Makefile56
-rw-r--r--arch/arm/mm/abort-ev4.S30
-rw-r--r--arch/arm/mm/abort-ev4t.S30
-rw-r--r--arch/arm/mm/abort-ev5t.S31
-rw-r--r--arch/arm/mm/abort-ev5tj.S35
-rw-r--r--arch/arm/mm/abort-ev6.S23
-rw-r--r--arch/arm/mm/abort-lv4t.S220
-rw-r--r--arch/arm/mm/abort-macro.S42
-rw-r--r--arch/arm/mm/alignment.c756
-rw-r--r--arch/arm/mm/blockops.c184
-rw-r--r--arch/arm/mm/cache-v3.S137
-rw-r--r--arch/arm/mm/cache-v4.S139
-rw-r--r--arch/arm/mm/cache-v4wb.S216
-rw-r--r--arch/arm/mm/cache-v4wt.S188
-rw-r--r--arch/arm/mm/cache-v6.S227
-rw-r--r--arch/arm/mm/consistent.c451
-rw-r--r--arch/arm/mm/copypage-v3.S67
-rw-r--r--arch/arm/mm/copypage-v4mc.S80
-rw-r--r--arch/arm/mm/copypage-v4wb.S79
-rw-r--r--arch/arm/mm/copypage-v4wt.S73
-rw-r--r--arch/arm/mm/copypage-v6.c155
-rw-r--r--arch/arm/mm/copypage-xscale.S113
-rw-r--r--arch/arm/mm/discontig.c49
-rw-r--r--arch/arm/mm/extable.c16
-rw-r--r--arch/arm/mm/fault-armv.c223
-rw-r--r--arch/arm/mm/fault.c462
-rw-r--r--arch/arm/mm/fault.h6
-rw-r--r--arch/arm/mm/flush.c94
-rw-r--r--arch/arm/mm/init.c621
-rw-r--r--arch/arm/mm/ioremap.c172
-rw-r--r--arch/arm/mm/minicache.c73
-rw-r--r--arch/arm/mm/mm-armv.c760
-rw-r--r--arch/arm/mm/mmap.c109
-rw-r--r--arch/arm/mm/mmu.c45
-rw-r--r--arch/arm/mm/proc-arm1020.S530
-rw-r--r--arch/arm/mm/proc-arm1020e.S513
-rw-r--r--arch/arm/mm/proc-arm1022.S495
-rw-r--r--arch/arm/mm/proc-arm1026.S491
-rw-r--r--arch/arm/mm/proc-arm6_7.S404
-rw-r--r--arch/arm/mm/proc-arm720.S267
-rw-r--r--arch/arm/mm/proc-arm920.S480
-rw-r--r--arch/arm/mm/proc-arm922.S484
-rw-r--r--arch/arm/mm/proc-arm925.S562
-rw-r--r--arch/arm/mm/proc-arm926.S495
-rw-r--r--arch/arm/mm/proc-macros.S51
-rw-r--r--arch/arm/mm/proc-sa110.S272
-rw-r--r--arch/arm/mm/proc-sa1100.S323
-rw-r--r--arch/arm/mm/proc-syms.c40
-rw-r--r--arch/arm/mm/proc-v6.S272
-rw-r--r--arch/arm/mm/proc-xscale.S934
-rw-r--r--arch/arm/mm/tlb-v3.S52
-rw-r--r--arch/arm/mm/tlb-v4.S65
-rw-r--r--arch/arm/mm/tlb-v4wb.S77
-rw-r--r--arch/arm/mm/tlb-v4wbi.S68
-rw-r--r--arch/arm/mm/tlb-v6.S92
56 files changed, 13340 insertions, 0 deletions
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
new file mode 100644
index 000000000000..5b670c9ac5ef
--- /dev/null
+++ b/arch/arm/mm/Kconfig
@@ -0,0 +1,411 @@
1comment "Processor Type"
2
3config CPU_32
4 bool
5 default y
6
7# Select CPU types depending on the architecture selected. This selects
8# which CPUs we support in the kernel image, and the compiler instruction
9# optimiser behaviour.
10
11# ARM610
12config CPU_ARM610
13 bool "Support ARM610 processor"
14 depends on ARCH_RPC
15 select CPU_32v3
16 select CPU_CACHE_V3
17 select CPU_CACHE_VIVT
18 select CPU_COPY_V3
19 select CPU_TLB_V3
20 help
21 The ARM610 is the successor to the ARM3 processor
22 and was produced by VLSI Technology Inc.
23
24 Say Y if you want support for the ARM610 processor.
25 Otherwise, say N.
26
27# ARM710
28config CPU_ARM710
29 bool "Support ARM710 processor" if !ARCH_CLPS7500 && ARCH_RPC
30 default y if ARCH_CLPS7500
31 select CPU_32v3
32 select CPU_CACHE_V3
33 select CPU_CACHE_VIVT
34 select CPU_COPY_V3
35 select CPU_TLB_V3
36 help
37 A 32-bit RISC microprocessor based on the ARM7 processor core
38 designed by Advanced RISC Machines Ltd. The ARM710 is the
39 successor to the ARM610 processor. It was released in
40 July 1994 by VLSI Technology Inc.
41
42 Say Y if you want support for the ARM710 processor.
43 Otherwise, say N.
44
45# ARM720T
46config CPU_ARM720T
47 bool "Support ARM720T processor" if !ARCH_CLPS711X && !ARCH_L7200 && !ARCH_CDB89712 && ARCH_INTEGRATOR
48 default y if ARCH_CLPS711X || ARCH_L7200 || ARCH_CDB89712 || ARCH_H720X
49 select CPU_32v4
50 select CPU_ABRT_LV4T
51 select CPU_CACHE_V4
52 select CPU_CACHE_VIVT
53 select CPU_COPY_V4WT
54 select CPU_TLB_V4WT
55 help
56 A 32-bit RISC processor with 8kByte Cache, Write Buffer and
57 MMU built around an ARM7TDMI core.
58
59 Say Y if you want support for the ARM720T processor.
60 Otherwise, say N.
61
62# ARM920T
63config CPU_ARM920T
64 bool "Support ARM920T processor" if !ARCH_S3C2410
65 depends on ARCH_INTEGRATOR || ARCH_S3C2410 || ARCH_IMX
66 default y if ARCH_S3C2410
67 select CPU_32v4
68 select CPU_ABRT_EV4T
69 select CPU_CACHE_V4WT
70 select CPU_CACHE_VIVT
71 select CPU_COPY_V4WB
72 select CPU_TLB_V4WBI
73 help
74 The ARM920T is licensed to be produced by numerous vendors,
75 and is used in the Maverick EP9312 and the Samsung S3C2410.
76
77 More information on the Maverick EP9312 at
78 <http://linuxdevices.com/products/PD2382866068.html>.
79
80 Say Y if you want support for the ARM920T processor.
81 Otherwise, say N.
82
83# ARM922T
84config CPU_ARM922T
85 bool "Support ARM922T processor" if ARCH_INTEGRATOR
86 depends on ARCH_CAMELOT || ARCH_LH7A40X || ARCH_INTEGRATOR
87 default y if ARCH_CAMELOT || ARCH_LH7A40X
88 select CPU_32v4
89 select CPU_ABRT_EV4T
90 select CPU_CACHE_V4WT
91 select CPU_CACHE_VIVT
92 select CPU_COPY_V4WB
93 select CPU_TLB_V4WBI
94 help
95 The ARM922T is a version of the ARM920T, but with smaller
96 instruction and data caches. It is used in Altera's
97 Excalibur XA device family.
98
99 Say Y if you want support for the ARM922T processor.
100 Otherwise, say N.
101
102# ARM925T
103config CPU_ARM925T
104 bool "Support ARM925T processor" if ARCH_OMAP
105 depends on ARCH_OMAP1510
106 default y if ARCH_OMAP1510
107 select CPU_32v4
108 select CPU_ABRT_EV4T
109 select CPU_CACHE_V4WT
110 select CPU_CACHE_VIVT
111 select CPU_COPY_V4WB
112 select CPU_TLB_V4WBI
113 help
114 The ARM925T is a mix between the ARM920T and ARM926T, but with
115 different instruction and data caches. It is used in TI's OMAP
116 device family.
117
118 Say Y if you want support for the ARM925T processor.
119 Otherwise, say N.
120
121# ARM926T
122config CPU_ARM926T
123 bool "Support ARM926T processor" if ARCH_INTEGRATOR
124 depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX
125 default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX
126 select CPU_32v5
127 select CPU_ABRT_EV5TJ
128 select CPU_CACHE_VIVT
129 select CPU_COPY_V4WB
130 select CPU_TLB_V4WBI
131 help
132 This is a variant of the ARM920. It has slightly different
133 instruction sequences for cache and TLB operations. Curiously,
134 there is no documentation on it at the ARM corporate website.
135
136 Say Y if you want support for the ARM926T processor.
137 Otherwise, say N.
138
139# ARM1020 - needs validating
140config CPU_ARM1020
141 bool "Support ARM1020T (rev 0) processor"
142 depends on ARCH_INTEGRATOR
143 select CPU_32v5
144 select CPU_ABRT_EV4T
145 select CPU_CACHE_V4WT
146 select CPU_CACHE_VIVT
147 select CPU_COPY_V4WB
148 select CPU_TLB_V4WBI
149 help
150 The ARM1020 is the 32K cached version of the ARM10 processor,
151 with an addition of a floating-point unit.
152
153 Say Y if you want support for the ARM1020 processor.
154 Otherwise, say N.
155
156# ARM1020E - needs validating
157config CPU_ARM1020E
158 bool "Support ARM1020E processor"
159 depends on ARCH_INTEGRATOR
160 select CPU_32v5
161 select CPU_ABRT_EV4T
162 select CPU_CACHE_V4WT
163 select CPU_CACHE_VIVT
164 select CPU_COPY_V4WB
165 select CPU_TLB_V4WBI
166 depends on n
167
168# ARM1022E
169config CPU_ARM1022
170 bool "Support ARM1022E processor"
171 depends on ARCH_INTEGRATOR
172 select CPU_32v5
173 select CPU_ABRT_EV4T
174 select CPU_CACHE_VIVT
175 select CPU_COPY_V4WB # can probably do better
176 select CPU_TLB_V4WBI
177 help
178 The ARM1022E is an implementation of the ARMv5TE architecture
179 based upon the ARM10 integer core with a 16KiB L1 Harvard cache,
180 embedded trace macrocell, and a floating-point unit.
181
182 Say Y if you want support for the ARM1022E processor.
183 Otherwise, say N.
184
185# ARM1026EJ-S
186config CPU_ARM1026
187 bool "Support ARM1026EJ-S processor"
188 depends on ARCH_INTEGRATOR
189 select CPU_32v5
190 select CPU_ABRT_EV5T # But need Jazelle, but EV5TJ ignores bit 10
191 select CPU_CACHE_VIVT
192 select CPU_COPY_V4WB # can probably do better
193 select CPU_TLB_V4WBI
194 help
195 The ARM1026EJ-S is an implementation of the ARMv5TEJ architecture
196 based upon the ARM10 integer core.
197
198 Say Y if you want support for the ARM1026EJ-S processor.
199 Otherwise, say N.
200
201# SA110
202config CPU_SA110
203 bool "Support StrongARM(R) SA-110 processor" if !ARCH_EBSA110 && !FOOTBRIDGE && !ARCH_TBOX && !ARCH_SHARK && !ARCH_NEXUSPCI && ARCH_RPC
204 default y if ARCH_EBSA110 || FOOTBRIDGE || ARCH_TBOX || ARCH_SHARK || ARCH_NEXUSPCI
205 select CPU_32v3 if ARCH_RPC
206 select CPU_32v4 if !ARCH_RPC
207 select CPU_ABRT_EV4
208 select CPU_CACHE_V4WB
209 select CPU_CACHE_VIVT
210 select CPU_COPY_V4WB
211 select CPU_TLB_V4WB
212 help
213 The Intel StrongARM(R) SA-110 is a 32-bit microprocessor and
214 is available at five speeds ranging from 100 MHz to 233 MHz.
215 More information is available at
216 <http://developer.intel.com/design/strong/sa110.htm>.
217
218 Say Y if you want support for the SA-110 processor.
219 Otherwise, say N.
220
221# SA1100
222config CPU_SA1100
223 bool
224 depends on ARCH_SA1100
225 default y
226 select CPU_32v4
227 select CPU_ABRT_EV4
228 select CPU_CACHE_V4WB
229 select CPU_CACHE_VIVT
230 select CPU_TLB_V4WB
231 select CPU_MINICACHE
232
233# XScale
234config CPU_XSCALE
235 bool
236 depends on ARCH_IOP3XX || ARCH_PXA || ARCH_IXP4XX || ARCH_IXP2000
237 default y
238 select CPU_32v5
239 select CPU_ABRT_EV5T
240 select CPU_CACHE_VIVT
241 select CPU_TLB_V4WBI
242 select CPU_MINICACHE
243
244# ARMv6
245config CPU_V6
246 bool "Support ARM V6 processor"
247 depends on ARCH_INTEGRATOR
248 select CPU_32v6
249 select CPU_ABRT_EV6
250 select CPU_CACHE_V6
251 select CPU_CACHE_VIPT
252 select CPU_COPY_V6
253 select CPU_TLB_V6
254
255# Figure out what processor architecture version we should be using.
256# This defines the compiler instruction set which depends on the machine type.
257config CPU_32v3
258 bool
259
260config CPU_32v4
261 bool
262
263config CPU_32v5
264 bool
265
266config CPU_32v6
267 bool
268
269# The abort model
270config CPU_ABRT_EV4
271 bool
272
273config CPU_ABRT_EV4T
274 bool
275
276config CPU_ABRT_LV4T
277 bool
278
279config CPU_ABRT_EV5T
280 bool
281
282config CPU_ABRT_EV5TJ
283 bool
284
285config CPU_ABRT_EV6
286 bool
287
288# The cache model
289config CPU_CACHE_V3
290 bool
291
292config CPU_CACHE_V4
293 bool
294
295config CPU_CACHE_V4WT
296 bool
297
298config CPU_CACHE_V4WB
299 bool
300
301config CPU_CACHE_V6
302 bool
303
304config CPU_CACHE_VIVT
305 bool
306
307config CPU_CACHE_VIPT
308 bool
309
310# The copy-page model
311config CPU_COPY_V3
312 bool
313
314config CPU_COPY_V4WT
315 bool
316
317config CPU_COPY_V4WB
318 bool
319
320config CPU_COPY_V6
321 bool
322
323# This selects the TLB model
324config CPU_TLB_V3
325 bool
326 help
327 ARM Architecture Version 3 TLB.
328
329config CPU_TLB_V4WT
330 bool
331 help
332 ARM Architecture Version 4 TLB with writethrough cache.
333
334config CPU_TLB_V4WB
335 bool
336 help
337 ARM Architecture Version 4 TLB with writeback cache.
338
339config CPU_TLB_V4WBI
340 bool
341 help
342 ARM Architecture Version 4 TLB with writeback cache and invalidate
343 instruction cache entry.
344
345config CPU_TLB_V6
346 bool
347
348config CPU_MINICACHE
349 bool
350 help
351 Processor has a minicache.
352
353comment "Processor Features"
354
355config ARM_THUMB
356 bool "Support Thumb user binaries"
357 depends on CPU_ARM720T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_V6
358 default y
359 help
360 Say Y if you want to include kernel support for running user space
361 Thumb binaries.
362
363 The Thumb instruction set is a compressed form of the standard ARM
364 instruction set resulting in smaller binaries at the expense of
365 slightly less efficient code.
366
367 If you don't know what this all is, saying Y is a safe choice.
368
369config CPU_BIG_ENDIAN
370 bool "Build big-endian kernel"
371 depends on ARCH_SUPPORTS_BIG_ENDIAN
372 help
373 Say Y if you plan on running a kernel in big-endian mode.
374 Note that your board must be properly built and your board
375 port must properly enable any big-endian related features
376 of your chipset/board/processor.
377
378config CPU_ICACHE_DISABLE
379 bool "Disable I-Cache"
380 depends on CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM1020
381 help
382 Say Y here to disable the processor instruction cache. Unless
383 you have a reason not to or are unsure, say N.
384
385config CPU_DCACHE_DISABLE
386 bool "Disable D-Cache"
387 depends on CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM1020
388 help
389 Say Y here to disable the processor data cache. Unless
390 you have a reason not to or are unsure, say N.
391
392config CPU_DCACHE_WRITETHROUGH
393 bool "Force write through D-cache"
394 depends on (CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM1020) && !CPU_DISABLE_DCACHE
395 default y if CPU_ARM925T
396 help
397 Say Y here to use the data cache in writethrough mode. Unless you
398 specifically require this or are unsure, say N.
399
400config CPU_CACHE_ROUND_ROBIN
401 bool "Round robin I and D cache replacement algorithm"
402 depends on (CPU_ARM926T || CPU_ARM1020) && (!CPU_ICACHE_DISABLE || !CPU_DCACHE_DISABLE)
403 help
404 Say Y here to use the predictable round-robin cache replacement
405 policy. Unless you specifically require this or are unsure, say N.
406
407config CPU_BPREDICT_DISABLE
408 bool "Disable branch prediction"
409 depends on CPU_ARM1020
410 help
411 Say Y here to disable branch prediction. If unsure, say N.
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
new file mode 100644
index 000000000000..ccf316c11e02
--- /dev/null
+++ b/arch/arm/mm/Makefile
@@ -0,0 +1,56 @@
1#
2# Makefile for the linux arm-specific parts of the memory manager.
3#
4
5obj-y := consistent.o extable.o fault-armv.o \
6 fault.o flush.o init.o ioremap.o mmap.o \
7 mm-armv.o
8
9obj-$(CONFIG_MODULES) += proc-syms.o
10
11obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o
12obj-$(CONFIG_DISCONTIGMEM) += discontig.o
13
14obj-$(CONFIG_CPU_ABRT_EV4) += abort-ev4.o
15obj-$(CONFIG_CPU_ABRT_EV4T) += abort-ev4t.o
16obj-$(CONFIG_CPU_ABRT_LV4T) += abort-lv4t.o
17obj-$(CONFIG_CPU_ABRT_EV5T) += abort-ev5t.o
18obj-$(CONFIG_CPU_ABRT_EV5TJ) += abort-ev5tj.o
19obj-$(CONFIG_CPU_ABRT_EV6) += abort-ev6.o
20
21obj-$(CONFIG_CPU_CACHE_V3) += cache-v3.o
22obj-$(CONFIG_CPU_CACHE_V4) += cache-v4.o
23obj-$(CONFIG_CPU_CACHE_V4WT) += cache-v4wt.o
24obj-$(CONFIG_CPU_CACHE_V4WB) += cache-v4wb.o
25obj-$(CONFIG_CPU_CACHE_V6) += cache-v6.o
26
27obj-$(CONFIG_CPU_COPY_V3) += copypage-v3.o
28obj-$(CONFIG_CPU_COPY_V4WT) += copypage-v4wt.o
29obj-$(CONFIG_CPU_COPY_V4WB) += copypage-v4wb.o
30obj-$(CONFIG_CPU_COPY_V6) += copypage-v6.o mmu.o
31obj-$(CONFIG_CPU_SA1100) += copypage-v4mc.o
32obj-$(CONFIG_CPU_XSCALE) += copypage-xscale.o
33
34obj-$(CONFIG_CPU_MINICACHE) += minicache.o
35
36obj-$(CONFIG_CPU_TLB_V3) += tlb-v3.o
37obj-$(CONFIG_CPU_TLB_V4WT) += tlb-v4.o
38obj-$(CONFIG_CPU_TLB_V4WB) += tlb-v4wb.o
39obj-$(CONFIG_CPU_TLB_V4WBI) += tlb-v4wbi.o
40obj-$(CONFIG_CPU_TLB_V6) += tlb-v6.o
41
42obj-$(CONFIG_CPU_ARM610) += proc-arm6_7.o
43obj-$(CONFIG_CPU_ARM710) += proc-arm6_7.o
44obj-$(CONFIG_CPU_ARM720T) += proc-arm720.o
45obj-$(CONFIG_CPU_ARM920T) += proc-arm920.o
46obj-$(CONFIG_CPU_ARM922T) += proc-arm922.o
47obj-$(CONFIG_CPU_ARM925T) += proc-arm925.o
48obj-$(CONFIG_CPU_ARM926T) += proc-arm926.o
49obj-$(CONFIG_CPU_ARM1020) += proc-arm1020.o
50obj-$(CONFIG_CPU_ARM1020E) += proc-arm1020e.o
51obj-$(CONFIG_CPU_ARM1022) += proc-arm1022.o
52obj-$(CONFIG_CPU_ARM1026) += proc-arm1026.o
53obj-$(CONFIG_CPU_SA110) += proc-sa110.o
54obj-$(CONFIG_CPU_SA1100) += proc-sa1100.o
55obj-$(CONFIG_CPU_XSCALE) += proc-xscale.o
56obj-$(CONFIG_CPU_V6) += proc-v6.o blockops.o
diff --git a/arch/arm/mm/abort-ev4.S b/arch/arm/mm/abort-ev4.S
new file mode 100644
index 000000000000..4f18f9e87bae
--- /dev/null
+++ b/arch/arm/mm/abort-ev4.S
@@ -0,0 +1,30 @@
1#include <linux/linkage.h>
2#include <asm/assembler.h>
3/*
4 * Function: v4_early_abort
5 *
6 * Params : r2 = address of aborted instruction
7 * : r3 = saved SPSR
8 *
9 * Returns : r0 = address of abort
10 * : r1 = FSR, bit 11 = write
11 * : r2-r8 = corrupted
12 * : r9 = preserved
13 * : sp = pointer to registers
14 *
15 * Purpose : obtain information about current aborted instruction.
16 * Note: we read user space. This means we might cause a data
17 * abort here if the I-TLB and D-TLB aren't seeing the same
18 * picture. Unfortunately, this does happen. We live with it.
19 */
20 .align 5
21ENTRY(v4_early_abort)
22 mrc p15, 0, r1, c5, c0, 0 @ get FSR
23 mrc p15, 0, r0, c6, c0, 0 @ get FAR
24 ldr r3, [r2] @ read aborted ARM instruction
25 bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR
26 tst r3, #1 << 20 @ L = 1 -> write?
27 orreq r1, r1, #1 << 11 @ yes.
28 mov pc, lr
29
30
diff --git a/arch/arm/mm/abort-ev4t.S b/arch/arm/mm/abort-ev4t.S
new file mode 100644
index 000000000000..b6282548f922
--- /dev/null
+++ b/arch/arm/mm/abort-ev4t.S
@@ -0,0 +1,30 @@
1#include <linux/linkage.h>
2#include <asm/assembler.h>
3#include "abort-macro.S"
4/*
5 * Function: v4t_early_abort
6 *
7 * Params : r2 = address of aborted instruction
8 * : r3 = saved SPSR
9 *
10 * Returns : r0 = address of abort
11 * : r1 = FSR, bit 11 = write
12 * : r2-r8 = corrupted
13 * : r9 = preserved
14 * : sp = pointer to registers
15 *
16 * Purpose : obtain information about current aborted instruction.
17 * Note: we read user space. This means we might cause a data
18 * abort here if the I-TLB and D-TLB aren't seeing the same
19 * picture. Unfortunately, this does happen. We live with it.
20 */
21 .align 5
22ENTRY(v4t_early_abort)
23 mrc p15, 0, r1, c5, c0, 0 @ get FSR
24 mrc p15, 0, r0, c6, c0, 0 @ get FAR
25 do_thumb_abort
26 ldreq r3, [r2] @ read aborted ARM instruction
27 bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR
28 tst r3, #1 << 20 @ check write
29 orreq r1, r1, #1 << 11
30 mov pc, lr
diff --git a/arch/arm/mm/abort-ev5t.S b/arch/arm/mm/abort-ev5t.S
new file mode 100644
index 000000000000..02251b526c0d
--- /dev/null
+++ b/arch/arm/mm/abort-ev5t.S
@@ -0,0 +1,31 @@
1#include <linux/linkage.h>
2#include <asm/assembler.h>
3#include "abort-macro.S"
4/*
5 * Function: v5t_early_abort
6 *
7 * Params : r2 = address of aborted instruction
8 * : r3 = saved SPSR
9 *
10 * Returns : r0 = address of abort
11 * : r1 = FSR, bit 11 = write
12 * : r2-r8 = corrupted
13 * : r9 = preserved
14 * : sp = pointer to registers
15 *
16 * Purpose : obtain information about current aborted instruction.
17 * Note: we read user space. This means we might cause a data
18 * abort here if the I-TLB and D-TLB aren't seeing the same
19 * picture. Unfortunately, this does happen. We live with it.
20 */
21 .align 5
22ENTRY(v5t_early_abort)
23 mrc p15, 0, r1, c5, c0, 0 @ get FSR
24 mrc p15, 0, r0, c6, c0, 0 @ get FAR
25 do_thumb_abort
26 ldreq r3, [r2] @ read aborted ARM instruction
27 bic r1, r1, #1 << 11 @ clear bits 11 of FSR
28 do_ldrd_abort
29 tst r3, #1 << 20 @ check write
30 orreq r1, r1, #1 << 11
31 mov pc, lr
diff --git a/arch/arm/mm/abort-ev5tj.S b/arch/arm/mm/abort-ev5tj.S
new file mode 100644
index 000000000000..bce68d601c8b
--- /dev/null
+++ b/arch/arm/mm/abort-ev5tj.S
@@ -0,0 +1,35 @@
1#include <linux/linkage.h>
2#include <asm/assembler.h>
3#include "abort-macro.S"
4/*
5 * Function: v5tj_early_abort
6 *
7 * Params : r2 = address of aborted instruction
8 * : r3 = saved SPSR
9 *
10 * Returns : r0 = address of abort
11 * : r1 = FSR, bit 11 = write
12 * : r2-r8 = corrupted
13 * : r9 = preserved
14 * : sp = pointer to registers
15 *
16 * Purpose : obtain information about current aborted instruction.
17 * Note: we read user space. This means we might cause a data
18 * abort here if the I-TLB and D-TLB aren't seeing the same
19 * picture. Unfortunately, this does happen. We live with it.
20 */
21 .align 5
22ENTRY(v5tj_early_abort)
23 mrc p15, 0, r1, c5, c0, 0 @ get FSR
24 mrc p15, 0, r0, c6, c0, 0 @ get FAR
25 bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR
26 tst r3, #PSR_J_BIT @ Java?
27 movne pc, lr
28 do_thumb_abort
29 ldreq r3, [r2] @ read aborted ARM instruction
30 do_ldrd_abort
31 tst r3, #1 << 20 @ L = 0 -> write
32 orreq r1, r1, #1 << 11 @ yes.
33 mov pc, lr
34
35
diff --git a/arch/arm/mm/abort-ev6.S b/arch/arm/mm/abort-ev6.S
new file mode 100644
index 000000000000..38b2cbb89beb
--- /dev/null
+++ b/arch/arm/mm/abort-ev6.S
@@ -0,0 +1,23 @@
1#include <linux/linkage.h>
2#include <asm/assembler.h>
3/*
4 * Function: v6_early_abort
5 *
6 * Params : r2 = address of aborted instruction
7 * : r3 = saved SPSR
8 *
9 * Returns : r0 = address of abort
10 * : r1 = FSR, bit 11 = write
11 * : r2-r8 = corrupted
12 * : r9 = preserved
13 * : sp = pointer to registers
14 *
15 * Purpose : obtain information about current aborted instruction.
16 */
17 .align 5
18ENTRY(v6_early_abort)
19 mrc p15, 0, r1, c5, c0, 0 @ get FSR
20 mrc p15, 0, r0, c6, c0, 0 @ get FAR
21 mov pc, lr
22
23
diff --git a/arch/arm/mm/abort-lv4t.S b/arch/arm/mm/abort-lv4t.S
new file mode 100644
index 000000000000..db743e510214
--- /dev/null
+++ b/arch/arm/mm/abort-lv4t.S
@@ -0,0 +1,220 @@
1#include <linux/linkage.h>
2#include <asm/assembler.h>
3/*
4 * Function: v4t_late_abort
5 *
6 * Params : r2 = address of aborted instruction
7 * : r3 = saved SPSR
8 *
9 * Returns : r0 = address of abort
10 * : r1 = FSR, bit 11 = write
11 * : r2-r8 = corrupted
12 * : r9 = preserved
13 * : sp = pointer to registers
14 *
15 * Purpose : obtain information about current aborted instruction.
16 * Note: we read user space. This means we might cause a data
17 * abort here if the I-TLB and D-TLB aren't seeing the same
18 * picture. Unfortunately, this does happen. We live with it.
19 */
20ENTRY(v4t_late_abort)
21 tst r3, #PSR_T_BIT @ check for thumb mode
22 mrc p15, 0, r1, c5, c0, 0 @ get FSR
23 mrc p15, 0, r0, c6, c0, 0 @ get FAR
24 bne .data_thumb_abort
25 ldr r8, [r2] @ read arm instruction
26 bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR
27 tst r8, #1 << 20 @ L = 1 -> write?
28 orreq r1, r1, #1 << 11 @ yes.
29 and r7, r8, #15 << 24
30 add pc, pc, r7, lsr #22 @ Now branch to the relevant processing routine
31 nop
32
33/* 0 */ b .data_arm_lateldrhpost @ ldrh rd, [rn], #m/rm
34/* 1 */ b .data_arm_lateldrhpre @ ldrh rd, [rn, #m/rm]
35/* 2 */ b .data_unknown
36/* 3 */ b .data_unknown
37/* 4 */ b .data_arm_lateldrpostconst @ ldr rd, [rn], #m
38/* 5 */ b .data_arm_lateldrpreconst @ ldr rd, [rn, #m]
39/* 6 */ b .data_arm_lateldrpostreg @ ldr rd, [rn], rm
40/* 7 */ b .data_arm_lateldrprereg @ ldr rd, [rn, rm]
41/* 8 */ b .data_arm_ldmstm @ ldm*a rn, <rlist>
42/* 9 */ b .data_arm_ldmstm @ ldm*b rn, <rlist>
43/* a */ b .data_unknown
44/* b */ b .data_unknown
45/* c */ mov pc, lr @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m
46/* d */ mov pc, lr @ ldc rd, [rn, #m]
47/* e */ b .data_unknown
48/* f */
49.data_unknown: @ Part of jumptable
50 mov r0, r2
51 mov r1, r8
52 mov r2, sp
53 bl baddataabort
54 b ret_from_exception
55
56.data_arm_ldmstm:
57 tst r8, #1 << 21 @ check writeback bit
58 moveq pc, lr @ no writeback -> no fixup
59 mov r7, #0x11
60 orr r7, r7, #0x1100
61 and r6, r8, r7
62 and r2, r8, r7, lsl #1
63 add r6, r6, r2, lsr #1
64 and r2, r8, r7, lsl #2
65 add r6, r6, r2, lsr #2
66 and r2, r8, r7, lsl #3
67 add r6, r6, r2, lsr #3
68 add r6, r6, r6, lsr #8
69 add r6, r6, r6, lsr #4
70 and r6, r6, #15 @ r6 = no. of registers to transfer.
71 and r5, r8, #15 << 16 @ Extract 'n' from instruction
72 ldr r7, [sp, r5, lsr #14] @ Get register 'Rn'
73 tst r8, #1 << 23 @ Check U bit
74 subne r7, r7, r6, lsl #2 @ Undo increment
75 addeq r7, r7, r6, lsl #2 @ Undo decrement
76 str r7, [sp, r5, lsr #14] @ Put register 'Rn'
77 mov pc, lr
78
79.data_arm_lateldrhpre:
80 tst r8, #1 << 21 @ Check writeback bit
81 moveq pc, lr @ No writeback -> no fixup
82.data_arm_lateldrhpost:
83 and r5, r8, #0x00f @ get Rm / low nibble of immediate value
84 tst r8, #1 << 22 @ if (immediate offset)
85 andne r6, r8, #0xf00 @ { immediate high nibble
86 orrne r6, r5, r6, lsr #4 @ combine nibbles } else
87 ldreq r6, [sp, r5, lsl #2] @ { load Rm value }
88.data_arm_apply_r6_and_rn:
89 and r5, r8, #15 << 16 @ Extract 'n' from instruction
90 ldr r7, [sp, r5, lsr #14] @ Get register 'Rn'
91 tst r8, #1 << 23 @ Check U bit
92 subne r7, r7, r6 @ Undo incrmenet
93 addeq r7, r7, r6 @ Undo decrement
94 str r7, [sp, r5, lsr #14] @ Put register 'Rn'
95 mov pc, lr
96
97.data_arm_lateldrpreconst:
98 tst r8, #1 << 21 @ check writeback bit
99 moveq pc, lr @ no writeback -> no fixup
100.data_arm_lateldrpostconst:
101 movs r2, r8, lsl #20 @ Get offset
102 moveq pc, lr @ zero -> no fixup
103 and r5, r8, #15 << 16 @ Extract 'n' from instruction
104 ldr r7, [sp, r5, lsr #14] @ Get register 'Rn'
105 tst r8, #1 << 23 @ Check U bit
106 subne r7, r7, r2, lsr #20 @ Undo increment
107 addeq r7, r7, r2, lsr #20 @ Undo decrement
108 str r7, [sp, r5, lsr #14] @ Put register 'Rn'
109 mov pc, lr
110
111.data_arm_lateldrprereg:
112 tst r8, #1 << 21 @ check writeback bit
113 moveq pc, lr @ no writeback -> no fixup
114.data_arm_lateldrpostreg:
115 and r7, r8, #15 @ Extract 'm' from instruction
116 ldr r6, [sp, r7, lsl #2] @ Get register 'Rm'
117 mov r5, r8, lsr #7 @ get shift count
118 ands r5, r5, #31
119 and r7, r8, #0x70 @ get shift type
120 orreq r7, r7, #8 @ shift count = 0
121 add pc, pc, r7
122 nop
123
124 mov r6, r6, lsl r5 @ 0: LSL #!0
125 b .data_arm_apply_r6_and_rn
126 b .data_arm_apply_r6_and_rn @ 1: LSL #0
127 nop
128 b .data_unknown @ 2: MUL?
129 nop
130 b .data_unknown @ 3: MUL?
131 nop
132 mov r6, r6, lsr r5 @ 4: LSR #!0
133 b .data_arm_apply_r6_and_rn
134 mov r6, r6, lsr #32 @ 5: LSR #32
135 b .data_arm_apply_r6_and_rn
136 b .data_unknown @ 6: MUL?
137 nop
138 b .data_unknown @ 7: MUL?
139 nop
140 mov r6, r6, asr r5 @ 8: ASR #!0
141 b .data_arm_apply_r6_and_rn
142 mov r6, r6, asr #32 @ 9: ASR #32
143 b .data_arm_apply_r6_and_rn
144 b .data_unknown @ A: MUL?
145 nop
146 b .data_unknown @ B: MUL?
147 nop
148 mov r6, r6, ror r5 @ C: ROR #!0
149 b .data_arm_apply_r6_and_rn
150 mov r6, r6, rrx @ D: RRX
151 b .data_arm_apply_r6_and_rn
152 b .data_unknown @ E: MUL?
153 nop
154 b .data_unknown @ F: MUL?
155
156.data_thumb_abort:
157 ldrh r8, [r2] @ read instruction
158 tst r8, #1 << 11 @ L = 1 -> write?
159 orreq r1, r1, #1 << 8 @ yes
160 and r7, r8, #15 << 12
161 add pc, pc, r7, lsr #10 @ lookup in table
162 nop
163
164/* 0 */ b .data_unknown
165/* 1 */ b .data_unknown
166/* 2 */ b .data_unknown
167/* 3 */ b .data_unknown
168/* 4 */ b .data_unknown
169/* 5 */ b .data_thumb_reg
170/* 6 */ mov pc, lr
171/* 7 */ mov pc, lr
172/* 8 */ mov pc, lr
173/* 9 */ mov pc, lr
174/* A */ b .data_unknown
175/* B */ b .data_thumb_pushpop
176/* C */ b .data_thumb_ldmstm
177/* D */ b .data_unknown
178/* E */ b .data_unknown
179/* F */ b .data_unknown
180
181.data_thumb_reg:
182 tst r8, #1 << 9
183 moveq pc, lr
184 tst r8, #1 << 10 @ If 'S' (signed) bit is set
185 movne r1, #0 @ it must be a load instr
186 mov pc, lr
187
188.data_thumb_pushpop:
189 tst r8, #1 << 10
190 beq .data_unknown
191 and r6, r8, #0x55 @ hweight8(r8) + R bit
192 and r2, r8, #0xaa
193 add r6, r6, r2, lsr #1
194 and r2, r6, #0xcc
195 and r6, r6, #0x33
196 add r6, r6, r2, lsr #2
197 movs r7, r8, lsr #9 @ C = r8 bit 8 (R bit)
198 adc r6, r6, r6, lsr #4 @ high + low nibble + R bit
199 and r6, r6, #15 @ number of regs to transfer
200 ldr r7, [sp, #13 << 2]
201 tst r8, #1 << 11
202 addeq r7, r7, r6, lsl #2 @ increment SP if PUSH
203 subne r7, r7, r6, lsl #2 @ decrement SP if POP
204 str r7, [sp, #13 << 2]
205 mov pc, lr
206
207.data_thumb_ldmstm:
208 and r6, r8, #0x55 @ hweight8(r8)
209 and r2, r8, #0xaa
210 add r6, r6, r2, lsr #1
211 and r2, r6, #0xcc
212 and r6, r6, #0x33
213 add r6, r6, r2, lsr #2
214 add r6, r6, r6, lsr #4
215 and r5, r8, #7 << 8
216 ldr r7, [sp, r5, lsr #6]
217 and r6, r6, #15 @ number of regs to transfer
218 sub r7, r7, r6, lsl #2 @ always decrement
219 str r7, [sp, r5, lsr #6]
220 mov pc, lr
diff --git a/arch/arm/mm/abort-macro.S b/arch/arm/mm/abort-macro.S
new file mode 100644
index 000000000000..d7cb1bfa51a4
--- /dev/null
+++ b/arch/arm/mm/abort-macro.S
@@ -0,0 +1,42 @@
1/*
2 * The ARM LDRD and Thumb LDRSB instructions use bit 20/11 (ARM/Thumb)
3 * differently than every other instruction, so it is set to 0 (write)
4 * even though the instructions are read instructions. This means that
5 * during an abort the instructions will be treated as a write and the
6 * handler will raise a signal from unwriteable locations if they
7 * fault. We have to specifically check for these instructions
8 * from the abort handlers to treat them properly.
9 *
10 */
11
12 .macro do_thumb_abort
13 tst r3, #PSR_T_BIT
14 beq not_thumb
15 ldrh r3, [r2] @ Read aborted Thumb instruction
16 and r3, r3, # 0xfe00 @ Mask opcode field
17 cmp r3, # 0x5600 @ Is it ldrsb?
18 orreq r3, r3, #1 << 11 @ Set L-bit if yes
19 tst r3, #1 << 11 @ L = 0 -> write
20 orreq r1, r1, #1 << 11 @ yes.
21 mov pc, lr
22not_thumb:
23 .endm
24
25/*
26 * We check for the following insturction encoding for LDRD.
27 *
28 * [27:25] == 0
29 * [7:4] == 1101
30 * [20] == 0
31 */
32 .macro do_ldrd_abort
33 tst r3, #0x0e000000 @ [27:25] == 0
34 bne not_ldrd
35 and r2, r3, #0x000000f0 @ [7:4] == 1101
36 cmp r2, #0x000000d0
37 bne not_ldrd
38 tst r3, #1 << 20 @ [20] == 0
39 moveq pc, lr
40not_ldrd:
41 .endm
42
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
new file mode 100644
index 000000000000..81f4a8a2d34b
--- /dev/null
+++ b/arch/arm/mm/alignment.c
@@ -0,0 +1,756 @@
1/*
2 * linux/arch/arm/mm/alignment.c
3 *
4 * Copyright (C) 1995 Linus Torvalds
5 * Modifications for ARM processor (c) 1995-2001 Russell King
6 * Thumb aligment fault fixups (c) 2004 MontaVista Software, Inc.
7 * - Adapted from gdb/sim/arm/thumbemu.c -- Thumb instruction emulation.
8 * Copyright (C) 1996, Cygnus Software Technologies Ltd.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14#include <linux/config.h>
15#include <linux/compiler.h>
16#include <linux/kernel.h>
17#include <linux/errno.h>
18#include <linux/string.h>
19#include <linux/ptrace.h>
20#include <linux/proc_fs.h>
21#include <linux/init.h>
22
23#include <asm/uaccess.h>
24#include <asm/unaligned.h>
25
26#include "fault.h"
27
28/*
29 * 32-bit misaligned trap handler (c) 1998 San Mehat (CCC) -July 1998
30 * /proc/sys/debug/alignment, modified and integrated into
31 * Linux 2.1 by Russell King
32 *
33 * Speed optimisations and better fault handling by Russell King.
34 *
35 * *** NOTE ***
36 * This code is not portable to processors with late data abort handling.
37 */
38#define CODING_BITS(i) (i & 0x0e000000)
39
40#define LDST_I_BIT(i) (i & (1 << 26)) /* Immediate constant */
41#define LDST_P_BIT(i) (i & (1 << 24)) /* Preindex */
42#define LDST_U_BIT(i) (i & (1 << 23)) /* Add offset */
43#define LDST_W_BIT(i) (i & (1 << 21)) /* Writeback */
44#define LDST_L_BIT(i) (i & (1 << 20)) /* Load */
45
46#define LDST_P_EQ_U(i) ((((i) ^ ((i) >> 1)) & (1 << 23)) == 0)
47
48#define LDSTH_I_BIT(i) (i & (1 << 22)) /* half-word immed */
49#define LDM_S_BIT(i) (i & (1 << 22)) /* write CPSR from SPSR */
50
51#define RN_BITS(i) ((i >> 16) & 15) /* Rn */
52#define RD_BITS(i) ((i >> 12) & 15) /* Rd */
53#define RM_BITS(i) (i & 15) /* Rm */
54
55#define REGMASK_BITS(i) (i & 0xffff)
56#define OFFSET_BITS(i) (i & 0x0fff)
57
58#define IS_SHIFT(i) (i & 0x0ff0)
59#define SHIFT_BITS(i) ((i >> 7) & 0x1f)
60#define SHIFT_TYPE(i) (i & 0x60)
61#define SHIFT_LSL 0x00
62#define SHIFT_LSR 0x20
63#define SHIFT_ASR 0x40
64#define SHIFT_RORRRX 0x60
65
66static unsigned long ai_user;
67static unsigned long ai_sys;
68static unsigned long ai_skipped;
69static unsigned long ai_half;
70static unsigned long ai_word;
71static unsigned long ai_multi;
72static int ai_usermode;
73
74#ifdef CONFIG_PROC_FS
75static const char *usermode_action[] = {
76 "ignored",
77 "warn",
78 "fixup",
79 "fixup+warn",
80 "signal",
81 "signal+warn"
82};
83
84static int
85proc_alignment_read(char *page, char **start, off_t off, int count, int *eof,
86 void *data)
87{
88 char *p = page;
89 int len;
90
91 p += sprintf(p, "User:\t\t%lu\n", ai_user);
92 p += sprintf(p, "System:\t\t%lu\n", ai_sys);
93 p += sprintf(p, "Skipped:\t%lu\n", ai_skipped);
94 p += sprintf(p, "Half:\t\t%lu\n", ai_half);
95 p += sprintf(p, "Word:\t\t%lu\n", ai_word);
96 p += sprintf(p, "Multi:\t\t%lu\n", ai_multi);
97 p += sprintf(p, "User faults:\t%i (%s)\n", ai_usermode,
98 usermode_action[ai_usermode]);
99
100 len = (p - page) - off;
101 if (len < 0)
102 len = 0;
103
104 *eof = (len <= count) ? 1 : 0;
105 *start = page + off;
106
107 return len;
108}
109
110static int proc_alignment_write(struct file *file, const char __user *buffer,
111 unsigned long count, void *data)
112{
113 char mode;
114
115 if (count > 0) {
116 if (get_user(mode, buffer))
117 return -EFAULT;
118 if (mode >= '0' && mode <= '5')
119 ai_usermode = mode - '0';
120 }
121 return count;
122}
123
124#endif /* CONFIG_PROC_FS */
125
126union offset_union {
127 unsigned long un;
128 signed long sn;
129};
130
131#define TYPE_ERROR 0
132#define TYPE_FAULT 1
133#define TYPE_LDST 2
134#define TYPE_DONE 3
135
136#ifdef __ARMEB__
137#define BE 1
138#define FIRST_BYTE_16 "mov %1, %1, ror #8\n"
139#define FIRST_BYTE_32 "mov %1, %1, ror #24\n"
140#define NEXT_BYTE "ror #24"
141#else
142#define BE 0
143#define FIRST_BYTE_16
144#define FIRST_BYTE_32
145#define NEXT_BYTE "lsr #8"
146#endif
147
148#define __get8_unaligned_check(ins,val,addr,err) \
149 __asm__( \
150 "1: "ins" %1, [%2], #1\n" \
151 "2:\n" \
152 " .section .fixup,\"ax\"\n" \
153 " .align 2\n" \
154 "3: mov %0, #1\n" \
155 " b 2b\n" \
156 " .previous\n" \
157 " .section __ex_table,\"a\"\n" \
158 " .align 3\n" \
159 " .long 1b, 3b\n" \
160 " .previous\n" \
161 : "=r" (err), "=&r" (val), "=r" (addr) \
162 : "0" (err), "2" (addr))
163
164#define __get16_unaligned_check(ins,val,addr) \
165 do { \
166 unsigned int err = 0, v, a = addr; \
167 __get8_unaligned_check(ins,v,a,err); \
168 val = v << ((BE) ? 8 : 0); \
169 __get8_unaligned_check(ins,v,a,err); \
170 val |= v << ((BE) ? 0 : 8); \
171 if (err) \
172 goto fault; \
173 } while (0)
174
175#define get16_unaligned_check(val,addr) \
176 __get16_unaligned_check("ldrb",val,addr)
177
178#define get16t_unaligned_check(val,addr) \
179 __get16_unaligned_check("ldrbt",val,addr)
180
181#define __get32_unaligned_check(ins,val,addr) \
182 do { \
183 unsigned int err = 0, v, a = addr; \
184 __get8_unaligned_check(ins,v,a,err); \
185 val = v << ((BE) ? 24 : 0); \
186 __get8_unaligned_check(ins,v,a,err); \
187 val |= v << ((BE) ? 16 : 8); \
188 __get8_unaligned_check(ins,v,a,err); \
189 val |= v << ((BE) ? 8 : 16); \
190 __get8_unaligned_check(ins,v,a,err); \
191 val |= v << ((BE) ? 0 : 24); \
192 if (err) \
193 goto fault; \
194 } while (0)
195
196#define get32_unaligned_check(val,addr) \
197 __get32_unaligned_check("ldrb",val,addr)
198
199#define get32t_unaligned_check(val,addr) \
200 __get32_unaligned_check("ldrbt",val,addr)
201
202#define __put16_unaligned_check(ins,val,addr) \
203 do { \
204 unsigned int err = 0, v = val, a = addr; \
205 __asm__( FIRST_BYTE_16 \
206 "1: "ins" %1, [%2], #1\n" \
207 " mov %1, %1, "NEXT_BYTE"\n" \
208 "2: "ins" %1, [%2]\n" \
209 "3:\n" \
210 " .section .fixup,\"ax\"\n" \
211 " .align 2\n" \
212 "4: mov %0, #1\n" \
213 " b 3b\n" \
214 " .previous\n" \
215 " .section __ex_table,\"a\"\n" \
216 " .align 3\n" \
217 " .long 1b, 4b\n" \
218 " .long 2b, 4b\n" \
219 " .previous\n" \
220 : "=r" (err), "=&r" (v), "=&r" (a) \
221 : "0" (err), "1" (v), "2" (a)); \
222 if (err) \
223 goto fault; \
224 } while (0)
225
226#define put16_unaligned_check(val,addr) \
227 __put16_unaligned_check("strb",val,addr)
228
229#define put16t_unaligned_check(val,addr) \
230 __put16_unaligned_check("strbt",val,addr)
231
232#define __put32_unaligned_check(ins,val,addr) \
233 do { \
234 unsigned int err = 0, v = val, a = addr; \
235 __asm__( FIRST_BYTE_32 \
236 "1: "ins" %1, [%2], #1\n" \
237 " mov %1, %1, "NEXT_BYTE"\n" \
238 "2: "ins" %1, [%2], #1\n" \
239 " mov %1, %1, "NEXT_BYTE"\n" \
240 "3: "ins" %1, [%2], #1\n" \
241 " mov %1, %1, "NEXT_BYTE"\n" \
242 "4: "ins" %1, [%2]\n" \
243 "5:\n" \
244 " .section .fixup,\"ax\"\n" \
245 " .align 2\n" \
246 "6: mov %0, #1\n" \
247 " b 5b\n" \
248 " .previous\n" \
249 " .section __ex_table,\"a\"\n" \
250 " .align 3\n" \
251 " .long 1b, 6b\n" \
252 " .long 2b, 6b\n" \
253 " .long 3b, 6b\n" \
254 " .long 4b, 6b\n" \
255 " .previous\n" \
256 : "=r" (err), "=&r" (v), "=&r" (a) \
257 : "0" (err), "1" (v), "2" (a)); \
258 if (err) \
259 goto fault; \
260 } while (0)
261
262#define put32_unaligned_check(val,addr) \
263 __put32_unaligned_check("strb", val, addr)
264
265#define put32t_unaligned_check(val,addr) \
266 __put32_unaligned_check("strbt", val, addr)
267
268static void
269do_alignment_finish_ldst(unsigned long addr, unsigned long instr, struct pt_regs *regs, union offset_union offset)
270{
271 if (!LDST_U_BIT(instr))
272 offset.un = -offset.un;
273
274 if (!LDST_P_BIT(instr))
275 addr += offset.un;
276
277 if (!LDST_P_BIT(instr) || LDST_W_BIT(instr))
278 regs->uregs[RN_BITS(instr)] = addr;
279}
280
281static int
282do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *regs)
283{
284 unsigned int rd = RD_BITS(instr);
285
286 if ((instr & 0x01f00ff0) == 0x01000090)
287 goto swp;
288
289 if ((instr & 0x90) != 0x90 || (instr & 0x60) == 0)
290 goto bad;
291
292 ai_half += 1;
293
294 if (user_mode(regs))
295 goto user;
296
297 if (LDST_L_BIT(instr)) {
298 unsigned long val;
299 get16_unaligned_check(val, addr);
300
301 /* signed half-word? */
302 if (instr & 0x40)
303 val = (signed long)((signed short) val);
304
305 regs->uregs[rd] = val;
306 } else
307 put16_unaligned_check(regs->uregs[rd], addr);
308
309 return TYPE_LDST;
310
311 user:
312 if (LDST_L_BIT(instr)) {
313 unsigned long val;
314 get16t_unaligned_check(val, addr);
315
316 /* signed half-word? */
317 if (instr & 0x40)
318 val = (signed long)((signed short) val);
319
320 regs->uregs[rd] = val;
321 } else
322 put16t_unaligned_check(regs->uregs[rd], addr);
323
324 return TYPE_LDST;
325
326 swp:
327 printk(KERN_ERR "Alignment trap: not handling swp instruction\n");
328 bad:
329 return TYPE_ERROR;
330
331 fault:
332 return TYPE_FAULT;
333}
334
335static int
336do_alignment_ldrstr(unsigned long addr, unsigned long instr, struct pt_regs *regs)
337{
338 unsigned int rd = RD_BITS(instr);
339
340 ai_word += 1;
341
342 if ((!LDST_P_BIT(instr) && LDST_W_BIT(instr)) || user_mode(regs))
343 goto trans;
344
345 if (LDST_L_BIT(instr)) {
346 unsigned int val;
347 get32_unaligned_check(val, addr);
348 regs->uregs[rd] = val;
349 } else
350 put32_unaligned_check(regs->uregs[rd], addr);
351 return TYPE_LDST;
352
353 trans:
354 if (LDST_L_BIT(instr)) {
355 unsigned int val;
356 get32t_unaligned_check(val, addr);
357 regs->uregs[rd] = val;
358 } else
359 put32t_unaligned_check(regs->uregs[rd], addr);
360 return TYPE_LDST;
361
362 fault:
363 return TYPE_FAULT;
364}
365
366/*
367 * LDM/STM alignment handler.
368 *
369 * There are 4 variants of this instruction:
370 *
371 * B = rn pointer before instruction, A = rn pointer after instruction
372 * ------ increasing address ----->
373 * | | r0 | r1 | ... | rx | |
374 * PU = 01 B A
375 * PU = 11 B A
376 * PU = 00 A B
377 * PU = 10 A B
378 */
379static int
380do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *regs)
381{
382 unsigned int rd, rn, correction, nr_regs, regbits;
383 unsigned long eaddr, newaddr;
384
385 if (LDM_S_BIT(instr))
386 goto bad;
387
388 correction = 4; /* processor implementation defined */
389 regs->ARM_pc += correction;
390
391 ai_multi += 1;
392
393 /* count the number of registers in the mask to be transferred */
394 nr_regs = hweight16(REGMASK_BITS(instr)) * 4;
395
396 rn = RN_BITS(instr);
397 newaddr = eaddr = regs->uregs[rn];
398
399 if (!LDST_U_BIT(instr))
400 nr_regs = -nr_regs;
401 newaddr += nr_regs;
402 if (!LDST_U_BIT(instr))
403 eaddr = newaddr;
404
405 if (LDST_P_EQ_U(instr)) /* U = P */
406 eaddr += 4;
407
408 /*
409 * For alignment faults on the ARM922T/ARM920T the MMU makes
410 * the FSR (and hence addr) equal to the updated base address
411 * of the multiple access rather than the restored value.
412 * Switch this message off if we've got a ARM92[02], otherwise
413 * [ls]dm alignment faults are noisy!
414 */
415#if !(defined CONFIG_CPU_ARM922T) && !(defined CONFIG_CPU_ARM920T)
416 /*
417 * This is a "hint" - we already have eaddr worked out by the
418 * processor for us.
419 */
420 if (addr != eaddr) {
421 printk(KERN_ERR "LDMSTM: PC = %08lx, instr = %08lx, "
422 "addr = %08lx, eaddr = %08lx\n",
423 instruction_pointer(regs), instr, addr, eaddr);
424 show_regs(regs);
425 }
426#endif
427
428 if (user_mode(regs)) {
429 for (regbits = REGMASK_BITS(instr), rd = 0; regbits;
430 regbits >>= 1, rd += 1)
431 if (regbits & 1) {
432 if (LDST_L_BIT(instr)) {
433 unsigned int val;
434 get32t_unaligned_check(val, eaddr);
435 regs->uregs[rd] = val;
436 } else
437 put32t_unaligned_check(regs->uregs[rd], eaddr);
438 eaddr += 4;
439 }
440 } else {
441 for (regbits = REGMASK_BITS(instr), rd = 0; regbits;
442 regbits >>= 1, rd += 1)
443 if (regbits & 1) {
444 if (LDST_L_BIT(instr)) {
445 unsigned int val;
446 get32_unaligned_check(val, eaddr);
447 regs->uregs[rd] = val;
448 } else
449 put32_unaligned_check(regs->uregs[rd], eaddr);
450 eaddr += 4;
451 }
452 }
453
454 if (LDST_W_BIT(instr))
455 regs->uregs[rn] = newaddr;
456 if (!LDST_L_BIT(instr) || !(REGMASK_BITS(instr) & (1 << 15)))
457 regs->ARM_pc -= correction;
458 return TYPE_DONE;
459
460fault:
461 regs->ARM_pc -= correction;
462 return TYPE_FAULT;
463
464bad:
465 printk(KERN_ERR "Alignment trap: not handling ldm with s-bit set\n");
466 return TYPE_ERROR;
467}
468
469/*
470 * Convert Thumb ld/st instruction forms to equivalent ARM instructions so
471 * we can reuse ARM userland alignment fault fixups for Thumb.
472 *
473 * This implementation was initially based on the algorithm found in
474 * gdb/sim/arm/thumbemu.c. It is basically just a code reduction of same
475 * to convert only Thumb ld/st instruction forms to equivalent ARM forms.
476 *
477 * NOTES:
478 * 1. Comments below refer to ARM ARM DDI0100E Thumb Instruction sections.
479 * 2. If for some reason we're passed an non-ld/st Thumb instruction to
480 * decode, we return 0xdeadc0de. This should never happen under normal
481 * circumstances but if it does, we've got other problems to deal with
482 * elsewhere and we obviously can't fix those problems here.
483 */
484
485static unsigned long
486thumb2arm(u16 tinstr)
487{
488 u32 L = (tinstr & (1<<11)) >> 11;
489
490 switch ((tinstr & 0xf800) >> 11) {
491 /* 6.5.1 Format 1: */
492 case 0x6000 >> 11: /* 7.1.52 STR(1) */
493 case 0x6800 >> 11: /* 7.1.26 LDR(1) */
494 case 0x7000 >> 11: /* 7.1.55 STRB(1) */
495 case 0x7800 >> 11: /* 7.1.30 LDRB(1) */
496 return 0xe5800000 |
497 ((tinstr & (1<<12)) << (22-12)) | /* fixup */
498 (L<<20) | /* L==1? */
499 ((tinstr & (7<<0)) << (12-0)) | /* Rd */
500 ((tinstr & (7<<3)) << (16-3)) | /* Rn */
501 ((tinstr & (31<<6)) >> /* immed_5 */
502 (6 - ((tinstr & (1<<12)) ? 0 : 2)));
503 case 0x8000 >> 11: /* 7.1.57 STRH(1) */
504 case 0x8800 >> 11: /* 7.1.32 LDRH(1) */
505 return 0xe1c000b0 |
506 (L<<20) | /* L==1? */
507 ((tinstr & (7<<0)) << (12-0)) | /* Rd */
508 ((tinstr & (7<<3)) << (16-3)) | /* Rn */
509 ((tinstr & (7<<6)) >> (6-1)) | /* immed_5[2:0] */
510 ((tinstr & (3<<9)) >> (9-8)); /* immed_5[4:3] */
511
512 /* 6.5.1 Format 2: */
513 case 0x5000 >> 11:
514 case 0x5800 >> 11:
515 {
516 static const u32 subset[8] = {
517 0xe7800000, /* 7.1.53 STR(2) */
518 0xe18000b0, /* 7.1.58 STRH(2) */
519 0xe7c00000, /* 7.1.56 STRB(2) */
520 0xe19000d0, /* 7.1.34 LDRSB */
521 0xe7900000, /* 7.1.27 LDR(2) */
522 0xe19000b0, /* 7.1.33 LDRH(2) */
523 0xe7d00000, /* 7.1.31 LDRB(2) */
524 0xe19000f0 /* 7.1.35 LDRSH */
525 };
526 return subset[(tinstr & (7<<9)) >> 9] |
527 ((tinstr & (7<<0)) << (12-0)) | /* Rd */
528 ((tinstr & (7<<3)) << (16-3)) | /* Rn */
529 ((tinstr & (7<<6)) >> (6-0)); /* Rm */
530 }
531
532 /* 6.5.1 Format 3: */
533 case 0x4800 >> 11: /* 7.1.28 LDR(3) */
534 /* NOTE: This case is not technically possible. We're
535 * loading 32-bit memory data via PC relative
536 * addressing mode. So we can and should eliminate
537 * this case. But I'll leave it here for now.
538 */
539 return 0xe59f0000 |
540 ((tinstr & (7<<8)) << (12-8)) | /* Rd */
541 ((tinstr & 255) << (2-0)); /* immed_8 */
542
543 /* 6.5.1 Format 4: */
544 case 0x9000 >> 11: /* 7.1.54 STR(3) */
545 case 0x9800 >> 11: /* 7.1.29 LDR(4) */
546 return 0xe58d0000 |
547 (L<<20) | /* L==1? */
548 ((tinstr & (7<<8)) << (12-8)) | /* Rd */
549 ((tinstr & 255) << 2); /* immed_8 */
550
551 /* 6.6.1 Format 1: */
552 case 0xc000 >> 11: /* 7.1.51 STMIA */
553 case 0xc800 >> 11: /* 7.1.25 LDMIA */
554 {
555 u32 Rn = (tinstr & (7<<8)) >> 8;
556 u32 W = ((L<<Rn) & (tinstr&255)) ? 0 : 1<<21;
557
558 return 0xe8800000 | W | (L<<20) | (Rn<<16) |
559 (tinstr&255);
560 }
561
562 /* 6.6.1 Format 2: */
563 case 0xb000 >> 11: /* 7.1.48 PUSH */
564 case 0xb800 >> 11: /* 7.1.47 POP */
565 if ((tinstr & (3 << 9)) == 0x0400) {
566 static const u32 subset[4] = {
567 0xe92d0000, /* STMDB sp!,{registers} */
568 0xe92d4000, /* STMDB sp!,{registers,lr} */
569 0xe8bd0000, /* LDMIA sp!,{registers} */
570 0xe8bd8000 /* LDMIA sp!,{registers,pc} */
571 };
572 return subset[(L<<1) | ((tinstr & (1<<8)) >> 8)] |
573 (tinstr & 255); /* register_list */
574 }
575 /* Else fall through for illegal instruction case */
576
577 default:
578 return 0xdeadc0de;
579 }
580}
581
582static int
583do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
584{
585 union offset_union offset;
586 unsigned long instr = 0, instrptr;
587 int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs);
588 unsigned int type;
589 mm_segment_t fs;
590 unsigned int fault;
591 u16 tinstr = 0;
592
593 instrptr = instruction_pointer(regs);
594
595 fs = get_fs();
596 set_fs(KERNEL_DS);
597 if thumb_mode(regs) {
598 fault = __get_user(tinstr, (u16 *)(instrptr & ~1));
599 if (!(fault))
600 instr = thumb2arm(tinstr);
601 } else
602 fault = __get_user(instr, (u32 *)instrptr);
603 set_fs(fs);
604
605 if (fault) {
606 type = TYPE_FAULT;
607 goto bad_or_fault;
608 }
609
610 if (user_mode(regs))
611 goto user;
612
613 ai_sys += 1;
614
615 fixup:
616
617 regs->ARM_pc += thumb_mode(regs) ? 2 : 4;
618
619 switch (CODING_BITS(instr)) {
620 case 0x00000000: /* ldrh or strh */
621 if (LDSTH_I_BIT(instr))
622 offset.un = (instr & 0xf00) >> 4 | (instr & 15);
623 else
624 offset.un = regs->uregs[RM_BITS(instr)];
625 handler = do_alignment_ldrhstrh;
626 break;
627
628 case 0x04000000: /* ldr or str immediate */
629 offset.un = OFFSET_BITS(instr);
630 handler = do_alignment_ldrstr;
631 break;
632
633 case 0x06000000: /* ldr or str register */
634 offset.un = regs->uregs[RM_BITS(instr)];
635
636 if (IS_SHIFT(instr)) {
637 unsigned int shiftval = SHIFT_BITS(instr);
638
639 switch(SHIFT_TYPE(instr)) {
640 case SHIFT_LSL:
641 offset.un <<= shiftval;
642 break;
643
644 case SHIFT_LSR:
645 offset.un >>= shiftval;
646 break;
647
648 case SHIFT_ASR:
649 offset.sn >>= shiftval;
650 break;
651
652 case SHIFT_RORRRX:
653 if (shiftval == 0) {
654 offset.un >>= 1;
655 if (regs->ARM_cpsr & PSR_C_BIT)
656 offset.un |= 1 << 31;
657 } else
658 offset.un = offset.un >> shiftval |
659 offset.un << (32 - shiftval);
660 break;
661 }
662 }
663 handler = do_alignment_ldrstr;
664 break;
665
666 case 0x08000000: /* ldm or stm */
667 handler = do_alignment_ldmstm;
668 break;
669
670 default:
671 goto bad;
672 }
673
674 type = handler(addr, instr, regs);
675
676 if (type == TYPE_ERROR || type == TYPE_FAULT)
677 goto bad_or_fault;
678
679 if (type == TYPE_LDST)
680 do_alignment_finish_ldst(addr, instr, regs, offset);
681
682 return 0;
683
684 bad_or_fault:
685 if (type == TYPE_ERROR)
686 goto bad;
687 regs->ARM_pc -= thumb_mode(regs) ? 2 : 4;
688 /*
689 * We got a fault - fix it up, or die.
690 */
691 do_bad_area(current, current->mm, addr, fsr, regs);
692 return 0;
693
694 bad:
695 /*
696 * Oops, we didn't handle the instruction.
697 */
698 printk(KERN_ERR "Alignment trap: not handling instruction "
699 "%0*lx at [<%08lx>]\n",
700 thumb_mode(regs) ? 4 : 8,
701 thumb_mode(regs) ? tinstr : instr, instrptr);
702 ai_skipped += 1;
703 return 1;
704
705 user:
706 ai_user += 1;
707
708 if (ai_usermode & 1)
709 printk("Alignment trap: %s (%d) PC=0x%08lx Instr=0x%0*lx "
710 "Address=0x%08lx FSR 0x%03x\n", current->comm,
711 current->pid, instrptr,
712 thumb_mode(regs) ? 4 : 8,
713 thumb_mode(regs) ? tinstr : instr,
714 addr, fsr);
715
716 if (ai_usermode & 2)
717 goto fixup;
718
719 if (ai_usermode & 4)
720 force_sig(SIGBUS, current);
721 else
722 set_cr(cr_no_alignment);
723
724 return 0;
725}
726
727/*
728 * This needs to be done after sysctl_init, otherwise sys/ will be
729 * overwritten. Actually, this shouldn't be in sys/ at all since
730 * it isn't a sysctl, and it doesn't contain sysctl information.
731 * We now locate it in /proc/cpu/alignment instead.
732 */
733static int __init alignment_init(void)
734{
735#ifdef CONFIG_PROC_FS
736 struct proc_dir_entry *res;
737
738 res = proc_mkdir("cpu", NULL);
739 if (!res)
740 return -ENOMEM;
741
742 res = create_proc_entry("alignment", S_IWUSR | S_IRUGO, res);
743 if (!res)
744 return -ENOMEM;
745
746 res->read_proc = proc_alignment_read;
747 res->write_proc = proc_alignment_write;
748#endif
749
750 hook_fault_code(1, do_alignment, SIGILL, "alignment exception");
751 hook_fault_code(3, do_alignment, SIGILL, "alignment exception");
752
753 return 0;
754}
755
756fs_initcall(alignment_init);
diff --git a/arch/arm/mm/blockops.c b/arch/arm/mm/blockops.c
new file mode 100644
index 000000000000..806c6eeb1b0c
--- /dev/null
+++ b/arch/arm/mm/blockops.c
@@ -0,0 +1,184 @@
1#include <linux/kernel.h>
2#include <linux/init.h>
3#include <linux/errno.h>
4#include <linux/mm.h>
5
6#include <asm/memory.h>
7#include <asm/ptrace.h>
8#include <asm/cacheflush.h>
9#include <asm/traps.h>
10
11extern struct cpu_cache_fns blk_cache_fns;
12
13#define HARVARD_CACHE
14
15/*
16 * blk_flush_kern_dcache_page(kaddr)
17 *
18 * Ensure that the data held in the page kaddr is written back
19 * to the page in question.
20 *
21 * - kaddr - kernel address (guaranteed to be page aligned)
22 */
23static void __attribute__((naked))
24blk_flush_kern_dcache_page(void *kaddr)
25{
26 asm(
27 "add r1, r0, %0 \n\
281: .word 0xec401f0e @ mcrr p15, 0, r0, r1, c14, 0 @ blocking \n\
29 mov r0, #0 \n\
30 mcr p15, 0, r0, c7, c5, 0 \n\
31 mcr p15, 0, r0, c7, c10, 4 \n\
32 mov pc, lr"
33 :
34 : "I" (PAGE_SIZE));
35}
36
37/*
38 * blk_dma_inv_range(start,end)
39 *
40 * Invalidate the data cache within the specified region; we will
41 * be performing a DMA operation in this region and we want to
42 * purge old data in the cache.
43 *
44 * - start - virtual start address of region
45 * - end - virtual end address of region
46 */
47static void __attribute__((naked))
48blk_dma_inv_range_unified(unsigned long start, unsigned long end)
49{
50 asm(
51 "tst r0, %0 \n\
52 mcrne p15, 0, r0, c7, c11, 1 @ clean unified line \n\
53 tst r1, %0 \n\
54 mcrne p15, 0, r1, c7, c15, 1 @ clean & invalidate unified line\n\
55 .word 0xec401f06 @ mcrr p15, 0, r1, r0, c6, 0 @ blocking \n\
56 mov r0, #0 \n\
57 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer \n\
58 mov pc, lr"
59 :
60 : "I" (L1_CACHE_BYTES - 1));
61}
62
63static void __attribute__((naked))
64blk_dma_inv_range_harvard(unsigned long start, unsigned long end)
65{
66 asm(
67 "tst r0, %0 \n\
68 mcrne p15, 0, r0, c7, c10, 1 @ clean D line \n\
69 tst r1, %0 \n\
70 mcrne p15, 0, r1, c7, c14, 1 @ clean & invalidate D line \n\
71 .word 0xec401f06 @ mcrr p15, 0, r1, r0, c6, 0 @ blocking \n\
72 mov r0, #0 \n\
73 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer \n\
74 mov pc, lr"
75 :
76 : "I" (L1_CACHE_BYTES - 1));
77}
78
79/*
80 * blk_dma_clean_range(start,end)
81 * - start - virtual start address of region
82 * - end - virtual end address of region
83 */
84static void __attribute__((naked))
85blk_dma_clean_range(unsigned long start, unsigned long end)
86{
87 asm(
88 ".word 0xec401f0c @ mcrr p15, 0, r1, r0, c12, 0 @ blocking \n\
89 mov r0, #0 \n\
90 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer \n\
91 mov pc, lr");
92}
93
94/*
95 * blk_dma_flush_range(start,end)
96 * - start - virtual start address of region
97 * - end - virtual end address of region
98 */
99static void __attribute__((naked))
100blk_dma_flush_range(unsigned long start, unsigned long end)
101{
102 asm(
103 ".word 0xec401f0e @ mcrr p15, 0, r1, r0, c14, 0 @ blocking \n\
104 mov pc, lr");
105}
106
107static int blockops_trap(struct pt_regs *regs, unsigned int instr)
108{
109 regs->ARM_r4 |= regs->ARM_r2;
110 regs->ARM_pc += 4;
111 return 0;
112}
113
114static char *func[] = {
115 "Prefetch data range",
116 "Clean+Invalidate data range",
117 "Clean data range",
118 "Invalidate data range",
119 "Invalidate instr range"
120};
121
122static struct undef_hook blockops_hook __initdata = {
123 .instr_mask = 0x0fffffd0,
124 .instr_val = 0x0c401f00,
125 .cpsr_mask = PSR_T_BIT,
126 .cpsr_val = 0,
127 .fn = blockops_trap,
128};
129
130static int __init blockops_check(void)
131{
132 register unsigned int err asm("r4") = 0;
133 unsigned int err_pos = 1;
134 unsigned int cache_type;
135 int i;
136
137 asm("mrc p15, 0, %0, c0, c0, 1" : "=r" (cache_type));
138
139 printk("Checking V6 block cache operations:\n");
140 register_undef_hook(&blockops_hook);
141
142 __asm__ ("mov r0, %0\n\t"
143 "mov r1, %1\n\t"
144 "mov r2, #1\n\t"
145 ".word 0xec401f2c @ mcrr p15, 0, r1, r0, c12, 2\n\t"
146 "mov r2, #2\n\t"
147 ".word 0xec401f0e @ mcrr p15, 0, r1, r0, c14, 0\n\t"
148 "mov r2, #4\n\t"
149 ".word 0xec401f0c @ mcrr p15, 0, r1, r0, c12, 0\n\t"
150 "mov r2, #8\n\t"
151 ".word 0xec401f06 @ mcrr p15, 0, r1, r0, c6, 0\n\t"
152 "mov r2, #16\n\t"
153 ".word 0xec401f05 @ mcrr p15, 0, r1, r0, c5, 0\n\t"
154 :
155 : "r" (PAGE_OFFSET), "r" (PAGE_OFFSET + 128)
156 : "r0", "r1", "r2");
157
158 unregister_undef_hook(&blockops_hook);
159
160 for (i = 0; i < ARRAY_SIZE(func); i++, err_pos <<= 1)
161 printk("%30s: %ssupported\n", func[i], err & err_pos ? "not " : "");
162
163 if ((err & 8) == 0) {
164 printk(" --> Using %s block cache invalidate\n",
165 cache_type & (1 << 24) ? "harvard" : "unified");
166 if (cache_type & (1 << 24))
167 cpu_cache.dma_inv_range = blk_dma_inv_range_harvard;
168 else
169 cpu_cache.dma_inv_range = blk_dma_inv_range_unified;
170 }
171 if ((err & 4) == 0) {
172 printk(" --> Using block cache clean\n");
173 cpu_cache.dma_clean_range = blk_dma_clean_range;
174 }
175 if ((err & 2) == 0) {
176 printk(" --> Using block cache clean+invalidate\n");
177 cpu_cache.dma_flush_range = blk_dma_flush_range;
178 cpu_cache.flush_kern_dcache_page = blk_flush_kern_dcache_page;
179 }
180
181 return 0;
182}
183
184__initcall(blockops_check);
diff --git a/arch/arm/mm/cache-v3.S b/arch/arm/mm/cache-v3.S
new file mode 100644
index 000000000000..e1994788cf0e
--- /dev/null
+++ b/arch/arm/mm/cache-v3.S
@@ -0,0 +1,137 @@
1/*
2 * linux/arch/arm/mm/cache-v3.S
3 *
4 * Copyright (C) 1997-2002 Russell king
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/linkage.h>
11#include <linux/init.h>
12#include <asm/hardware.h>
13#include <asm/page.h>
14#include "proc-macros.S"
15
16/*
17 * flush_user_cache_all()
18 *
19 * Invalidate all cache entries in a particular address
20 * space.
21 *
22 * - mm - mm_struct describing address space
23 */
24ENTRY(v3_flush_user_cache_all)
25 /* FALLTHROUGH */
26/*
27 * flush_kern_cache_all()
28 *
29 * Clean and invalidate the entire cache.
30 */
31ENTRY(v3_flush_kern_cache_all)
32 /* FALLTHROUGH */
33
34/*
35 * flush_user_cache_range(start, end, flags)
36 *
37 * Invalidate a range of cache entries in the specified
38 * address space.
39 *
40 * - start - start address (may not be aligned)
41 * - end - end address (exclusive, may not be aligned)
42 * - flags - vma_area_struct flags describing address space
43 */
44ENTRY(v3_flush_user_cache_range)
45 mov ip, #0
46 mcreq p15, 0, ip, c7, c0, 0 @ flush ID cache
47 mov pc, lr
48
49/*
50 * coherent_kern_range(start, end)
51 *
52 * Ensure coherency between the Icache and the Dcache in the
53 * region described by start. If you have non-snooping
54 * Harvard caches, you need to implement this function.
55 *
56 * - start - virtual start address
57 * - end - virtual end address
58 */
59ENTRY(v3_coherent_kern_range)
60 /* FALLTHROUGH */
61
62/*
63 * coherent_user_range(start, end)
64 *
65 * Ensure coherency between the Icache and the Dcache in the
66 * region described by start. If you have non-snooping
67 * Harvard caches, you need to implement this function.
68 *
69 * - start - virtual start address
70 * - end - virtual end address
71 */
72ENTRY(v3_coherent_user_range)
73 mov pc, lr
74
75/*
76 * flush_kern_dcache_page(void *page)
77 *
78 * Ensure no D cache aliasing occurs, either with itself or
79 * the I cache
80 *
81 * - addr - page aligned address
82 */
83ENTRY(v3_flush_kern_dcache_page)
84 /* FALLTHROUGH */
85
86/*
87 * dma_inv_range(start, end)
88 *
89 * Invalidate (discard) the specified virtual address range.
90 * May not write back any entries. If 'start' or 'end'
91 * are not cache line aligned, those lines must be written
92 * back.
93 *
94 * - start - virtual start address
95 * - end - virtual end address
96 */
97ENTRY(v3_dma_inv_range)
98 /* FALLTHROUGH */
99
100/*
101 * dma_flush_range(start, end)
102 *
103 * Clean and invalidate the specified virtual address range.
104 *
105 * - start - virtual start address
106 * - end - virtual end address
107 */
108ENTRY(v3_dma_flush_range)
109 mov r0, #0
110 mcr p15, 0, r0, c7, c0, 0 @ flush ID cache
111 /* FALLTHROUGH */
112
113/*
114 * dma_clean_range(start, end)
115 *
116 * Clean (write back) the specified virtual address range.
117 *
118 * - start - virtual start address
119 * - end - virtual end address
120 */
121ENTRY(v3_dma_clean_range)
122 mov pc, lr
123
124 __INITDATA
125
126 .type v3_cache_fns, #object
127ENTRY(v3_cache_fns)
128 .long v3_flush_kern_cache_all
129 .long v3_flush_user_cache_all
130 .long v3_flush_user_cache_range
131 .long v3_coherent_kern_range
132 .long v3_coherent_user_range
133 .long v3_flush_kern_dcache_page
134 .long v3_dma_inv_range
135 .long v3_dma_clean_range
136 .long v3_dma_flush_range
137 .size v3_cache_fns, . - v3_cache_fns
diff --git a/arch/arm/mm/cache-v4.S b/arch/arm/mm/cache-v4.S
new file mode 100644
index 000000000000..b8ad5d58ebe2
--- /dev/null
+++ b/arch/arm/mm/cache-v4.S
@@ -0,0 +1,139 @@
1/*
2 * linux/arch/arm/mm/cache-v4.S
3 *
4 * Copyright (C) 1997-2002 Russell king
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/linkage.h>
11#include <linux/init.h>
12#include <asm/hardware.h>
13#include <asm/page.h>
14#include "proc-macros.S"
15
16/*
17 * flush_user_cache_all()
18 *
19 * Invalidate all cache entries in a particular address
20 * space.
21 *
22 * - mm - mm_struct describing address space
23 */
24ENTRY(v4_flush_user_cache_all)
25 /* FALLTHROUGH */
26/*
27 * flush_kern_cache_all()
28 *
29 * Clean and invalidate the entire cache.
30 */
31ENTRY(v4_flush_kern_cache_all)
32 mov r0, #0
33 mcr p15, 0, r0, c7, c7, 0 @ flush ID cache
34 mov pc, lr
35
36/*
37 * flush_user_cache_range(start, end, flags)
38 *
39 * Invalidate a range of cache entries in the specified
40 * address space.
41 *
42 * - start - start address (may not be aligned)
43 * - end - end address (exclusive, may not be aligned)
44 * - flags - vma_area_struct flags describing address space
45 */
46ENTRY(v4_flush_user_cache_range)
47 mov ip, #0
48 mcreq p15, 0, ip, c7, c7, 0 @ flush ID cache
49 mov pc, lr
50
51/*
52 * coherent_kern_range(start, end)
53 *
54 * Ensure coherency between the Icache and the Dcache in the
55 * region described by start. If you have non-snooping
56 * Harvard caches, you need to implement this function.
57 *
58 * - start - virtual start address
59 * - end - virtual end address
60 */
61ENTRY(v4_coherent_kern_range)
62 /* FALLTHROUGH */
63
64/*
65 * coherent_user_range(start, end)
66 *
67 * Ensure coherency between the Icache and the Dcache in the
68 * region described by start. If you have non-snooping
69 * Harvard caches, you need to implement this function.
70 *
71 * - start - virtual start address
72 * - end - virtual end address
73 */
74ENTRY(v4_coherent_user_range)
75 mov pc, lr
76
77/*
78 * flush_kern_dcache_page(void *page)
79 *
80 * Ensure no D cache aliasing occurs, either with itself or
81 * the I cache
82 *
83 * - addr - page aligned address
84 */
85ENTRY(v4_flush_kern_dcache_page)
86 /* FALLTHROUGH */
87
88/*
89 * dma_inv_range(start, end)
90 *
91 * Invalidate (discard) the specified virtual address range.
92 * May not write back any entries. If 'start' or 'end'
93 * are not cache line aligned, those lines must be written
94 * back.
95 *
96 * - start - virtual start address
97 * - end - virtual end address
98 */
99ENTRY(v4_dma_inv_range)
100 /* FALLTHROUGH */
101
102/*
103 * dma_flush_range(start, end)
104 *
105 * Clean and invalidate the specified virtual address range.
106 *
107 * - start - virtual start address
108 * - end - virtual end address
109 */
110ENTRY(v4_dma_flush_range)
111 mov r0, #0
112 mcr p15, 0, r0, c7, c7, 0 @ flush ID cache
113 /* FALLTHROUGH */
114
115/*
116 * dma_clean_range(start, end)
117 *
118 * Clean (write back) the specified virtual address range.
119 *
120 * - start - virtual start address
121 * - end - virtual end address
122 */
123ENTRY(v4_dma_clean_range)
124 mov pc, lr
125
126 __INITDATA
127
128 .type v4_cache_fns, #object
129ENTRY(v4_cache_fns)
130 .long v4_flush_kern_cache_all
131 .long v4_flush_user_cache_all
132 .long v4_flush_user_cache_range
133 .long v4_coherent_kern_range
134 .long v4_coherent_user_range
135 .long v4_flush_kern_dcache_page
136 .long v4_dma_inv_range
137 .long v4_dma_clean_range
138 .long v4_dma_flush_range
139 .size v4_cache_fns, . - v4_cache_fns
diff --git a/arch/arm/mm/cache-v4wb.S b/arch/arm/mm/cache-v4wb.S
new file mode 100644
index 000000000000..5c4055b62d97
--- /dev/null
+++ b/arch/arm/mm/cache-v4wb.S
@@ -0,0 +1,216 @@
1/*
2 * linux/arch/arm/mm/cache-v4wb.S
3 *
4 * Copyright (C) 1997-2002 Russell king
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/config.h>
11#include <linux/linkage.h>
12#include <linux/init.h>
13#include <asm/hardware.h>
14#include <asm/page.h>
15#include "proc-macros.S"
16
17/*
18 * The size of one data cache line.
19 */
20#define CACHE_DLINESIZE 32
21
22/*
23 * The total size of the data cache.
24 */
25#if defined(CONFIG_CPU_SA110)
26# define CACHE_DSIZE 16384
27#elif defined(CONFIG_CPU_SA1100)
28# define CACHE_DSIZE 8192
29#else
30# error Unknown cache size
31#endif
32
33/*
34 * This is the size at which it becomes more efficient to
35 * clean the whole cache, rather than using the individual
36 * cache line maintainence instructions.
37 *
38 * Size Clean (ticks) Dirty (ticks)
39 * 4096 21 20 21 53 55 54
40 * 8192 40 41 40 106 100 102
41 * 16384 77 77 76 140 140 138
42 * 32768 150 149 150 214 216 212 <---
43 * 65536 296 297 296 351 358 361
44 * 131072 591 591 591 656 657 651
45 * Whole 132 136 132 221 217 207 <---
46 */
47#define CACHE_DLIMIT (CACHE_DSIZE * 4)
48
49/*
50 * flush_user_cache_all()
51 *
52 * Clean and invalidate all cache entries in a particular address
53 * space.
54 */
55ENTRY(v4wb_flush_user_cache_all)
56 /* FALLTHROUGH */
57/*
58 * flush_kern_cache_all()
59 *
60 * Clean and invalidate the entire cache.
61 */
62ENTRY(v4wb_flush_kern_cache_all)
63 mov ip, #0
64 mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache
65__flush_whole_cache:
66 mov r0, #FLUSH_BASE
67 add r1, r0, #CACHE_DSIZE
681: ldr r2, [r0], #32
69 cmp r0, r1
70 blo 1b
71 mcr p15, 0, ip, c7, c10, 4 @ drain write buffer
72 mov pc, lr
73
74/*
75 * flush_user_cache_range(start, end, flags)
76 *
77 * Invalidate a range of cache entries in the specified
78 * address space.
79 *
80 * - start - start address (inclusive, page aligned)
81 * - end - end address (exclusive, page aligned)
82 * - flags - vma_area_struct flags describing address space
83 */
84ENTRY(v4wb_flush_user_cache_range)
85 sub r3, r1, r0 @ calculate total size
86 tst r2, #VM_EXEC @ executable region?
87 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
88
89 cmp r3, #CACHE_DLIMIT @ total size >= limit?
90 bhs __flush_whole_cache @ flush whole D cache
91
921: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
93 mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
94 add r0, r0, #CACHE_DLINESIZE
95 cmp r0, r1
96 blo 1b
97 tst r2, #VM_EXEC
98 mcrne p15, 0, ip, c7, c10, 4 @ drain write buffer
99 mov pc, lr
100
101/*
102 * flush_kern_dcache_page(void *page)
103 *
104 * Ensure no D cache aliasing occurs, either with itself or
105 * the I cache
106 *
107 * - addr - page aligned address
108 */
109ENTRY(v4wb_flush_kern_dcache_page)
110 add r1, r0, #PAGE_SZ
111 /* fall through */
112
113/*
114 * coherent_kern_range(start, end)
115 *
116 * Ensure coherency between the Icache and the Dcache in the
117 * region described by start. If you have non-snooping
118 * Harvard caches, you need to implement this function.
119 *
120 * - start - virtual start address
121 * - end - virtual end address
122 */
123ENTRY(v4wb_coherent_kern_range)
124 /* fall through */
125
126/*
127 * coherent_user_range(start, end)
128 *
129 * Ensure coherency between the Icache and the Dcache in the
130 * region described by start. If you have non-snooping
131 * Harvard caches, you need to implement this function.
132 *
133 * - start - virtual start address
134 * - end - virtual end address
135 */
136ENTRY(v4wb_coherent_user_range)
137 bic r0, r0, #CACHE_DLINESIZE - 1
1381: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
139 mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
140 add r0, r0, #CACHE_DLINESIZE
141 cmp r0, r1
142 blo 1b
143 mov ip, #0
144 mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache
145 mcr p15, 0, ip, c7, c10, 4 @ drain WB
146 mov pc, lr
147
148
149/*
150 * dma_inv_range(start, end)
151 *
152 * Invalidate (discard) the specified virtual address range.
153 * May not write back any entries. If 'start' or 'end'
154 * are not cache line aligned, those lines must be written
155 * back.
156 *
157 * - start - virtual start address
158 * - end - virtual end address
159 */
160ENTRY(v4wb_dma_inv_range)
161 tst r0, #CACHE_DLINESIZE - 1
162 bic r0, r0, #CACHE_DLINESIZE - 1
163 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
164 tst r1, #CACHE_DLINESIZE - 1
165 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry
1661: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
167 add r0, r0, #CACHE_DLINESIZE
168 cmp r0, r1
169 blo 1b
170 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
171 mov pc, lr
172
173/*
174 * dma_clean_range(start, end)
175 *
176 * Clean (write back) the specified virtual address range.
177 *
178 * - start - virtual start address
179 * - end - virtual end address
180 */
181ENTRY(v4wb_dma_clean_range)
182 bic r0, r0, #CACHE_DLINESIZE - 1
1831: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
184 add r0, r0, #CACHE_DLINESIZE
185 cmp r0, r1
186 blo 1b
187 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
188 mov pc, lr
189
190/*
191 * dma_flush_range(start, end)
192 *
193 * Clean and invalidate the specified virtual address range.
194 *
195 * - start - virtual start address
196 * - end - virtual end address
197 *
198 * This is actually the same as v4wb_coherent_kern_range()
199 */
200 .globl v4wb_dma_flush_range
201 .set v4wb_dma_flush_range, v4wb_coherent_kern_range
202
203 __INITDATA
204
205 .type v4wb_cache_fns, #object
206ENTRY(v4wb_cache_fns)
207 .long v4wb_flush_kern_cache_all
208 .long v4wb_flush_user_cache_all
209 .long v4wb_flush_user_cache_range
210 .long v4wb_coherent_kern_range
211 .long v4wb_coherent_user_range
212 .long v4wb_flush_kern_dcache_page
213 .long v4wb_dma_inv_range
214 .long v4wb_dma_clean_range
215 .long v4wb_dma_flush_range
216 .size v4wb_cache_fns, . - v4wb_cache_fns
diff --git a/arch/arm/mm/cache-v4wt.S b/arch/arm/mm/cache-v4wt.S
new file mode 100644
index 000000000000..9bcabd86c6f3
--- /dev/null
+++ b/arch/arm/mm/cache-v4wt.S
@@ -0,0 +1,188 @@
1/*
2 * linux/arch/arm/mm/cache-v4wt.S
3 *
4 * Copyright (C) 1997-2002 Russell king
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ARMv4 write through cache operations support.
11 *
12 * We assume that the write buffer is not enabled.
13 */
14#include <linux/linkage.h>
15#include <linux/init.h>
16#include <asm/hardware.h>
17#include <asm/page.h>
18#include "proc-macros.S"
19
20/*
21 * The size of one data cache line.
22 */
23#define CACHE_DLINESIZE 32
24
25/*
26 * The number of data cache segments.
27 */
28#define CACHE_DSEGMENTS 8
29
30/*
31 * The number of lines in a cache segment.
32 */
33#define CACHE_DENTRIES 64
34
35/*
36 * This is the size at which it becomes more efficient to
37 * clean the whole cache, rather than using the individual
38 * cache line maintainence instructions.
39 *
40 * *** This needs benchmarking
41 */
42#define CACHE_DLIMIT 16384
43
44/*
45 * flush_user_cache_all()
46 *
47 * Invalidate all cache entries in a particular address
48 * space.
49 */
50ENTRY(v4wt_flush_user_cache_all)
51 /* FALLTHROUGH */
52/*
53 * flush_kern_cache_all()
54 *
55 * Clean and invalidate the entire cache.
56 */
57ENTRY(v4wt_flush_kern_cache_all)
58 mov r2, #VM_EXEC
59 mov ip, #0
60__flush_whole_cache:
61 tst r2, #VM_EXEC
62 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
63 mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache
64 mov pc, lr
65
66/*
67 * flush_user_cache_range(start, end, flags)
68 *
69 * Clean and invalidate a range of cache entries in the specified
70 * address space.
71 *
72 * - start - start address (inclusive, page aligned)
73 * - end - end address (exclusive, page aligned)
74 * - flags - vma_area_struct flags describing address space
75 */
76ENTRY(v4wt_flush_user_cache_range)
77 sub r3, r1, r0 @ calculate total size
78 cmp r3, #CACHE_DLIMIT
79 bhs __flush_whole_cache
80
811: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
82 tst r2, #VM_EXEC
83 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
84 add r0, r0, #CACHE_DLINESIZE
85 cmp r0, r1
86 blo 1b
87 mov pc, lr
88
89/*
90 * coherent_kern_range(start, end)
91 *
92 * Ensure coherency between the Icache and the Dcache in the
93 * region described by start. If you have non-snooping
94 * Harvard caches, you need to implement this function.
95 *
96 * - start - virtual start address
97 * - end - virtual end address
98 */
99ENTRY(v4wt_coherent_kern_range)
100 /* FALLTRHOUGH */
101
102/*
103 * coherent_user_range(start, end)
104 *
105 * Ensure coherency between the Icache and the Dcache in the
106 * region described by start. If you have non-snooping
107 * Harvard caches, you need to implement this function.
108 *
109 * - start - virtual start address
110 * - end - virtual end address
111 */
112ENTRY(v4wt_coherent_user_range)
113 bic r0, r0, #CACHE_DLINESIZE - 1
1141: mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry
115 add r0, r0, #CACHE_DLINESIZE
116 cmp r0, r1
117 blo 1b
118 mov pc, lr
119
120/*
121 * flush_kern_dcache_page(void *page)
122 *
123 * Ensure no D cache aliasing occurs, either with itself or
124 * the I cache
125 *
126 * - addr - page aligned address
127 */
128ENTRY(v4wt_flush_kern_dcache_page)
129 mov r2, #0
130 mcr p15, 0, r2, c7, c5, 0 @ invalidate I cache
131 add r1, r0, #PAGE_SZ
132 /* fallthrough */
133
134/*
135 * dma_inv_range(start, end)
136 *
137 * Invalidate (discard) the specified virtual address range.
138 * May not write back any entries. If 'start' or 'end'
139 * are not cache line aligned, those lines must be written
140 * back.
141 *
142 * - start - virtual start address
143 * - end - virtual end address
144 */
145ENTRY(v4wt_dma_inv_range)
146 bic r0, r0, #CACHE_DLINESIZE - 1
1471: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
148 add r0, r0, #CACHE_DLINESIZE
149 cmp r0, r1
150 blo 1b
151 /* FALLTHROUGH */
152
153/*
154 * dma_clean_range(start, end)
155 *
156 * Clean the specified virtual address range.
157 *
158 * - start - virtual start address
159 * - end - virtual end address
160 */
161ENTRY(v4wt_dma_clean_range)
162 mov pc, lr
163
164/*
165 * dma_flush_range(start, end)
166 *
167 * Clean and invalidate the specified virtual address range.
168 *
169 * - start - virtual start address
170 * - end - virtual end address
171 */
172 .globl v4wt_dma_flush_range
173 .equ v4wt_dma_flush_range, v4wt_dma_inv_range
174
175 __INITDATA
176
177 .type v4wt_cache_fns, #object
178ENTRY(v4wt_cache_fns)
179 .long v4wt_flush_kern_cache_all
180 .long v4wt_flush_user_cache_all
181 .long v4wt_flush_user_cache_range
182 .long v4wt_coherent_kern_range
183 .long v4wt_coherent_user_range
184 .long v4wt_flush_kern_dcache_page
185 .long v4wt_dma_inv_range
186 .long v4wt_dma_clean_range
187 .long v4wt_dma_flush_range
188 .size v4wt_cache_fns, . - v4wt_cache_fns
diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S
new file mode 100644
index 000000000000..85c10a71e7c6
--- /dev/null
+++ b/arch/arm/mm/cache-v6.S
@@ -0,0 +1,227 @@
1/*
2 * linux/arch/arm/mm/cache-v6.S
3 *
4 * Copyright (C) 2001 Deep Blue Solutions Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This is the "shell" of the ARMv6 processor support.
11 */
12#include <linux/linkage.h>
13#include <linux/init.h>
14#include <asm/assembler.h>
15
16#include "proc-macros.S"
17
18#define HARVARD_CACHE
19#define CACHE_LINE_SIZE 32
20#define D_CACHE_LINE_SIZE 32
21
22/*
23 * v6_flush_cache_all()
24 *
25 * Flush the entire cache.
26 *
27 * It is assumed that:
28 */
29ENTRY(v6_flush_kern_cache_all)
30 mov r0, #0
31#ifdef HARVARD_CACHE
32 mcr p15, 0, r0, c7, c14, 0 @ D cache clean+invalidate
33 mcr p15, 0, r0, c7, c5, 0 @ I+BTB cache invalidate
34#else
35 mcr p15, 0, r0, c7, c15, 0 @ Cache clean+invalidate
36#endif
37 mov pc, lr
38
39/*
40 * v6_flush_cache_all()
41 *
42 * Flush all TLB entries in a particular address space
43 *
44 * - mm - mm_struct describing address space
45 */
46ENTRY(v6_flush_user_cache_all)
47 /*FALLTHROUGH*/
48
49/*
50 * v6_flush_cache_range(start, end, flags)
51 *
52 * Flush a range of TLB entries in the specified address space.
53 *
54 * - start - start address (may not be aligned)
55 * - end - end address (exclusive, may not be aligned)
56 * - flags - vm_area_struct flags describing address space
57 *
58 * It is assumed that:
59 * - we have a VIPT cache.
60 */
61ENTRY(v6_flush_user_cache_range)
62 mov pc, lr
63
64/*
65 * v6_coherent_kern_range(start,end)
66 *
67 * Ensure that the I and D caches are coherent within specified
68 * region. This is typically used when code has been written to
69 * a memory region, and will be executed.
70 *
71 * - start - virtual start address of region
72 * - end - virtual end address of region
73 *
74 * It is assumed that:
75 * - the Icache does not read data from the write buffer
76 */
77ENTRY(v6_coherent_kern_range)
78 /* FALLTHROUGH */
79
80/*
81 * v6_coherent_user_range(start,end)
82 *
83 * Ensure that the I and D caches are coherent within specified
84 * region. This is typically used when code has been written to
85 * a memory region, and will be executed.
86 *
87 * - start - virtual start address of region
88 * - end - virtual end address of region
89 *
90 * It is assumed that:
91 * - the Icache does not read data from the write buffer
92 */
93ENTRY(v6_coherent_user_range)
94 bic r0, r0, #CACHE_LINE_SIZE - 1
951:
96#ifdef HARVARD_CACHE
97 mcr p15, 0, r0, c7, c10, 1 @ clean D line
98 mcr p15, 0, r0, c7, c5, 1 @ invalidate I line
99#endif
100 mcr p15, 0, r0, c7, c5, 7 @ invalidate BTB entry
101 add r0, r0, #CACHE_LINE_SIZE
102 cmp r0, r1
103 blo 1b
104#ifdef HARVARD_CACHE
105 mov r0, #0
106 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
107#endif
108 mov pc, lr
109
110/*
111 * v6_flush_kern_dcache_page(kaddr)
112 *
113 * Ensure that the data held in the page kaddr is written back
114 * to the page in question.
115 *
116 * - kaddr - kernel address (guaranteed to be page aligned)
117 */
118ENTRY(v6_flush_kern_dcache_page)
119 add r1, r0, #PAGE_SZ
1201:
121#ifdef HARVARD_CACHE
122 mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D line
123#else
124 mcr p15, 0, r0, c7, c15, 1 @ clean & invalidate unified line
125#endif
126 add r0, r0, #D_CACHE_LINE_SIZE
127 cmp r0, r1
128 blo 1b
129#ifdef HARVARD_CACHE
130 mov r0, #0
131 mcr p15, 0, r0, c7, c10, 4
132#endif
133 mov pc, lr
134
135
136/*
137 * v6_dma_inv_range(start,end)
138 *
139 * Invalidate the data cache within the specified region; we will
140 * be performing a DMA operation in this region and we want to
141 * purge old data in the cache.
142 *
143 * - start - virtual start address of region
144 * - end - virtual end address of region
145 */
146ENTRY(v6_dma_inv_range)
147 tst r0, #D_CACHE_LINE_SIZE - 1
148 bic r0, r0, #D_CACHE_LINE_SIZE - 1
149#ifdef HARVARD_CACHE
150 mcrne p15, 0, r0, c7, c10, 1 @ clean D line
151#else
152 mcrne p15, 0, r0, c7, c11, 1 @ clean unified line
153#endif
154 tst r1, #D_CACHE_LINE_SIZE - 1
155 bic r1, r1, #D_CACHE_LINE_SIZE - 1
156#ifdef HARVARD_CACHE
157 mcrne p15, 0, r1, c7, c14, 1 @ clean & invalidate D line
158#else
159 mcrne p15, 0, r1, c7, c15, 1 @ clean & invalidate unified line
160#endif
1611:
162#ifdef HARVARD_CACHE
163 mcr p15, 0, r0, c7, c6, 1 @ invalidate D line
164#else
165 mcr p15, 0, r0, c7, c7, 1 @ invalidate unified line
166#endif
167 add r0, r0, #D_CACHE_LINE_SIZE
168 cmp r0, r1
169 blo 1b
170 mov r0, #0
171 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
172 mov pc, lr
173
174/*
175 * v6_dma_clean_range(start,end)
176 * - start - virtual start address of region
177 * - end - virtual end address of region
178 */
179ENTRY(v6_dma_clean_range)
180 bic r0, r0, #D_CACHE_LINE_SIZE - 1
1811:
182#ifdef HARVARD_CACHE
183 mcr p15, 0, r0, c7, c10, 1 @ clean D line
184#else
185 mcr p15, 0, r0, c7, c11, 1 @ clean unified line
186#endif
187 add r0, r0, #D_CACHE_LINE_SIZE
188 cmp r0, r1
189 blo 1b
190 mov r0, #0
191 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
192 mov pc, lr
193
194/*
195 * v6_dma_flush_range(start,end)
196 * - start - virtual start address of region
197 * - end - virtual end address of region
198 */
199ENTRY(v6_dma_flush_range)
200 bic r0, r0, #D_CACHE_LINE_SIZE - 1
2011:
202#ifdef HARVARD_CACHE
203 mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D line
204#else
205 mcr p15, 0, r0, c7, c15, 1 @ clean & invalidate line
206#endif
207 add r0, r0, #D_CACHE_LINE_SIZE
208 cmp r0, r1
209 blo 1b
210 mov r0, #0
211 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
212 mov pc, lr
213
214 __INITDATA
215
216 .type v6_cache_fns, #object
217ENTRY(v6_cache_fns)
218 .long v6_flush_kern_cache_all
219 .long v6_flush_user_cache_all
220 .long v6_flush_user_cache_range
221 .long v6_coherent_kern_range
222 .long v6_coherent_user_range
223 .long v6_flush_kern_dcache_page
224 .long v6_dma_inv_range
225 .long v6_dma_clean_range
226 .long v6_dma_flush_range
227 .size v6_cache_fns, . - v6_cache_fns
diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c
new file mode 100644
index 000000000000..26356ce4da54
--- /dev/null
+++ b/arch/arm/mm/consistent.c
@@ -0,0 +1,451 @@
1/*
2 * linux/arch/arm/mm/consistent.c
3 *
4 * Copyright (C) 2000-2004 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * DMA uncached mapping support.
11 */
12#include <linux/module.h>
13#include <linux/mm.h>
14#include <linux/slab.h>
15#include <linux/errno.h>
16#include <linux/list.h>
17#include <linux/init.h>
18#include <linux/device.h>
19#include <linux/dma-mapping.h>
20
21#include <asm/cacheflush.h>
22#include <asm/io.h>
23#include <asm/tlbflush.h>
24
25#define CONSISTENT_BASE (0xffc00000)
26#define CONSISTENT_END (0xffe00000)
27#define CONSISTENT_OFFSET(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PAGE_SHIFT)
28
29/*
30 * This is the page table (2MB) covering uncached, DMA consistent allocations
31 */
32static pte_t *consistent_pte;
33static DEFINE_SPINLOCK(consistent_lock);
34
35/*
36 * VM region handling support.
37 *
38 * This should become something generic, handling VM region allocations for
39 * vmalloc and similar (ioremap, module space, etc).
40 *
41 * I envisage vmalloc()'s supporting vm_struct becoming:
42 *
43 * struct vm_struct {
44 * struct vm_region region;
45 * unsigned long flags;
46 * struct page **pages;
47 * unsigned int nr_pages;
48 * unsigned long phys_addr;
49 * };
50 *
51 * get_vm_area() would then call vm_region_alloc with an appropriate
52 * struct vm_region head (eg):
53 *
54 * struct vm_region vmalloc_head = {
55 * .vm_list = LIST_HEAD_INIT(vmalloc_head.vm_list),
56 * .vm_start = VMALLOC_START,
57 * .vm_end = VMALLOC_END,
58 * };
59 *
60 * However, vmalloc_head.vm_start is variable (typically, it is dependent on
61 * the amount of RAM found at boot time.) I would imagine that get_vm_area()
62 * would have to initialise this each time prior to calling vm_region_alloc().
63 */
64struct vm_region {
65 struct list_head vm_list;
66 unsigned long vm_start;
67 unsigned long vm_end;
68 struct page *vm_pages;
69};
70
71static struct vm_region consistent_head = {
72 .vm_list = LIST_HEAD_INIT(consistent_head.vm_list),
73 .vm_start = CONSISTENT_BASE,
74 .vm_end = CONSISTENT_END,
75};
76
77static struct vm_region *
78vm_region_alloc(struct vm_region *head, size_t size, int gfp)
79{
80 unsigned long addr = head->vm_start, end = head->vm_end - size;
81 unsigned long flags;
82 struct vm_region *c, *new;
83
84 new = kmalloc(sizeof(struct vm_region), gfp);
85 if (!new)
86 goto out;
87
88 spin_lock_irqsave(&consistent_lock, flags);
89
90 list_for_each_entry(c, &head->vm_list, vm_list) {
91 if ((addr + size) < addr)
92 goto nospc;
93 if ((addr + size) <= c->vm_start)
94 goto found;
95 addr = c->vm_end;
96 if (addr > end)
97 goto nospc;
98 }
99
100 found:
101 /*
102 * Insert this entry _before_ the one we found.
103 */
104 list_add_tail(&new->vm_list, &c->vm_list);
105 new->vm_start = addr;
106 new->vm_end = addr + size;
107
108 spin_unlock_irqrestore(&consistent_lock, flags);
109 return new;
110
111 nospc:
112 spin_unlock_irqrestore(&consistent_lock, flags);
113 kfree(new);
114 out:
115 return NULL;
116}
117
118static struct vm_region *vm_region_find(struct vm_region *head, unsigned long addr)
119{
120 struct vm_region *c;
121
122 list_for_each_entry(c, &head->vm_list, vm_list) {
123 if (c->vm_start == addr)
124 goto out;
125 }
126 c = NULL;
127 out:
128 return c;
129}
130
131#ifdef CONFIG_HUGETLB_PAGE
132#error ARM Coherent DMA allocator does not (yet) support huge TLB
133#endif
134
135static void *
136__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, int gfp,
137 pgprot_t prot)
138{
139 struct page *page;
140 struct vm_region *c;
141 unsigned long order;
142 u64 mask = ISA_DMA_THRESHOLD, limit;
143
144 if (!consistent_pte) {
145 printk(KERN_ERR "%s: not initialised\n", __func__);
146 dump_stack();
147 return NULL;
148 }
149
150 if (dev) {
151 mask = dev->coherent_dma_mask;
152
153 /*
154 * Sanity check the DMA mask - it must be non-zero, and
155 * must be able to be satisfied by a DMA allocation.
156 */
157 if (mask == 0) {
158 dev_warn(dev, "coherent DMA mask is unset\n");
159 goto no_page;
160 }
161
162 if ((~mask) & ISA_DMA_THRESHOLD) {
163 dev_warn(dev, "coherent DMA mask %#llx is smaller "
164 "than system GFP_DMA mask %#llx\n",
165 mask, (unsigned long long)ISA_DMA_THRESHOLD);
166 goto no_page;
167 }
168 }
169
170 /*
171 * Sanity check the allocation size.
172 */
173 size = PAGE_ALIGN(size);
174 limit = (mask + 1) & ~mask;
175 if ((limit && size >= limit) ||
176 size >= (CONSISTENT_END - CONSISTENT_BASE)) {
177 printk(KERN_WARNING "coherent allocation too big "
178 "(requested %#x mask %#llx)\n", size, mask);
179 goto no_page;
180 }
181
182 order = get_order(size);
183
184 if (mask != 0xffffffff)
185 gfp |= GFP_DMA;
186
187 page = alloc_pages(gfp, order);
188 if (!page)
189 goto no_page;
190
191 /*
192 * Invalidate any data that might be lurking in the
193 * kernel direct-mapped region for device DMA.
194 */
195 {
196 unsigned long kaddr = (unsigned long)page_address(page);
197 memset(page_address(page), 0, size);
198 dmac_flush_range(kaddr, kaddr + size);
199 }
200
201 /*
202 * Allocate a virtual address in the consistent mapping region.
203 */
204 c = vm_region_alloc(&consistent_head, size,
205 gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
206 if (c) {
207 pte_t *pte = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
208 struct page *end = page + (1 << order);
209
210 c->vm_pages = page;
211
212 /*
213 * Set the "dma handle"
214 */
215 *handle = page_to_dma(dev, page);
216
217 do {
218 BUG_ON(!pte_none(*pte));
219
220 set_page_count(page, 1);
221 /*
222 * x86 does not mark the pages reserved...
223 */
224 SetPageReserved(page);
225 set_pte(pte, mk_pte(page, prot));
226 page++;
227 pte++;
228 } while (size -= PAGE_SIZE);
229
230 /*
231 * Free the otherwise unused pages.
232 */
233 while (page < end) {
234 set_page_count(page, 1);
235 __free_page(page);
236 page++;
237 }
238
239 return (void *)c->vm_start;
240 }
241
242 if (page)
243 __free_pages(page, order);
244 no_page:
245 *handle = ~0;
246 return NULL;
247}
248
249/*
250 * Allocate DMA-coherent memory space and return both the kernel remapped
251 * virtual and bus address for that space.
252 */
253void *
254dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, int gfp)
255{
256 return __dma_alloc(dev, size, handle, gfp,
257 pgprot_noncached(pgprot_kernel));
258}
259EXPORT_SYMBOL(dma_alloc_coherent);
260
261/*
262 * Allocate a writecombining region, in much the same way as
263 * dma_alloc_coherent above.
264 */
265void *
266dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, int gfp)
267{
268 return __dma_alloc(dev, size, handle, gfp,
269 pgprot_writecombine(pgprot_kernel));
270}
271EXPORT_SYMBOL(dma_alloc_writecombine);
272
273static int dma_mmap(struct device *dev, struct vm_area_struct *vma,
274 void *cpu_addr, dma_addr_t dma_addr, size_t size)
275{
276 unsigned long flags, user_size, kern_size;
277 struct vm_region *c;
278 int ret = -ENXIO;
279
280 user_size = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
281
282 spin_lock_irqsave(&consistent_lock, flags);
283 c = vm_region_find(&consistent_head, (unsigned long)cpu_addr);
284 spin_unlock_irqrestore(&consistent_lock, flags);
285
286 if (c) {
287 unsigned long off = vma->vm_pgoff;
288
289 kern_size = (c->vm_end - c->vm_start) >> PAGE_SHIFT;
290
291 if (off < kern_size &&
292 user_size <= (kern_size - off)) {
293 vma->vm_flags |= VM_RESERVED;
294 ret = remap_pfn_range(vma, vma->vm_start,
295 page_to_pfn(c->vm_pages) + off,
296 user_size << PAGE_SHIFT,
297 vma->vm_page_prot);
298 }
299 }
300
301 return ret;
302}
303
304int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
305 void *cpu_addr, dma_addr_t dma_addr, size_t size)
306{
307 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
308 return dma_mmap(dev, vma, cpu_addr, dma_addr, size);
309}
310EXPORT_SYMBOL(dma_mmap_coherent);
311
312int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma,
313 void *cpu_addr, dma_addr_t dma_addr, size_t size)
314{
315 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
316 return dma_mmap(dev, vma, cpu_addr, dma_addr, size);
317}
318EXPORT_SYMBOL(dma_mmap_writecombine);
319
320/*
321 * free a page as defined by the above mapping.
322 */
323void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle)
324{
325 struct vm_region *c;
326 unsigned long flags, addr;
327 pte_t *ptep;
328
329 size = PAGE_ALIGN(size);
330
331 spin_lock_irqsave(&consistent_lock, flags);
332
333 c = vm_region_find(&consistent_head, (unsigned long)cpu_addr);
334 if (!c)
335 goto no_area;
336
337 if ((c->vm_end - c->vm_start) != size) {
338 printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n",
339 __func__, c->vm_end - c->vm_start, size);
340 dump_stack();
341 size = c->vm_end - c->vm_start;
342 }
343
344 ptep = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
345 addr = c->vm_start;
346 do {
347 pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep);
348 unsigned long pfn;
349
350 ptep++;
351 addr += PAGE_SIZE;
352
353 if (!pte_none(pte) && pte_present(pte)) {
354 pfn = pte_pfn(pte);
355
356 if (pfn_valid(pfn)) {
357 struct page *page = pfn_to_page(pfn);
358
359 /*
360 * x86 does not mark the pages reserved...
361 */
362 ClearPageReserved(page);
363
364 __free_page(page);
365 continue;
366 }
367 }
368
369 printk(KERN_CRIT "%s: bad page in kernel page table\n",
370 __func__);
371 } while (size -= PAGE_SIZE);
372
373 flush_tlb_kernel_range(c->vm_start, c->vm_end);
374
375 list_del(&c->vm_list);
376
377 spin_unlock_irqrestore(&consistent_lock, flags);
378
379 kfree(c);
380 return;
381
382 no_area:
383 spin_unlock_irqrestore(&consistent_lock, flags);
384 printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n",
385 __func__, cpu_addr);
386 dump_stack();
387}
388EXPORT_SYMBOL(dma_free_coherent);
389
390/*
391 * Initialise the consistent memory allocation.
392 */
393static int __init consistent_init(void)
394{
395 pgd_t *pgd;
396 pmd_t *pmd;
397 pte_t *pte;
398 int ret = 0;
399
400 spin_lock(&init_mm.page_table_lock);
401
402 do {
403 pgd = pgd_offset(&init_mm, CONSISTENT_BASE);
404 pmd = pmd_alloc(&init_mm, pgd, CONSISTENT_BASE);
405 if (!pmd) {
406 printk(KERN_ERR "%s: no pmd tables\n", __func__);
407 ret = -ENOMEM;
408 break;
409 }
410 WARN_ON(!pmd_none(*pmd));
411
412 pte = pte_alloc_kernel(&init_mm, pmd, CONSISTENT_BASE);
413 if (!pte) {
414 printk(KERN_ERR "%s: no pte tables\n", __func__);
415 ret = -ENOMEM;
416 break;
417 }
418
419 consistent_pte = pte;
420 } while (0);
421
422 spin_unlock(&init_mm.page_table_lock);
423
424 return ret;
425}
426
427core_initcall(consistent_init);
428
429/*
430 * Make an area consistent for devices.
431 */
432void consistent_sync(void *vaddr, size_t size, int direction)
433{
434 unsigned long start = (unsigned long)vaddr;
435 unsigned long end = start + size;
436
437 switch (direction) {
438 case DMA_FROM_DEVICE: /* invalidate only */
439 dmac_inv_range(start, end);
440 break;
441 case DMA_TO_DEVICE: /* writeback only */
442 dmac_clean_range(start, end);
443 break;
444 case DMA_BIDIRECTIONAL: /* writeback and invalidate */
445 dmac_flush_range(start, end);
446 break;
447 default:
448 BUG();
449 }
450}
451EXPORT_SYMBOL(consistent_sync);
diff --git a/arch/arm/mm/copypage-v3.S b/arch/arm/mm/copypage-v3.S
new file mode 100644
index 000000000000..4940f1908316
--- /dev/null
+++ b/arch/arm/mm/copypage-v3.S
@@ -0,0 +1,67 @@
1/*
2 * linux/arch/arm/lib/copypage.S
3 *
4 * Copyright (C) 1995-1999 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ASM optimised string functions
11 */
12#include <linux/linkage.h>
13#include <linux/init.h>
14#include <asm/assembler.h>
15#include <asm/constants.h>
16
17 .text
18 .align 5
19/*
20 * ARMv3 optimised copy_user_page
21 *
22 * FIXME: do we need to handle cache stuff...
23 */
24ENTRY(v3_copy_user_page)
25 stmfd sp!, {r4, lr} @ 2
26 mov r2, #PAGE_SZ/64 @ 1
27 ldmia r1!, {r3, r4, ip, lr} @ 4+1
281: stmia r0!, {r3, r4, ip, lr} @ 4
29 ldmia r1!, {r3, r4, ip, lr} @ 4+1
30 stmia r0!, {r3, r4, ip, lr} @ 4
31 ldmia r1!, {r3, r4, ip, lr} @ 4+1
32 stmia r0!, {r3, r4, ip, lr} @ 4
33 ldmia r1!, {r3, r4, ip, lr} @ 4
34 subs r2, r2, #1 @ 1
35 stmia r0!, {r3, r4, ip, lr} @ 4
36 ldmneia r1!, {r3, r4, ip, lr} @ 4
37 bne 1b @ 1
38 LOADREGS(fd, sp!, {r4, pc}) @ 3
39
40 .align 5
41/*
42 * ARMv3 optimised clear_user_page
43 *
44 * FIXME: do we need to handle cache stuff...
45 */
46ENTRY(v3_clear_user_page)
47 str lr, [sp, #-4]!
48 mov r1, #PAGE_SZ/64 @ 1
49 mov r2, #0 @ 1
50 mov r3, #0 @ 1
51 mov ip, #0 @ 1
52 mov lr, #0 @ 1
531: stmia r0!, {r2, r3, ip, lr} @ 4
54 stmia r0!, {r2, r3, ip, lr} @ 4
55 stmia r0!, {r2, r3, ip, lr} @ 4
56 stmia r0!, {r2, r3, ip, lr} @ 4
57 subs r1, r1, #1 @ 1
58 bne 1b @ 1
59 ldr pc, [sp], #4
60
61 __INITDATA
62
63 .type v3_user_fns, #object
64ENTRY(v3_user_fns)
65 .long v3_clear_user_page
66 .long v3_copy_user_page
67 .size v3_user_fns, . - v3_user_fns
diff --git a/arch/arm/mm/copypage-v4mc.S b/arch/arm/mm/copypage-v4mc.S
new file mode 100644
index 000000000000..305af3dab3d8
--- /dev/null
+++ b/arch/arm/mm/copypage-v4mc.S
@@ -0,0 +1,80 @@
1/*
2 * linux/arch/arm/lib/copy_page-armv4mc.S
3 *
4 * Copyright (C) 1995-2001 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ASM optimised string functions
11 */
12#include <linux/linkage.h>
13#include <linux/init.h>
14#include <asm/constants.h>
15
16 .text
17 .align 5
18/*
19 * ARMv4 mini-dcache optimised copy_user_page
20 *
21 * We flush the destination cache lines just before we write the data into the
22 * corresponding address. Since the Dcache is read-allocate, this removes the
23 * Dcache aliasing issue. The writes will be forwarded to the write buffer,
24 * and merged as appropriate.
25 *
26 * Note: We rely on all ARMv4 processors implementing the "invalidate D line"
27 * instruction. If your processor does not supply this, you have to write your
28 * own copy_user_page that does the right thing.
29 */
30ENTRY(v4_mc_copy_user_page)
31 stmfd sp!, {r4, lr} @ 2
32 mov r4, r0
33 mov r0, r1
34 bl map_page_minicache
35 mov r1, #PAGE_SZ/64 @ 1
36 ldmia r0!, {r2, r3, ip, lr} @ 4
371: mcr p15, 0, r4, c7, c6, 1 @ 1 invalidate D line
38 stmia r4!, {r2, r3, ip, lr} @ 4
39 ldmia r0!, {r2, r3, ip, lr} @ 4+1
40 stmia r4!, {r2, r3, ip, lr} @ 4
41 ldmia r0!, {r2, r3, ip, lr} @ 4
42 mcr p15, 0, r4, c7, c6, 1 @ 1 invalidate D line
43 stmia r4!, {r2, r3, ip, lr} @ 4
44 ldmia r0!, {r2, r3, ip, lr} @ 4
45 subs r1, r1, #1 @ 1
46 stmia r4!, {r2, r3, ip, lr} @ 4
47 ldmneia r0!, {r2, r3, ip, lr} @ 4
48 bne 1b @ 1
49 ldmfd sp!, {r4, pc} @ 3
50
51 .align 5
52/*
53 * ARMv4 optimised clear_user_page
54 *
55 * Same story as above.
56 */
57ENTRY(v4_mc_clear_user_page)
58 str lr, [sp, #-4]!
59 mov r1, #PAGE_SZ/64 @ 1
60 mov r2, #0 @ 1
61 mov r3, #0 @ 1
62 mov ip, #0 @ 1
63 mov lr, #0 @ 1
641: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line
65 stmia r0!, {r2, r3, ip, lr} @ 4
66 stmia r0!, {r2, r3, ip, lr} @ 4
67 mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line
68 stmia r0!, {r2, r3, ip, lr} @ 4
69 stmia r0!, {r2, r3, ip, lr} @ 4
70 subs r1, r1, #1 @ 1
71 bne 1b @ 1
72 ldr pc, [sp], #4
73
74 __INITDATA
75
76 .type v4_mc_user_fns, #object
77ENTRY(v4_mc_user_fns)
78 .long v4_mc_clear_user_page
79 .long v4_mc_copy_user_page
80 .size v4_mc_user_fns, . - v4_mc_user_fns
diff --git a/arch/arm/mm/copypage-v4wb.S b/arch/arm/mm/copypage-v4wb.S
new file mode 100644
index 000000000000..b94c345ceb94
--- /dev/null
+++ b/arch/arm/mm/copypage-v4wb.S
@@ -0,0 +1,79 @@
1/*
2 * linux/arch/arm/lib/copypage.S
3 *
4 * Copyright (C) 1995-1999 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ASM optimised string functions
11 */
12#include <linux/linkage.h>
13#include <linux/init.h>
14#include <asm/constants.h>
15
16 .text
17 .align 5
18/*
19 * ARMv4 optimised copy_user_page
20 *
21 * We flush the destination cache lines just before we write the data into the
22 * corresponding address. Since the Dcache is read-allocate, this removes the
23 * Dcache aliasing issue. The writes will be forwarded to the write buffer,
24 * and merged as appropriate.
25 *
26 * Note: We rely on all ARMv4 processors implementing the "invalidate D line"
27 * instruction. If your processor does not supply this, you have to write your
28 * own copy_user_page that does the right thing.
29 */
30ENTRY(v4wb_copy_user_page)
31 stmfd sp!, {r4, lr} @ 2
32 mov r2, #PAGE_SZ/64 @ 1
33 ldmia r1!, {r3, r4, ip, lr} @ 4
341: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line
35 stmia r0!, {r3, r4, ip, lr} @ 4
36 ldmia r1!, {r3, r4, ip, lr} @ 4+1
37 stmia r0!, {r3, r4, ip, lr} @ 4
38 ldmia r1!, {r3, r4, ip, lr} @ 4
39 mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line
40 stmia r0!, {r3, r4, ip, lr} @ 4
41 ldmia r1!, {r3, r4, ip, lr} @ 4
42 subs r2, r2, #1 @ 1
43 stmia r0!, {r3, r4, ip, lr} @ 4
44 ldmneia r1!, {r3, r4, ip, lr} @ 4
45 bne 1b @ 1
46 mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB
47 ldmfd sp!, {r4, pc} @ 3
48
49 .align 5
50/*
51 * ARMv4 optimised clear_user_page
52 *
53 * Same story as above.
54 */
55ENTRY(v4wb_clear_user_page)
56 str lr, [sp, #-4]!
57 mov r1, #PAGE_SZ/64 @ 1
58 mov r2, #0 @ 1
59 mov r3, #0 @ 1
60 mov ip, #0 @ 1
61 mov lr, #0 @ 1
621: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line
63 stmia r0!, {r2, r3, ip, lr} @ 4
64 stmia r0!, {r2, r3, ip, lr} @ 4
65 mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line
66 stmia r0!, {r2, r3, ip, lr} @ 4
67 stmia r0!, {r2, r3, ip, lr} @ 4
68 subs r1, r1, #1 @ 1
69 bne 1b @ 1
70 mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB
71 ldr pc, [sp], #4
72
73 __INITDATA
74
75 .type v4wb_user_fns, #object
76ENTRY(v4wb_user_fns)
77 .long v4wb_clear_user_page
78 .long v4wb_copy_user_page
79 .size v4wb_user_fns, . - v4wb_user_fns
diff --git a/arch/arm/mm/copypage-v4wt.S b/arch/arm/mm/copypage-v4wt.S
new file mode 100644
index 000000000000..976793937a93
--- /dev/null
+++ b/arch/arm/mm/copypage-v4wt.S
@@ -0,0 +1,73 @@
1/*
2 * linux/arch/arm/lib/copypage-v4.S
3 *
4 * Copyright (C) 1995-1999 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ASM optimised string functions
11 *
12 * This is for CPUs with a writethrough cache and 'flush ID cache' is
13 * the only supported cache operation.
14 */
15#include <linux/linkage.h>
16#include <linux/init.h>
17#include <asm/constants.h>
18
19 .text
20 .align 5
21/*
22 * ARMv4 optimised copy_user_page
23 *
24 * Since we have writethrough caches, we don't have to worry about
25 * dirty data in the cache. However, we do have to ensure that
26 * subsequent reads are up to date.
27 */
28ENTRY(v4wt_copy_user_page)
29 stmfd sp!, {r4, lr} @ 2
30 mov r2, #PAGE_SZ/64 @ 1
31 ldmia r1!, {r3, r4, ip, lr} @ 4
321: stmia r0!, {r3, r4, ip, lr} @ 4
33 ldmia r1!, {r3, r4, ip, lr} @ 4+1
34 stmia r0!, {r3, r4, ip, lr} @ 4
35 ldmia r1!, {r3, r4, ip, lr} @ 4
36 stmia r0!, {r3, r4, ip, lr} @ 4
37 ldmia r1!, {r3, r4, ip, lr} @ 4
38 subs r2, r2, #1 @ 1
39 stmia r0!, {r3, r4, ip, lr} @ 4
40 ldmneia r1!, {r3, r4, ip, lr} @ 4
41 bne 1b @ 1
42 mcr p15, 0, r2, c7, c7, 0 @ flush ID cache
43 ldmfd sp!, {r4, pc} @ 3
44
45 .align 5
46/*
47 * ARMv4 optimised clear_user_page
48 *
49 * Same story as above.
50 */
51ENTRY(v4wt_clear_user_page)
52 str lr, [sp, #-4]!
53 mov r1, #PAGE_SZ/64 @ 1
54 mov r2, #0 @ 1
55 mov r3, #0 @ 1
56 mov ip, #0 @ 1
57 mov lr, #0 @ 1
581: stmia r0!, {r2, r3, ip, lr} @ 4
59 stmia r0!, {r2, r3, ip, lr} @ 4
60 stmia r0!, {r2, r3, ip, lr} @ 4
61 stmia r0!, {r2, r3, ip, lr} @ 4
62 subs r1, r1, #1 @ 1
63 bne 1b @ 1
64 mcr p15, 0, r2, c7, c7, 0 @ flush ID cache
65 ldr pc, [sp], #4
66
67 __INITDATA
68
69 .type v4wt_user_fns, #object
70ENTRY(v4wt_user_fns)
71 .long v4wt_clear_user_page
72 .long v4wt_copy_user_page
73 .size v4wt_user_fns, . - v4wt_user_fns
diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c
new file mode 100644
index 000000000000..694ac8208858
--- /dev/null
+++ b/arch/arm/mm/copypage-v6.c
@@ -0,0 +1,155 @@
1/*
2 * linux/arch/arm/mm/copypage-v6.c
3 *
4 * Copyright (C) 2002 Deep Blue Solutions Ltd, All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/init.h>
11#include <linux/spinlock.h>
12#include <linux/mm.h>
13
14#include <asm/page.h>
15#include <asm/pgtable.h>
16#include <asm/shmparam.h>
17#include <asm/tlbflush.h>
18#include <asm/cacheflush.h>
19
20#if SHMLBA > 16384
21#error FIX ME
22#endif
23
24#define from_address (0xffff8000)
25#define from_pgprot PAGE_KERNEL
26#define to_address (0xffffc000)
27#define to_pgprot PAGE_KERNEL
28
29static pte_t *from_pte;
30static pte_t *to_pte;
31static DEFINE_SPINLOCK(v6_lock);
32
33#define DCACHE_COLOUR(vaddr) ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT)
34
35/*
36 * Copy the user page. No aliasing to deal with so we can just
37 * attack the kernel's existing mapping of these pages.
38 */
39void v6_copy_user_page_nonaliasing(void *kto, const void *kfrom, unsigned long vaddr)
40{
41 copy_page(kto, kfrom);
42}
43
44/*
45 * Clear the user page. No aliasing to deal with so we can just
46 * attack the kernel's existing mapping of this page.
47 */
48void v6_clear_user_page_nonaliasing(void *kaddr, unsigned long vaddr)
49{
50 clear_page(kaddr);
51}
52
53/*
54 * Copy the page, taking account of the cache colour.
55 */
56void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned long vaddr)
57{
58 unsigned int offset = DCACHE_COLOUR(vaddr);
59 unsigned long from, to;
60
61 /*
62 * Discard data in the kernel mapping for the new page.
63 * FIXME: needs this MCRR to be supported.
64 */
65 __asm__("mcrr p15, 0, %1, %0, c6 @ 0xec401f06"
66 :
67 : "r" (kto),
68 "r" ((unsigned long)kto + PAGE_SIZE - L1_CACHE_BYTES)
69 : "cc");
70
71 /*
72 * Now copy the page using the same cache colour as the
73 * pages ultimate destination.
74 */
75 spin_lock(&v6_lock);
76
77 set_pte(from_pte + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, from_pgprot));
78 set_pte(to_pte + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, to_pgprot));
79
80 from = from_address + (offset << PAGE_SHIFT);
81 to = to_address + (offset << PAGE_SHIFT);
82
83 flush_tlb_kernel_page(from);
84 flush_tlb_kernel_page(to);
85
86 copy_page((void *)to, (void *)from);
87
88 spin_unlock(&v6_lock);
89}
90
91/*
92 * Clear the user page. We need to deal with the aliasing issues,
93 * so remap the kernel page into the same cache colour as the user
94 * page.
95 */
96void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr)
97{
98 unsigned int offset = DCACHE_COLOUR(vaddr);
99 unsigned long to = to_address + (offset << PAGE_SHIFT);
100
101 /*
102 * Discard data in the kernel mapping for the new page
103 * FIXME: needs this MCRR to be supported.
104 */
105 __asm__("mcrr p15, 0, %1, %0, c6 @ 0xec401f06"
106 :
107 : "r" (kaddr),
108 "r" ((unsigned long)kaddr + PAGE_SIZE - L1_CACHE_BYTES)
109 : "cc");
110
111 /*
112 * Now clear the page using the same cache colour as
113 * the pages ultimate destination.
114 */
115 spin_lock(&v6_lock);
116
117 set_pte(to_pte + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, to_pgprot));
118 flush_tlb_kernel_page(to);
119 clear_page((void *)to);
120
121 spin_unlock(&v6_lock);
122}
123
124struct cpu_user_fns v6_user_fns __initdata = {
125 .cpu_clear_user_page = v6_clear_user_page_nonaliasing,
126 .cpu_copy_user_page = v6_copy_user_page_nonaliasing,
127};
128
129static int __init v6_userpage_init(void)
130{
131 if (cache_is_vipt_aliasing()) {
132 pgd_t *pgd;
133 pmd_t *pmd;
134
135 pgd = pgd_offset_k(from_address);
136 pmd = pmd_alloc(&init_mm, pgd, from_address);
137 if (!pmd)
138 BUG();
139 from_pte = pte_alloc_kernel(&init_mm, pmd, from_address);
140 if (!from_pte)
141 BUG();
142
143 to_pte = pte_alloc_kernel(&init_mm, pmd, to_address);
144 if (!to_pte)
145 BUG();
146
147 cpu_user.cpu_clear_user_page = v6_clear_user_page_aliasing;
148 cpu_user.cpu_copy_user_page = v6_copy_user_page_aliasing;
149 }
150
151 return 0;
152}
153
154__initcall(v6_userpage_init);
155
diff --git a/arch/arm/mm/copypage-xscale.S b/arch/arm/mm/copypage-xscale.S
new file mode 100644
index 000000000000..bb277316ef52
--- /dev/null
+++ b/arch/arm/mm/copypage-xscale.S
@@ -0,0 +1,113 @@
1/*
2 * linux/arch/arm/lib/copypage-xscale.S
3 *
4 * Copyright (C) 2001 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/linkage.h>
11#include <linux/init.h>
12#include <asm/constants.h>
13
14/*
15 * General note:
16 * We don't really want write-allocate cache behaviour for these functions
17 * since that will just eat through 8K of the cache.
18 */
19
20 .text
21 .align 5
22/*
23 * XScale optimised copy_user_page
24 * r0 = destination
25 * r1 = source
26 * r2 = virtual user address of ultimate destination page
27 *
28 * The source page may have some clean entries in the cache already, but we
29 * can safely ignore them - break_cow() will flush them out of the cache
30 * if we eventually end up using our copied page.
31 *
32 * What we could do is use the mini-cache to buffer reads from the source
33 * page. We rely on the mini-cache being smaller than one page, so we'll
34 * cycle through the complete cache anyway.
35 */
36ENTRY(xscale_mc_copy_user_page)
37 stmfd sp!, {r4, r5, lr}
38 mov r5, r0
39 mov r0, r1
40 bl map_page_minicache
41 mov r1, r5
42 mov lr, #PAGE_SZ/64-1
43
44 /*
45 * Strangely enough, best performance is achieved
46 * when prefetching destination as well. (NP)
47 */
48 pld [r0, #0]
49 pld [r0, #32]
50 pld [r1, #0]
51 pld [r1, #32]
52
531: pld [r0, #64]
54 pld [r0, #96]
55 pld [r1, #64]
56 pld [r1, #96]
57
582: ldrd r2, [r0], #8
59 ldrd r4, [r0], #8
60 mov ip, r1
61 strd r2, [r1], #8
62 ldrd r2, [r0], #8
63 strd r4, [r1], #8
64 ldrd r4, [r0], #8
65 strd r2, [r1], #8
66 strd r4, [r1], #8
67 mcr p15, 0, ip, c7, c10, 1 @ clean D line
68 ldrd r2, [r0], #8
69 mcr p15, 0, ip, c7, c6, 1 @ invalidate D line
70 ldrd r4, [r0], #8
71 mov ip, r1
72 strd r2, [r1], #8
73 ldrd r2, [r0], #8
74 strd r4, [r1], #8
75 ldrd r4, [r0], #8
76 strd r2, [r1], #8
77 strd r4, [r1], #8
78 mcr p15, 0, ip, c7, c10, 1 @ clean D line
79 subs lr, lr, #1
80 mcr p15, 0, ip, c7, c6, 1 @ invalidate D line
81 bgt 1b
82 beq 2b
83
84 ldmfd sp!, {r4, r5, pc}
85
86 .align 5
87/*
88 * XScale optimised clear_user_page
89 * r0 = destination
90 * r1 = virtual user address of ultimate destination page
91 */
92ENTRY(xscale_mc_clear_user_page)
93 mov r1, #PAGE_SZ/32
94 mov r2, #0
95 mov r3, #0
961: mov ip, r0
97 strd r2, [r0], #8
98 strd r2, [r0], #8
99 strd r2, [r0], #8
100 strd r2, [r0], #8
101 mcr p15, 0, ip, c7, c10, 1 @ clean D line
102 subs r1, r1, #1
103 mcr p15, 0, ip, c7, c6, 1 @ invalidate D line
104 bne 1b
105 mov pc, lr
106
107 __INITDATA
108
109 .type xscale_mc_user_fns, #object
110ENTRY(xscale_mc_user_fns)
111 .long xscale_mc_clear_user_page
112 .long xscale_mc_copy_user_page
113 .size xscale_mc_user_fns, . - xscale_mc_user_fns
diff --git a/arch/arm/mm/discontig.c b/arch/arm/mm/discontig.c
new file mode 100644
index 000000000000..0d097bb1bc4d
--- /dev/null
+++ b/arch/arm/mm/discontig.c
@@ -0,0 +1,49 @@
1/*
2 * linux/arch/arm/mm/discontig.c
3 *
4 * Discontiguous memory support.
5 *
6 * Initial code: Copyright (C) 1999-2000 Nicolas Pitre
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/module.h>
14#include <linux/mm.h>
15#include <linux/init.h>
16#include <linux/bootmem.h>
17
18#if MAX_NUMNODES != 4 && MAX_NUMNODES != 16
19# error Fix Me Please
20#endif
21
22/*
23 * Our node_data structure for discontiguous memory.
24 */
25
26static bootmem_data_t node_bootmem_data[MAX_NUMNODES];
27
28pg_data_t discontig_node_data[MAX_NUMNODES] = {
29 { .bdata = &node_bootmem_data[0] },
30 { .bdata = &node_bootmem_data[1] },
31 { .bdata = &node_bootmem_data[2] },
32 { .bdata = &node_bootmem_data[3] },
33#if MAX_NUMNODES == 16
34 { .bdata = &node_bootmem_data[4] },
35 { .bdata = &node_bootmem_data[5] },
36 { .bdata = &node_bootmem_data[6] },
37 { .bdata = &node_bootmem_data[7] },
38 { .bdata = &node_bootmem_data[8] },
39 { .bdata = &node_bootmem_data[9] },
40 { .bdata = &node_bootmem_data[10] },
41 { .bdata = &node_bootmem_data[11] },
42 { .bdata = &node_bootmem_data[12] },
43 { .bdata = &node_bootmem_data[13] },
44 { .bdata = &node_bootmem_data[14] },
45 { .bdata = &node_bootmem_data[15] },
46#endif
47};
48
49EXPORT_SYMBOL(discontig_node_data);
diff --git a/arch/arm/mm/extable.c b/arch/arm/mm/extable.c
new file mode 100644
index 000000000000..9592c3ee4cb2
--- /dev/null
+++ b/arch/arm/mm/extable.c
@@ -0,0 +1,16 @@
1/*
2 * linux/arch/arm/mm/extable.c
3 */
4#include <linux/module.h>
5#include <asm/uaccess.h>
6
7int fixup_exception(struct pt_regs *regs)
8{
9 const struct exception_table_entry *fixup;
10
11 fixup = search_exception_tables(instruction_pointer(regs));
12 if (fixup)
13 regs->ARM_pc = fixup->fixup;
14
15 return fixup != NULL;
16}
diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c
new file mode 100644
index 000000000000..01967ddeef53
--- /dev/null
+++ b/arch/arm/mm/fault-armv.c
@@ -0,0 +1,223 @@
1/*
2 * linux/arch/arm/mm/fault-armv.c
3 *
4 * Copyright (C) 1995 Linus Torvalds
5 * Modifications for ARM processor (c) 1995-2002 Russell King
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#include <linux/module.h>
12#include <linux/sched.h>
13#include <linux/kernel.h>
14#include <linux/mm.h>
15#include <linux/bitops.h>
16#include <linux/vmalloc.h>
17#include <linux/init.h>
18#include <linux/pagemap.h>
19
20#include <asm/cacheflush.h>
21#include <asm/pgtable.h>
22#include <asm/tlbflush.h>
23
24static unsigned long shared_pte_mask = L_PTE_CACHEABLE;
25
26/*
27 * We take the easy way out of this problem - we make the
28 * PTE uncacheable. However, we leave the write buffer on.
29 */
30static int adjust_pte(struct vm_area_struct *vma, unsigned long address)
31{
32 pgd_t *pgd;
33 pmd_t *pmd;
34 pte_t *pte, entry;
35 int ret = 0;
36
37 pgd = pgd_offset(vma->vm_mm, address);
38 if (pgd_none(*pgd))
39 goto no_pgd;
40 if (pgd_bad(*pgd))
41 goto bad_pgd;
42
43 pmd = pmd_offset(pgd, address);
44 if (pmd_none(*pmd))
45 goto no_pmd;
46 if (pmd_bad(*pmd))
47 goto bad_pmd;
48
49 pte = pte_offset_map(pmd, address);
50 entry = *pte;
51
52 /*
53 * If this page isn't present, or is already setup to
54 * fault (ie, is old), we can safely ignore any issues.
55 */
56 if (pte_present(entry) && pte_val(entry) & shared_pte_mask) {
57 flush_cache_page(vma, address, pte_pfn(entry));
58 pte_val(entry) &= ~shared_pte_mask;
59 set_pte(pte, entry);
60 flush_tlb_page(vma, address);
61 ret = 1;
62 }
63 pte_unmap(pte);
64 return ret;
65
66bad_pgd:
67 pgd_ERROR(*pgd);
68 pgd_clear(pgd);
69no_pgd:
70 return 0;
71
72bad_pmd:
73 pmd_ERROR(*pmd);
74 pmd_clear(pmd);
75no_pmd:
76 return 0;
77}
78
79static void
80make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page, int dirty)
81{
82 struct address_space *mapping = page_mapping(page);
83 struct mm_struct *mm = vma->vm_mm;
84 struct vm_area_struct *mpnt;
85 struct prio_tree_iter iter;
86 unsigned long offset;
87 pgoff_t pgoff;
88 int aliases = 0;
89
90 if (!mapping)
91 return;
92
93 pgoff = vma->vm_pgoff + ((addr - vma->vm_start) >> PAGE_SHIFT);
94
95 /*
96 * If we have any shared mappings that are in the same mm
97 * space, then we need to handle them specially to maintain
98 * cache coherency.
99 */
100 flush_dcache_mmap_lock(mapping);
101 vma_prio_tree_foreach(mpnt, &iter, &mapping->i_mmap, pgoff, pgoff) {
102 /*
103 * If this VMA is not in our MM, we can ignore it.
104 * Note that we intentionally mask out the VMA
105 * that we are fixing up.
106 */
107 if (mpnt->vm_mm != mm || mpnt == vma)
108 continue;
109 if (!(mpnt->vm_flags & VM_MAYSHARE))
110 continue;
111 offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT;
112 aliases += adjust_pte(mpnt, mpnt->vm_start + offset);
113 }
114 flush_dcache_mmap_unlock(mapping);
115 if (aliases)
116 adjust_pte(vma, addr);
117 else
118 flush_cache_page(vma, addr, page_to_pfn(page));
119}
120
121/*
122 * Take care of architecture specific things when placing a new PTE into
123 * a page table, or changing an existing PTE. Basically, there are two
124 * things that we need to take care of:
125 *
126 * 1. If PG_dcache_dirty is set for the page, we need to ensure
127 * that any cache entries for the kernels virtual memory
128 * range are written back to the page.
129 * 2. If we have multiple shared mappings of the same space in
130 * an object, we need to deal with the cache aliasing issues.
131 *
132 * Note that the page_table_lock will be held.
133 */
134void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
135{
136 unsigned long pfn = pte_pfn(pte);
137 struct page *page;
138
139 if (!pfn_valid(pfn))
140 return;
141 page = pfn_to_page(pfn);
142 if (page_mapping(page)) {
143 int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags);
144
145 if (dirty) {
146 /*
147 * This is our first userspace mapping of this page.
148 * Ensure that the physical page is coherent with
149 * the kernel mapping.
150 *
151 * FIXME: only need to do this on VIVT and aliasing
152 * VIPT cache architectures. We can do that
153 * by choosing whether to set this bit...
154 */
155 __cpuc_flush_dcache_page(page_address(page));
156 }
157
158 if (cache_is_vivt())
159 make_coherent(vma, addr, page, dirty);
160 }
161}
162
163/*
164 * Check whether the write buffer has physical address aliasing
165 * issues. If it has, we need to avoid them for the case where
166 * we have several shared mappings of the same object in user
167 * space.
168 */
169static int __init check_writebuffer(unsigned long *p1, unsigned long *p2)
170{
171 register unsigned long zero = 0, one = 1, val;
172
173 local_irq_disable();
174 mb();
175 *p1 = one;
176 mb();
177 *p2 = zero;
178 mb();
179 val = *p1;
180 mb();
181 local_irq_enable();
182 return val != zero;
183}
184
185void __init check_writebuffer_bugs(void)
186{
187 struct page *page;
188 const char *reason;
189 unsigned long v = 1;
190
191 printk(KERN_INFO "CPU: Testing write buffer coherency: ");
192
193 page = alloc_page(GFP_KERNEL);
194 if (page) {
195 unsigned long *p1, *p2;
196 pgprot_t prot = __pgprot(L_PTE_PRESENT|L_PTE_YOUNG|
197 L_PTE_DIRTY|L_PTE_WRITE|
198 L_PTE_BUFFERABLE);
199
200 p1 = vmap(&page, 1, VM_IOREMAP, prot);
201 p2 = vmap(&page, 1, VM_IOREMAP, prot);
202
203 if (p1 && p2) {
204 v = check_writebuffer(p1, p2);
205 reason = "enabling work-around";
206 } else {
207 reason = "unable to map memory\n";
208 }
209
210 vunmap(p1);
211 vunmap(p2);
212 put_page(page);
213 } else {
214 reason = "unable to grab page\n";
215 }
216
217 if (v) {
218 printk("failed, %s\n", reason);
219 shared_pte_mask |= L_PTE_BUFFERABLE;
220 } else {
221 printk("ok\n");
222 }
223}
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
new file mode 100644
index 000000000000..29be1c018949
--- /dev/null
+++ b/arch/arm/mm/fault.c
@@ -0,0 +1,462 @@
1/*
2 * linux/arch/arm/mm/fault.c
3 *
4 * Copyright (C) 1995 Linus Torvalds
5 * Modifications for ARM processor (c) 1995-2004 Russell King
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#include <linux/config.h>
12#include <linux/module.h>
13#include <linux/signal.h>
14#include <linux/ptrace.h>
15#include <linux/mm.h>
16#include <linux/init.h>
17
18#include <asm/system.h>
19#include <asm/pgtable.h>
20#include <asm/tlbflush.h>
21#include <asm/uaccess.h>
22
23#include "fault.h"
24
25/*
26 * This is useful to dump out the page tables associated with
27 * 'addr' in mm 'mm'.
28 */
29void show_pte(struct mm_struct *mm, unsigned long addr)
30{
31 pgd_t *pgd;
32
33 if (!mm)
34 mm = &init_mm;
35
36 printk(KERN_ALERT "pgd = %p\n", mm->pgd);
37 pgd = pgd_offset(mm, addr);
38 printk(KERN_ALERT "[%08lx] *pgd=%08lx", addr, pgd_val(*pgd));
39
40 do {
41 pmd_t *pmd;
42 pte_t *pte;
43
44 if (pgd_none(*pgd))
45 break;
46
47 if (pgd_bad(*pgd)) {
48 printk("(bad)");
49 break;
50 }
51
52 pmd = pmd_offset(pgd, addr);
53#if PTRS_PER_PMD != 1
54 printk(", *pmd=%08lx", pmd_val(*pmd));
55#endif
56
57 if (pmd_none(*pmd))
58 break;
59
60 if (pmd_bad(*pmd)) {
61 printk("(bad)");
62 break;
63 }
64
65#ifndef CONFIG_HIGHMEM
66 /* We must not map this if we have highmem enabled */
67 pte = pte_offset_map(pmd, addr);
68 printk(", *pte=%08lx", pte_val(*pte));
69 printk(", *ppte=%08lx", pte_val(pte[-PTRS_PER_PTE]));
70 pte_unmap(pte);
71#endif
72 } while(0);
73
74 printk("\n");
75}
76
77/*
78 * Oops. The kernel tried to access some page that wasn't present.
79 */
80static void
81__do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
82 struct pt_regs *regs)
83{
84 /*
85 * Are we prepared to handle this kernel fault?
86 */
87 if (fixup_exception(regs))
88 return;
89
90 /*
91 * No handler, we'll have to terminate things with extreme prejudice.
92 */
93 bust_spinlocks(1);
94 printk(KERN_ALERT
95 "Unable to handle kernel %s at virtual address %08lx\n",
96 (addr < PAGE_SIZE) ? "NULL pointer dereference" :
97 "paging request", addr);
98
99 show_pte(mm, addr);
100 die("Oops", regs, fsr);
101 bust_spinlocks(0);
102 do_exit(SIGKILL);
103}
104
105/*
106 * Something tried to access memory that isn't in our memory map..
107 * User mode accesses just cause a SIGSEGV
108 */
109static void
110__do_user_fault(struct task_struct *tsk, unsigned long addr,
111 unsigned int fsr, int code, struct pt_regs *regs)
112{
113 struct siginfo si;
114
115#ifdef CONFIG_DEBUG_USER
116 if (user_debug & UDBG_SEGV) {
117 printk(KERN_DEBUG "%s: unhandled page fault at 0x%08lx, code 0x%03x\n",
118 tsk->comm, addr, fsr);
119 show_pte(tsk->mm, addr);
120 show_regs(regs);
121 }
122#endif
123
124 tsk->thread.address = addr;
125 tsk->thread.error_code = fsr;
126 tsk->thread.trap_no = 14;
127 si.si_signo = SIGSEGV;
128 si.si_errno = 0;
129 si.si_code = code;
130 si.si_addr = (void __user *)addr;
131 force_sig_info(SIGSEGV, &si, tsk);
132}
133
134void
135do_bad_area(struct task_struct *tsk, struct mm_struct *mm, unsigned long addr,
136 unsigned int fsr, struct pt_regs *regs)
137{
138 /*
139 * If we are in kernel mode at this point, we
140 * have no context to handle this fault with.
141 */
142 if (user_mode(regs))
143 __do_user_fault(tsk, addr, fsr, SEGV_MAPERR, regs);
144 else
145 __do_kernel_fault(mm, addr, fsr, regs);
146}
147
148#define VM_FAULT_BADMAP (-20)
149#define VM_FAULT_BADACCESS (-21)
150
151static int
152__do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
153 struct task_struct *tsk)
154{
155 struct vm_area_struct *vma;
156 int fault, mask;
157
158 vma = find_vma(mm, addr);
159 fault = VM_FAULT_BADMAP;
160 if (!vma)
161 goto out;
162 if (vma->vm_start > addr)
163 goto check_stack;
164
165 /*
166 * Ok, we have a good vm_area for this
167 * memory access, so we can handle it.
168 */
169good_area:
170 if (fsr & (1 << 11)) /* write? */
171 mask = VM_WRITE;
172 else
173 mask = VM_READ|VM_EXEC;
174
175 fault = VM_FAULT_BADACCESS;
176 if (!(vma->vm_flags & mask))
177 goto out;
178
179 /*
180 * If for any reason at all we couldn't handle
181 * the fault, make sure we exit gracefully rather
182 * than endlessly redo the fault.
183 */
184survive:
185 fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, fsr & (1 << 11));
186
187 /*
188 * Handle the "normal" cases first - successful and sigbus
189 */
190 switch (fault) {
191 case VM_FAULT_MAJOR:
192 tsk->maj_flt++;
193 return fault;
194 case VM_FAULT_MINOR:
195 tsk->min_flt++;
196 case VM_FAULT_SIGBUS:
197 return fault;
198 }
199
200 if (tsk->pid != 1)
201 goto out;
202
203 /*
204 * If we are out of memory for pid1,
205 * sleep for a while and retry
206 */
207 yield();
208 goto survive;
209
210check_stack:
211 if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr))
212 goto good_area;
213out:
214 return fault;
215}
216
217static int
218do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
219{
220 struct task_struct *tsk;
221 struct mm_struct *mm;
222 int fault;
223
224 tsk = current;
225 mm = tsk->mm;
226
227 /*
228 * If we're in an interrupt or have no user
229 * context, we must not take the fault..
230 */
231 if (in_interrupt() || !mm)
232 goto no_context;
233
234 down_read(&mm->mmap_sem);
235 fault = __do_page_fault(mm, addr, fsr, tsk);
236 up_read(&mm->mmap_sem);
237
238 /*
239 * Handle the "normal" case first
240 */
241 if (fault > 0)
242 return 0;
243
244 /*
245 * We had some memory, but were unable to
246 * successfully fix up this page fault.
247 */
248 if (fault == 0)
249 goto do_sigbus;
250
251 /*
252 * If we are in kernel mode at this point, we
253 * have no context to handle this fault with.
254 */
255 if (!user_mode(regs))
256 goto no_context;
257
258 if (fault == VM_FAULT_OOM) {
259 /*
260 * We ran out of memory, or some other thing happened to
261 * us that made us unable to handle the page fault gracefully.
262 */
263 printk("VM: killing process %s\n", tsk->comm);
264 do_exit(SIGKILL);
265 } else
266 __do_user_fault(tsk, addr, fsr, fault == VM_FAULT_BADACCESS ?
267 SEGV_ACCERR : SEGV_MAPERR, regs);
268 return 0;
269
270
271/*
272 * We ran out of memory, or some other thing happened to us that made
273 * us unable to handle the page fault gracefully.
274 */
275do_sigbus:
276 /*
277 * Send a sigbus, regardless of whether we were in kernel
278 * or user mode.
279 */
280 tsk->thread.address = addr;
281 tsk->thread.error_code = fsr;
282 tsk->thread.trap_no = 14;
283 force_sig(SIGBUS, tsk);
284#ifdef CONFIG_DEBUG_USER
285 if (user_debug & UDBG_BUS) {
286 printk(KERN_DEBUG "%s: sigbus at 0x%08lx, pc=0x%08lx\n",
287 current->comm, addr, instruction_pointer(regs));
288 }
289#endif
290
291 /* Kernel mode? Handle exceptions or die */
292 if (user_mode(regs))
293 return 0;
294
295no_context:
296 __do_kernel_fault(mm, addr, fsr, regs);
297 return 0;
298}
299
300/*
301 * First Level Translation Fault Handler
302 *
303 * We enter here because the first level page table doesn't contain
304 * a valid entry for the address.
305 *
306 * If the address is in kernel space (>= TASK_SIZE), then we are
307 * probably faulting in the vmalloc() area.
308 *
309 * If the init_task's first level page tables contains the relevant
310 * entry, we copy the it to this task. If not, we send the process
311 * a signal, fixup the exception, or oops the kernel.
312 *
313 * NOTE! We MUST NOT take any locks for this case. We may be in an
314 * interrupt or a critical region, and should only copy the information
315 * from the master page table, nothing more.
316 */
317static int
318do_translation_fault(unsigned long addr, unsigned int fsr,
319 struct pt_regs *regs)
320{
321 struct task_struct *tsk;
322 unsigned int index;
323 pgd_t *pgd, *pgd_k;
324 pmd_t *pmd, *pmd_k;
325
326 if (addr < TASK_SIZE)
327 return do_page_fault(addr, fsr, regs);
328
329 index = pgd_index(addr);
330
331 /*
332 * FIXME: CP15 C1 is write only on ARMv3 architectures.
333 */
334 pgd = cpu_get_pgd() + index;
335 pgd_k = init_mm.pgd + index;
336
337 if (pgd_none(*pgd_k))
338 goto bad_area;
339
340 if (!pgd_present(*pgd))
341 set_pgd(pgd, *pgd_k);
342
343 pmd_k = pmd_offset(pgd_k, addr);
344 pmd = pmd_offset(pgd, addr);
345
346 if (pmd_none(*pmd_k))
347 goto bad_area;
348
349 copy_pmd(pmd, pmd_k);
350 return 0;
351
352bad_area:
353 tsk = current;
354
355 do_bad_area(tsk, tsk->active_mm, addr, fsr, regs);
356 return 0;
357}
358
359/*
360 * Some section permission faults need to be handled gracefully.
361 * They can happen due to a __{get,put}_user during an oops.
362 */
363static int
364do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
365{
366 struct task_struct *tsk = current;
367 do_bad_area(tsk, tsk->active_mm, addr, fsr, regs);
368 return 0;
369}
370
371/*
372 * This abort handler always returns "fault".
373 */
374static int
375do_bad(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
376{
377 return 1;
378}
379
380static struct fsr_info {
381 int (*fn)(unsigned long addr, unsigned int fsr, struct pt_regs *regs);
382 int sig;
383 const char *name;
384} fsr_info[] = {
385 /*
386 * The following are the standard ARMv3 and ARMv4 aborts. ARMv5
387 * defines these to be "precise" aborts.
388 */
389 { do_bad, SIGSEGV, "vector exception" },
390 { do_bad, SIGILL, "alignment exception" },
391 { do_bad, SIGKILL, "terminal exception" },
392 { do_bad, SIGILL, "alignment exception" },
393 { do_bad, SIGBUS, "external abort on linefetch" },
394 { do_translation_fault, SIGSEGV, "section translation fault" },
395 { do_bad, SIGBUS, "external abort on linefetch" },
396 { do_page_fault, SIGSEGV, "page translation fault" },
397 { do_bad, SIGBUS, "external abort on non-linefetch" },
398 { do_bad, SIGSEGV, "section domain fault" },
399 { do_bad, SIGBUS, "external abort on non-linefetch" },
400 { do_bad, SIGSEGV, "page domain fault" },
401 { do_bad, SIGBUS, "external abort on translation" },
402 { do_sect_fault, SIGSEGV, "section permission fault" },
403 { do_bad, SIGBUS, "external abort on translation" },
404 { do_page_fault, SIGSEGV, "page permission fault" },
405 /*
406 * The following are "imprecise" aborts, which are signalled by bit
407 * 10 of the FSR, and may not be recoverable. These are only
408 * supported if the CPU abort handler supports bit 10.
409 */
410 { do_bad, SIGBUS, "unknown 16" },
411 { do_bad, SIGBUS, "unknown 17" },
412 { do_bad, SIGBUS, "unknown 18" },
413 { do_bad, SIGBUS, "unknown 19" },
414 { do_bad, SIGBUS, "lock abort" }, /* xscale */
415 { do_bad, SIGBUS, "unknown 21" },
416 { do_bad, SIGBUS, "imprecise external abort" }, /* xscale */
417 { do_bad, SIGBUS, "unknown 23" },
418 { do_bad, SIGBUS, "dcache parity error" }, /* xscale */
419 { do_bad, SIGBUS, "unknown 25" },
420 { do_bad, SIGBUS, "unknown 26" },
421 { do_bad, SIGBUS, "unknown 27" },
422 { do_bad, SIGBUS, "unknown 28" },
423 { do_bad, SIGBUS, "unknown 29" },
424 { do_bad, SIGBUS, "unknown 30" },
425 { do_bad, SIGBUS, "unknown 31" }
426};
427
428void __init
429hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *),
430 int sig, const char *name)
431{
432 if (nr >= 0 && nr < ARRAY_SIZE(fsr_info)) {
433 fsr_info[nr].fn = fn;
434 fsr_info[nr].sig = sig;
435 fsr_info[nr].name = name;
436 }
437}
438
439/*
440 * Dispatch a data abort to the relevant handler.
441 */
442asmlinkage void
443do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
444{
445 const struct fsr_info *inf = fsr_info + (fsr & 15) + ((fsr & (1 << 10)) >> 6);
446
447 if (!inf->fn(addr, fsr, regs))
448 return;
449
450 printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n",
451 inf->name, fsr, addr);
452 force_sig(inf->sig, current);
453 show_pte(current->mm, addr);
454 die_if_kernel("Oops", regs, 0);
455}
456
457asmlinkage void
458do_PrefetchAbort(unsigned long addr, struct pt_regs *regs)
459{
460 do_translation_fault(addr, 0, regs);
461}
462
diff --git a/arch/arm/mm/fault.h b/arch/arm/mm/fault.h
new file mode 100644
index 000000000000..73b59e83227f
--- /dev/null
+++ b/arch/arm/mm/fault.h
@@ -0,0 +1,6 @@
1void do_bad_area(struct task_struct *tsk, struct mm_struct *mm,
2 unsigned long addr, unsigned int fsr, struct pt_regs *regs);
3
4void show_pte(struct mm_struct *mm, unsigned long addr);
5
6unsigned long search_exception_table(unsigned long addr);
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
new file mode 100644
index 000000000000..c6de48d89503
--- /dev/null
+++ b/arch/arm/mm/flush.c
@@ -0,0 +1,94 @@
1/*
2 * linux/arch/arm/mm/flush.c
3 *
4 * Copyright (C) 1995-2002 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/module.h>
11#include <linux/mm.h>
12#include <linux/pagemap.h>
13
14#include <asm/cacheflush.h>
15#include <asm/system.h>
16
17static void __flush_dcache_page(struct address_space *mapping, struct page *page)
18{
19 struct mm_struct *mm = current->active_mm;
20 struct vm_area_struct *mpnt;
21 struct prio_tree_iter iter;
22 pgoff_t pgoff;
23
24 /*
25 * Writeback any data associated with the kernel mapping of this
26 * page. This ensures that data in the physical page is mutually
27 * coherent with the kernels mapping.
28 */
29 __cpuc_flush_dcache_page(page_address(page));
30
31 /*
32 * If there's no mapping pointer here, then this page isn't
33 * visible to userspace yet, so there are no cache lines
34 * associated with any other aliases.
35 */
36 if (!mapping)
37 return;
38
39 /*
40 * There are possible user space mappings of this page:
41 * - VIVT cache: we need to also write back and invalidate all user
42 * data in the current VM view associated with this page.
43 * - aliasing VIPT: we only need to find one mapping of this page.
44 */
45 pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
46
47 flush_dcache_mmap_lock(mapping);
48 vma_prio_tree_foreach(mpnt, &iter, &mapping->i_mmap, pgoff, pgoff) {
49 unsigned long offset;
50
51 /*
52 * If this VMA is not in our MM, we can ignore it.
53 */
54 if (mpnt->vm_mm != mm)
55 continue;
56 if (!(mpnt->vm_flags & VM_MAYSHARE))
57 continue;
58 offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT;
59 flush_cache_page(mpnt, mpnt->vm_start + offset, page_to_pfn(page));
60 if (cache_is_vipt())
61 break;
62 }
63 flush_dcache_mmap_unlock(mapping);
64}
65
66/*
67 * Ensure cache coherency between kernel mapping and userspace mapping
68 * of this page.
69 *
70 * We have three cases to consider:
71 * - VIPT non-aliasing cache: fully coherent so nothing required.
72 * - VIVT: fully aliasing, so we need to handle every alias in our
73 * current VM view.
74 * - VIPT aliasing: need to handle one alias in our current VM view.
75 *
76 * If we need to handle aliasing:
77 * If the page only exists in the page cache and there are no user
78 * space mappings, we can be lazy and remember that we may have dirty
79 * kernel cache lines for later. Otherwise, we assume we have
80 * aliasing mappings.
81 */
82void flush_dcache_page(struct page *page)
83{
84 struct address_space *mapping = page_mapping(page);
85
86 if (cache_is_vipt_nonaliasing())
87 return;
88
89 if (mapping && !mapping_mapped(mapping))
90 set_bit(PG_dcache_dirty, &page->flags);
91 else
92 __flush_dcache_page(mapping, page);
93}
94EXPORT_SYMBOL(flush_dcache_page);
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
new file mode 100644
index 000000000000..41156c5370f7
--- /dev/null
+++ b/arch/arm/mm/init.c
@@ -0,0 +1,621 @@
1/*
2 * linux/arch/arm/mm/init.c
3 *
4 * Copyright (C) 1995-2002 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/config.h>
11#include <linux/kernel.h>
12#include <linux/errno.h>
13#include <linux/ptrace.h>
14#include <linux/swap.h>
15#include <linux/init.h>
16#include <linux/bootmem.h>
17#include <linux/mman.h>
18#include <linux/nodemask.h>
19#include <linux/initrd.h>
20
21#include <asm/mach-types.h>
22#include <asm/hardware.h>
23#include <asm/setup.h>
24#include <asm/tlb.h>
25
26#include <asm/mach/arch.h>
27#include <asm/mach/map.h>
28
29#define TABLE_SIZE (2 * PTRS_PER_PTE * sizeof(pte_t))
30
31DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
32
33extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
34extern void _stext, _text, _etext, __data_start, _end, __init_begin, __init_end;
35extern unsigned long phys_initrd_start;
36extern unsigned long phys_initrd_size;
37
38/*
39 * The sole use of this is to pass memory configuration
40 * data from paging_init to mem_init.
41 */
42static struct meminfo meminfo __initdata = { 0, };
43
44/*
45 * empty_zero_page is a special page that is used for
46 * zero-initialized data and COW.
47 */
48struct page *empty_zero_page;
49
50void show_mem(void)
51{
52 int free = 0, total = 0, reserved = 0;
53 int shared = 0, cached = 0, slab = 0, node;
54
55 printk("Mem-info:\n");
56 show_free_areas();
57 printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
58
59 for_each_online_node(node) {
60 struct page *page, *end;
61
62 page = NODE_MEM_MAP(node);
63 end = page + NODE_DATA(node)->node_spanned_pages;
64
65 do {
66 total++;
67 if (PageReserved(page))
68 reserved++;
69 else if (PageSwapCache(page))
70 cached++;
71 else if (PageSlab(page))
72 slab++;
73 else if (!page_count(page))
74 free++;
75 else
76 shared += page_count(page) - 1;
77 page++;
78 } while (page < end);
79 }
80
81 printk("%d pages of RAM\n", total);
82 printk("%d free pages\n", free);
83 printk("%d reserved pages\n", reserved);
84 printk("%d slab pages\n", slab);
85 printk("%d pages shared\n", shared);
86 printk("%d pages swap cached\n", cached);
87}
88
89struct node_info {
90 unsigned int start;
91 unsigned int end;
92 int bootmap_pages;
93};
94
95#define O_PFN_DOWN(x) ((x) >> PAGE_SHIFT)
96#define V_PFN_DOWN(x) O_PFN_DOWN(__pa(x))
97
98#define O_PFN_UP(x) (PAGE_ALIGN(x) >> PAGE_SHIFT)
99#define V_PFN_UP(x) O_PFN_UP(__pa(x))
100
101#define PFN_SIZE(x) ((x) >> PAGE_SHIFT)
102#define PFN_RANGE(s,e) PFN_SIZE(PAGE_ALIGN((unsigned long)(e)) - \
103 (((unsigned long)(s)) & PAGE_MASK))
104
105/*
106 * FIXME: We really want to avoid allocating the bootmap bitmap
107 * over the top of the initrd. Hopefully, this is located towards
108 * the start of a bank, so if we allocate the bootmap bitmap at
109 * the end, we won't clash.
110 */
111static unsigned int __init
112find_bootmap_pfn(int node, struct meminfo *mi, unsigned int bootmap_pages)
113{
114 unsigned int start_pfn, bank, bootmap_pfn;
115
116 start_pfn = V_PFN_UP(&_end);
117 bootmap_pfn = 0;
118
119 for (bank = 0; bank < mi->nr_banks; bank ++) {
120 unsigned int start, end;
121
122 if (mi->bank[bank].node != node)
123 continue;
124
125 start = O_PFN_UP(mi->bank[bank].start);
126 end = O_PFN_DOWN(mi->bank[bank].size +
127 mi->bank[bank].start);
128
129 if (end < start_pfn)
130 continue;
131
132 if (start < start_pfn)
133 start = start_pfn;
134
135 if (end <= start)
136 continue;
137
138 if (end - start >= bootmap_pages) {
139 bootmap_pfn = start;
140 break;
141 }
142 }
143
144 if (bootmap_pfn == 0)
145 BUG();
146
147 return bootmap_pfn;
148}
149
150/*
151 * Scan the memory info structure and pull out:
152 * - the end of memory
153 * - the number of nodes
154 * - the pfn range of each node
155 * - the number of bootmem bitmap pages
156 */
157static unsigned int __init
158find_memend_and_nodes(struct meminfo *mi, struct node_info *np)
159{
160 unsigned int i, bootmem_pages = 0, memend_pfn = 0;
161
162 for (i = 0; i < MAX_NUMNODES; i++) {
163 np[i].start = -1U;
164 np[i].end = 0;
165 np[i].bootmap_pages = 0;
166 }
167
168 for (i = 0; i < mi->nr_banks; i++) {
169 unsigned long start, end;
170 int node;
171
172 if (mi->bank[i].size == 0) {
173 /*
174 * Mark this bank with an invalid node number
175 */
176 mi->bank[i].node = -1;
177 continue;
178 }
179
180 node = mi->bank[i].node;
181
182 /*
183 * Make sure we haven't exceeded the maximum number of nodes
184 * that we have in this configuration. If we have, we're in
185 * trouble. (maybe we ought to limit, instead of bugging?)
186 */
187 if (node >= MAX_NUMNODES)
188 BUG();
189 node_set_online(node);
190
191 /*
192 * Get the start and end pfns for this bank
193 */
194 start = O_PFN_UP(mi->bank[i].start);
195 end = O_PFN_DOWN(mi->bank[i].start + mi->bank[i].size);
196
197 if (np[node].start > start)
198 np[node].start = start;
199
200 if (np[node].end < end)
201 np[node].end = end;
202
203 if (memend_pfn < end)
204 memend_pfn = end;
205 }
206
207 /*
208 * Calculate the number of pages we require to
209 * store the bootmem bitmaps.
210 */
211 for_each_online_node(i) {
212 if (np[i].end == 0)
213 continue;
214
215 np[i].bootmap_pages = bootmem_bootmap_pages(np[i].end -
216 np[i].start);
217 bootmem_pages += np[i].bootmap_pages;
218 }
219
220 high_memory = __va(memend_pfn << PAGE_SHIFT);
221
222 /*
223 * This doesn't seem to be used by the Linux memory
224 * manager any more. If we can get rid of it, we
225 * also get rid of some of the stuff above as well.
226 */
227 max_low_pfn = memend_pfn - O_PFN_DOWN(PHYS_OFFSET);
228 max_pfn = memend_pfn - O_PFN_DOWN(PHYS_OFFSET);
229
230 return bootmem_pages;
231}
232
233static int __init check_initrd(struct meminfo *mi)
234{
235 int initrd_node = -2;
236#ifdef CONFIG_BLK_DEV_INITRD
237 unsigned long end = phys_initrd_start + phys_initrd_size;
238
239 /*
240 * Make sure that the initrd is within a valid area of
241 * memory.
242 */
243 if (phys_initrd_size) {
244 unsigned int i;
245
246 initrd_node = -1;
247
248 for (i = 0; i < mi->nr_banks; i++) {
249 unsigned long bank_end;
250
251 bank_end = mi->bank[i].start + mi->bank[i].size;
252
253 if (mi->bank[i].start <= phys_initrd_start &&
254 end <= bank_end)
255 initrd_node = mi->bank[i].node;
256 }
257 }
258
259 if (initrd_node == -1) {
260 printk(KERN_ERR "initrd (0x%08lx - 0x%08lx) extends beyond "
261 "physical memory - disabling initrd\n",
262 phys_initrd_start, end);
263 phys_initrd_start = phys_initrd_size = 0;
264 }
265#endif
266
267 return initrd_node;
268}
269
270/*
271 * Reserve the various regions of node 0
272 */
273static __init void reserve_node_zero(unsigned int bootmap_pfn, unsigned int bootmap_pages)
274{
275 pg_data_t *pgdat = NODE_DATA(0);
276 unsigned long res_size = 0;
277
278 /*
279 * Register the kernel text and data with bootmem.
280 * Note that this can only be in node 0.
281 */
282#ifdef CONFIG_XIP_KERNEL
283 reserve_bootmem_node(pgdat, __pa(&__data_start), &_end - &__data_start);
284#else
285 reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext);
286#endif
287
288 /*
289 * Reserve the page tables. These are already in use,
290 * and can only be in node 0.
291 */
292 reserve_bootmem_node(pgdat, __pa(swapper_pg_dir),
293 PTRS_PER_PGD * sizeof(pgd_t));
294
295 /*
296 * And don't forget to reserve the allocator bitmap,
297 * which will be freed later.
298 */
299 reserve_bootmem_node(pgdat, bootmap_pfn << PAGE_SHIFT,
300 bootmap_pages << PAGE_SHIFT);
301
302 /*
303 * Hmm... This should go elsewhere, but we really really need to
304 * stop things allocating the low memory; ideally we need a better
305 * implementation of GFP_DMA which does not assume that DMA-able
306 * memory starts at zero.
307 */
308 if (machine_is_integrator() || machine_is_cintegrator())
309 res_size = __pa(swapper_pg_dir) - PHYS_OFFSET;
310
311 /*
312 * These should likewise go elsewhere. They pre-reserve the
313 * screen memory region at the start of main system memory.
314 */
315 if (machine_is_edb7211())
316 res_size = 0x00020000;
317 if (machine_is_p720t())
318 res_size = 0x00014000;
319
320#ifdef CONFIG_SA1111
321 /*
322 * Because of the SA1111 DMA bug, we want to preserve our
323 * precious DMA-able memory...
324 */
325 res_size = __pa(swapper_pg_dir) - PHYS_OFFSET;
326#endif
327 if (res_size)
328 reserve_bootmem_node(pgdat, PHYS_OFFSET, res_size);
329}
330
331/*
332 * Register all available RAM in this node with the bootmem allocator.
333 */
334static inline void free_bootmem_node_bank(int node, struct meminfo *mi)
335{
336 pg_data_t *pgdat = NODE_DATA(node);
337 int bank;
338
339 for (bank = 0; bank < mi->nr_banks; bank++)
340 if (mi->bank[bank].node == node)
341 free_bootmem_node(pgdat, mi->bank[bank].start,
342 mi->bank[bank].size);
343}
344
345/*
346 * Initialise the bootmem allocator for all nodes. This is called
347 * early during the architecture specific initialisation.
348 */
349static void __init bootmem_init(struct meminfo *mi)
350{
351 struct node_info node_info[MAX_NUMNODES], *np = node_info;
352 unsigned int bootmap_pages, bootmap_pfn, map_pg;
353 int node, initrd_node;
354
355 bootmap_pages = find_memend_and_nodes(mi, np);
356 bootmap_pfn = find_bootmap_pfn(0, mi, bootmap_pages);
357 initrd_node = check_initrd(mi);
358
359 map_pg = bootmap_pfn;
360
361 /*
362 * Initialise the bootmem nodes.
363 *
364 * What we really want to do is:
365 *
366 * unmap_all_regions_except_kernel();
367 * for_each_node_in_reverse_order(node) {
368 * map_node(node);
369 * allocate_bootmem_map(node);
370 * init_bootmem_node(node);
371 * free_bootmem_node(node);
372 * }
373 *
374 * but this is a 2.5-type change. For now, we just set
375 * the nodes up in reverse order.
376 *
377 * (we could also do with rolling bootmem_init and paging_init
378 * into one generic "memory_init" type function).
379 */
380 np += num_online_nodes() - 1;
381 for (node = num_online_nodes() - 1; node >= 0; node--, np--) {
382 /*
383 * If there are no pages in this node, ignore it.
384 * Note that node 0 must always have some pages.
385 */
386 if (np->end == 0 || !node_online(node)) {
387 if (node == 0)
388 BUG();
389 continue;
390 }
391
392 /*
393 * Initialise the bootmem allocator.
394 */
395 init_bootmem_node(NODE_DATA(node), map_pg, np->start, np->end);
396 free_bootmem_node_bank(node, mi);
397 map_pg += np->bootmap_pages;
398
399 /*
400 * If this is node 0, we need to reserve some areas ASAP -
401 * we may use bootmem on node 0 to setup the other nodes.
402 */
403 if (node == 0)
404 reserve_node_zero(bootmap_pfn, bootmap_pages);
405 }
406
407
408#ifdef CONFIG_BLK_DEV_INITRD
409 if (phys_initrd_size && initrd_node >= 0) {
410 reserve_bootmem_node(NODE_DATA(initrd_node), phys_initrd_start,
411 phys_initrd_size);
412 initrd_start = __phys_to_virt(phys_initrd_start);
413 initrd_end = initrd_start + phys_initrd_size;
414 }
415#endif
416
417 BUG_ON(map_pg != bootmap_pfn + bootmap_pages);
418}
419
420/*
421 * paging_init() sets up the page tables, initialises the zone memory
422 * maps, and sets up the zero page, bad page and bad page tables.
423 */
424void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc)
425{
426 void *zero_page;
427 int node;
428
429 bootmem_init(mi);
430
431 memcpy(&meminfo, mi, sizeof(meminfo));
432
433 /*
434 * allocate the zero page. Note that we count on this going ok.
435 */
436 zero_page = alloc_bootmem_low_pages(PAGE_SIZE);
437
438 /*
439 * initialise the page tables.
440 */
441 memtable_init(mi);
442 if (mdesc->map_io)
443 mdesc->map_io();
444 flush_tlb_all();
445
446 /*
447 * initialise the zones within each node
448 */
449 for_each_online_node(node) {
450 unsigned long zone_size[MAX_NR_ZONES];
451 unsigned long zhole_size[MAX_NR_ZONES];
452 struct bootmem_data *bdata;
453 pg_data_t *pgdat;
454 int i;
455
456 /*
457 * Initialise the zone size information.
458 */
459 for (i = 0; i < MAX_NR_ZONES; i++) {
460 zone_size[i] = 0;
461 zhole_size[i] = 0;
462 }
463
464 pgdat = NODE_DATA(node);
465 bdata = pgdat->bdata;
466
467 /*
468 * The size of this node has already been determined.
469 * If we need to do anything fancy with the allocation
470 * of this memory to the zones, now is the time to do
471 * it.
472 */
473 zone_size[0] = bdata->node_low_pfn -
474 (bdata->node_boot_start >> PAGE_SHIFT);
475
476 /*
477 * If this zone has zero size, skip it.
478 */
479 if (!zone_size[0])
480 continue;
481
482 /*
483 * For each bank in this node, calculate the size of the
484 * holes. holes = node_size - sum(bank_sizes_in_node)
485 */
486 zhole_size[0] = zone_size[0];
487 for (i = 0; i < mi->nr_banks; i++) {
488 if (mi->bank[i].node != node)
489 continue;
490
491 zhole_size[0] -= mi->bank[i].size >> PAGE_SHIFT;
492 }
493
494 /*
495 * Adjust the sizes according to any special
496 * requirements for this machine type.
497 */
498 arch_adjust_zones(node, zone_size, zhole_size);
499
500 free_area_init_node(node, pgdat, zone_size,
501 bdata->node_boot_start >> PAGE_SHIFT, zhole_size);
502 }
503
504 /*
505 * finish off the bad pages once
506 * the mem_map is initialised
507 */
508 memzero(zero_page, PAGE_SIZE);
509 empty_zero_page = virt_to_page(zero_page);
510 flush_dcache_page(empty_zero_page);
511}
512
513static inline void free_area(unsigned long addr, unsigned long end, char *s)
514{
515 unsigned int size = (end - addr) >> 10;
516
517 for (; addr < end; addr += PAGE_SIZE) {
518 struct page *page = virt_to_page(addr);
519 ClearPageReserved(page);
520 set_page_count(page, 1);
521 free_page(addr);
522 totalram_pages++;
523 }
524
525 if (size && s)
526 printk(KERN_INFO "Freeing %s memory: %dK\n", s, size);
527}
528
529/*
530 * mem_init() marks the free areas in the mem_map and tells us how much
531 * memory is free. This is done after various parts of the system have
532 * claimed their memory after the kernel image.
533 */
534void __init mem_init(void)
535{
536 unsigned int codepages, datapages, initpages;
537 int i, node;
538
539 codepages = &_etext - &_text;
540 datapages = &_end - &__data_start;
541 initpages = &__init_end - &__init_begin;
542
543#ifndef CONFIG_DISCONTIGMEM
544 max_mapnr = virt_to_page(high_memory) - mem_map;
545#endif
546
547 /*
548 * We may have non-contiguous memory.
549 */
550 if (meminfo.nr_banks != 1)
551 create_memmap_holes(&meminfo);
552
553 /* this will put all unused low memory onto the freelists */
554 for_each_online_node(node) {
555 pg_data_t *pgdat = NODE_DATA(node);
556
557 if (pgdat->node_spanned_pages != 0)
558 totalram_pages += free_all_bootmem_node(pgdat);
559 }
560
561#ifdef CONFIG_SA1111
562 /* now that our DMA memory is actually so designated, we can free it */
563 free_area(PAGE_OFFSET, (unsigned long)swapper_pg_dir, NULL);
564#endif
565
566 /*
567 * Since our memory may not be contiguous, calculate the
568 * real number of pages we have in this system
569 */
570 printk(KERN_INFO "Memory:");
571
572 num_physpages = 0;
573 for (i = 0; i < meminfo.nr_banks; i++) {
574 num_physpages += meminfo.bank[i].size >> PAGE_SHIFT;
575 printk(" %ldMB", meminfo.bank[i].size >> 20);
576 }
577
578 printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));
579 printk(KERN_NOTICE "Memory: %luKB available (%dK code, "
580 "%dK data, %dK init)\n",
581 (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
582 codepages >> 10, datapages >> 10, initpages >> 10);
583
584 if (PAGE_SIZE >= 16384 && num_physpages <= 128) {
585 extern int sysctl_overcommit_memory;
586 /*
587 * On a machine this small we won't get
588 * anywhere without overcommit, so turn
589 * it on by default.
590 */
591 sysctl_overcommit_memory = OVERCOMMIT_ALWAYS;
592 }
593}
594
595void free_initmem(void)
596{
597 if (!machine_is_integrator() && !machine_is_cintegrator()) {
598 free_area((unsigned long)(&__init_begin),
599 (unsigned long)(&__init_end),
600 "init");
601 }
602}
603
604#ifdef CONFIG_BLK_DEV_INITRD
605
606static int keep_initrd;
607
608void free_initrd_mem(unsigned long start, unsigned long end)
609{
610 if (!keep_initrd)
611 free_area(start, end, "initrd");
612}
613
614static int __init keepinitrd_setup(char *__unused)
615{
616 keep_initrd = 1;
617 return 1;
618}
619
620__setup("keepinitrd", keepinitrd_setup);
621#endif
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
new file mode 100644
index 000000000000..00bb8fd37a59
--- /dev/null
+++ b/arch/arm/mm/ioremap.c
@@ -0,0 +1,172 @@
1/*
2 * linux/arch/arm/mm/ioremap.c
3 *
4 * Re-map IO memory to kernel address space so that we can access it.
5 *
6 * (C) Copyright 1995 1996 Linus Torvalds
7 *
8 * Hacked for ARM by Phil Blundell <philb@gnu.org>
9 * Hacked to allow all architectures to build, and various cleanups
10 * by Russell King
11 *
12 * This allows a driver to remap an arbitrary region of bus memory into
13 * virtual space. One should *only* use readl, writel, memcpy_toio and
14 * so on with such remapped areas.
15 *
16 * Because the ARM only has a 32-bit address space we can't address the
17 * whole of the (physical) PCI space at once. PCI huge-mode addressing
18 * allows us to circumvent this restriction by splitting PCI space into
19 * two 2GB chunks and mapping only one at a time into processor memory.
20 * We use MMU protection domains to trap any attempt to access the bank
21 * that is not currently mapped. (This isn't fully implemented yet.)
22 */
23#include <linux/module.h>
24#include <linux/errno.h>
25#include <linux/mm.h>
26#include <linux/vmalloc.h>
27
28#include <asm/cacheflush.h>
29#include <asm/io.h>
30#include <asm/tlbflush.h>
31
32static inline void
33remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
34 unsigned long phys_addr, pgprot_t pgprot)
35{
36 unsigned long end;
37
38 address &= ~PMD_MASK;
39 end = address + size;
40 if (end > PMD_SIZE)
41 end = PMD_SIZE;
42 BUG_ON(address >= end);
43 do {
44 if (!pte_none(*pte))
45 goto bad;
46
47 set_pte(pte, pfn_pte(phys_addr >> PAGE_SHIFT, pgprot));
48 address += PAGE_SIZE;
49 phys_addr += PAGE_SIZE;
50 pte++;
51 } while (address && (address < end));
52 return;
53
54 bad:
55 printk("remap_area_pte: page already exists\n");
56 BUG();
57}
58
59static inline int
60remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
61 unsigned long phys_addr, unsigned long flags)
62{
63 unsigned long end;
64 pgprot_t pgprot;
65
66 address &= ~PGDIR_MASK;
67 end = address + size;
68
69 if (end > PGDIR_SIZE)
70 end = PGDIR_SIZE;
71
72 phys_addr -= address;
73 BUG_ON(address >= end);
74
75 pgprot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_WRITE | flags);
76 do {
77 pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address);
78 if (!pte)
79 return -ENOMEM;
80 remap_area_pte(pte, address, end - address, address + phys_addr, pgprot);
81 address = (address + PMD_SIZE) & PMD_MASK;
82 pmd++;
83 } while (address && (address < end));
84 return 0;
85}
86
87static int
88remap_area_pages(unsigned long start, unsigned long phys_addr,
89 unsigned long size, unsigned long flags)
90{
91 unsigned long address = start;
92 unsigned long end = start + size;
93 int err = 0;
94 pgd_t * dir;
95
96 phys_addr -= address;
97 dir = pgd_offset(&init_mm, address);
98 BUG_ON(address >= end);
99 spin_lock(&init_mm.page_table_lock);
100 do {
101 pmd_t *pmd = pmd_alloc(&init_mm, dir, address);
102 if (!pmd) {
103 err = -ENOMEM;
104 break;
105 }
106 if (remap_area_pmd(pmd, address, end - address,
107 phys_addr + address, flags)) {
108 err = -ENOMEM;
109 break;
110 }
111
112 address = (address + PGDIR_SIZE) & PGDIR_MASK;
113 dir++;
114 } while (address && (address < end));
115
116 spin_unlock(&init_mm.page_table_lock);
117 flush_cache_vmap(start, end);
118 return err;
119}
120
121/*
122 * Remap an arbitrary physical address space into the kernel virtual
123 * address space. Needed when the kernel wants to access high addresses
124 * directly.
125 *
126 * NOTE! We need to allow non-page-aligned mappings too: we will obviously
127 * have to convert them into an offset in a page-aligned mapping, but the
128 * caller shouldn't need to know that small detail.
129 *
130 * 'flags' are the extra L_PTE_ flags that you want to specify for this
131 * mapping. See include/asm-arm/proc-armv/pgtable.h for more information.
132 */
133void __iomem *
134__ioremap(unsigned long phys_addr, size_t size, unsigned long flags,
135 unsigned long align)
136{
137 void * addr;
138 struct vm_struct * area;
139 unsigned long offset, last_addr;
140
141 /* Don't allow wraparound or zero size */
142 last_addr = phys_addr + size - 1;
143 if (!size || last_addr < phys_addr)
144 return NULL;
145
146 /*
147 * Mappings have to be page-aligned
148 */
149 offset = phys_addr & ~PAGE_MASK;
150 phys_addr &= PAGE_MASK;
151 size = PAGE_ALIGN(last_addr + 1) - phys_addr;
152
153 /*
154 * Ok, go for it..
155 */
156 area = get_vm_area(size, VM_IOREMAP);
157 if (!area)
158 return NULL;
159 addr = area->addr;
160 if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
161 vfree(addr);
162 return NULL;
163 }
164 return (void __iomem *) (offset + (char *)addr);
165}
166EXPORT_SYMBOL(__ioremap);
167
168void __iounmap(void __iomem *addr)
169{
170 vfree((void *) (PAGE_MASK & (unsigned long) addr));
171}
172EXPORT_SYMBOL(__iounmap);
diff --git a/arch/arm/mm/minicache.c b/arch/arm/mm/minicache.c
new file mode 100644
index 000000000000..dedf2ab01b2a
--- /dev/null
+++ b/arch/arm/mm/minicache.c
@@ -0,0 +1,73 @@
1/*
2 * linux/arch/arm/mm/minicache.c
3 *
4 * Copyright (C) 2001 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This handles the mini data cache, as found on SA11x0 and XScale
11 * processors. When we copy a user page page, we map it in such a way
12 * that accesses to this page will not touch the main data cache, but
13 * will be cached in the mini data cache. This prevents us thrashing
14 * the main data cache on page faults.
15 */
16#include <linux/init.h>
17#include <linux/mm.h>
18
19#include <asm/page.h>
20#include <asm/pgtable.h>
21#include <asm/tlbflush.h>
22
23/*
24 * 0xffff8000 to 0xffffffff is reserved for any ARM architecture
25 * specific hacks for copying pages efficiently.
26 */
27#define minicache_address (0xffff8000)
28#define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \
29 L_PTE_CACHEABLE)
30
31static pte_t *minicache_pte;
32
33/*
34 * Note that this is intended to be called only from the copy_user_page
35 * asm code; anything else will require special locking to prevent the
36 * mini-cache space being re-used. (Note: probably preempt unsafe).
37 *
38 * We rely on the fact that the minicache is 2K, and we'll be pushing
39 * 4K of data through it, so we don't actually have to specifically
40 * flush the minicache when we change the mapping.
41 *
42 * Note also: assert(PAGE_OFFSET <= virt < high_memory).
43 * Unsafe: preempt, kmap.
44 */
45unsigned long map_page_minicache(unsigned long virt)
46{
47 set_pte(minicache_pte, pfn_pte(__pa(virt) >> PAGE_SHIFT, minicache_pgprot));
48 flush_tlb_kernel_page(minicache_address);
49
50 return minicache_address;
51}
52
53static int __init minicache_init(void)
54{
55 pgd_t *pgd;
56 pmd_t *pmd;
57
58 spin_lock(&init_mm.page_table_lock);
59
60 pgd = pgd_offset_k(minicache_address);
61 pmd = pmd_alloc(&init_mm, pgd, minicache_address);
62 if (!pmd)
63 BUG();
64 minicache_pte = pte_alloc_kernel(&init_mm, pmd, minicache_address);
65 if (!minicache_pte)
66 BUG();
67
68 spin_unlock(&init_mm.page_table_lock);
69
70 return 0;
71}
72
73core_initcall(minicache_init);
diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c
new file mode 100644
index 000000000000..f5a87db8b498
--- /dev/null
+++ b/arch/arm/mm/mm-armv.c
@@ -0,0 +1,760 @@
1/*
2 * linux/arch/arm/mm/mm-armv.c
3 *
4 * Copyright (C) 1998-2002 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * Page table sludge for ARM v3 and v4 processor architectures.
11 */
12#include <linux/config.h>
13#include <linux/module.h>
14#include <linux/mm.h>
15#include <linux/init.h>
16#include <linux/bootmem.h>
17#include <linux/highmem.h>
18#include <linux/nodemask.h>
19
20#include <asm/pgalloc.h>
21#include <asm/page.h>
22#include <asm/io.h>
23#include <asm/setup.h>
24#include <asm/tlbflush.h>
25
26#include <asm/mach/map.h>
27
28#define CPOLICY_UNCACHED 0
29#define CPOLICY_BUFFERED 1
30#define CPOLICY_WRITETHROUGH 2
31#define CPOLICY_WRITEBACK 3
32#define CPOLICY_WRITEALLOC 4
33
34static unsigned int cachepolicy __initdata = CPOLICY_WRITEBACK;
35static unsigned int ecc_mask __initdata = 0;
36pgprot_t pgprot_kernel;
37
38EXPORT_SYMBOL(pgprot_kernel);
39
40struct cachepolicy {
41 const char policy[16];
42 unsigned int cr_mask;
43 unsigned int pmd;
44 unsigned int pte;
45};
46
47static struct cachepolicy cache_policies[] __initdata = {
48 {
49 .policy = "uncached",
50 .cr_mask = CR_W|CR_C,
51 .pmd = PMD_SECT_UNCACHED,
52 .pte = 0,
53 }, {
54 .policy = "buffered",
55 .cr_mask = CR_C,
56 .pmd = PMD_SECT_BUFFERED,
57 .pte = PTE_BUFFERABLE,
58 }, {
59 .policy = "writethrough",
60 .cr_mask = 0,
61 .pmd = PMD_SECT_WT,
62 .pte = PTE_CACHEABLE,
63 }, {
64 .policy = "writeback",
65 .cr_mask = 0,
66 .pmd = PMD_SECT_WB,
67 .pte = PTE_BUFFERABLE|PTE_CACHEABLE,
68 }, {
69 .policy = "writealloc",
70 .cr_mask = 0,
71 .pmd = PMD_SECT_WBWA,
72 .pte = PTE_BUFFERABLE|PTE_CACHEABLE,
73 }
74};
75
76/*
77 * These are useful for identifing cache coherency
78 * problems by allowing the cache or the cache and
79 * writebuffer to be turned off. (Note: the write
80 * buffer should not be on and the cache off).
81 */
82static void __init early_cachepolicy(char **p)
83{
84 int i;
85
86 for (i = 0; i < ARRAY_SIZE(cache_policies); i++) {
87 int len = strlen(cache_policies[i].policy);
88
89 if (memcmp(*p, cache_policies[i].policy, len) == 0) {
90 cachepolicy = i;
91 cr_alignment &= ~cache_policies[i].cr_mask;
92 cr_no_alignment &= ~cache_policies[i].cr_mask;
93 *p += len;
94 break;
95 }
96 }
97 if (i == ARRAY_SIZE(cache_policies))
98 printk(KERN_ERR "ERROR: unknown or unsupported cache policy\n");
99 flush_cache_all();
100 set_cr(cr_alignment);
101}
102
103static void __init early_nocache(char **__unused)
104{
105 char *p = "buffered";
106 printk(KERN_WARNING "nocache is deprecated; use cachepolicy=%s\n", p);
107 early_cachepolicy(&p);
108}
109
110static void __init early_nowrite(char **__unused)
111{
112 char *p = "uncached";
113 printk(KERN_WARNING "nowb is deprecated; use cachepolicy=%s\n", p);
114 early_cachepolicy(&p);
115}
116
117static void __init early_ecc(char **p)
118{
119 if (memcmp(*p, "on", 2) == 0) {
120 ecc_mask = PMD_PROTECTION;
121 *p += 2;
122 } else if (memcmp(*p, "off", 3) == 0) {
123 ecc_mask = 0;
124 *p += 3;
125 }
126}
127
128__early_param("nocache", early_nocache);
129__early_param("nowb", early_nowrite);
130__early_param("cachepolicy=", early_cachepolicy);
131__early_param("ecc=", early_ecc);
132
133static int __init noalign_setup(char *__unused)
134{
135 cr_alignment &= ~CR_A;
136 cr_no_alignment &= ~CR_A;
137 set_cr(cr_alignment);
138 return 1;
139}
140
141__setup("noalign", noalign_setup);
142
143#define FIRST_KERNEL_PGD_NR (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD)
144
145/*
146 * need to get a 16k page for level 1
147 */
148pgd_t *get_pgd_slow(struct mm_struct *mm)
149{
150 pgd_t *new_pgd, *init_pgd;
151 pmd_t *new_pmd, *init_pmd;
152 pte_t *new_pte, *init_pte;
153
154 new_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL, 2);
155 if (!new_pgd)
156 goto no_pgd;
157
158 memzero(new_pgd, FIRST_KERNEL_PGD_NR * sizeof(pgd_t));
159
160 init_pgd = pgd_offset_k(0);
161
162 if (!vectors_high()) {
163 /*
164 * This lock is here just to satisfy pmd_alloc and pte_lock
165 */
166 spin_lock(&mm->page_table_lock);
167
168 /*
169 * On ARM, first page must always be allocated since it
170 * contains the machine vectors.
171 */
172 new_pmd = pmd_alloc(mm, new_pgd, 0);
173 if (!new_pmd)
174 goto no_pmd;
175
176 new_pte = pte_alloc_map(mm, new_pmd, 0);
177 if (!new_pte)
178 goto no_pte;
179
180 init_pmd = pmd_offset(init_pgd, 0);
181 init_pte = pte_offset_map_nested(init_pmd, 0);
182 set_pte(new_pte, *init_pte);
183 pte_unmap_nested(init_pte);
184 pte_unmap(new_pte);
185
186 spin_unlock(&mm->page_table_lock);
187 }
188
189 /*
190 * Copy over the kernel and IO PGD entries
191 */
192 memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
193 (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
194
195 clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));
196
197 return new_pgd;
198
199no_pte:
200 spin_unlock(&mm->page_table_lock);
201 pmd_free(new_pmd);
202 free_pages((unsigned long)new_pgd, 2);
203 return NULL;
204
205no_pmd:
206 spin_unlock(&mm->page_table_lock);
207 free_pages((unsigned long)new_pgd, 2);
208 return NULL;
209
210no_pgd:
211 return NULL;
212}
213
214void free_pgd_slow(pgd_t *pgd)
215{
216 pmd_t *pmd;
217 struct page *pte;
218
219 if (!pgd)
220 return;
221
222 /* pgd is always present and good */
223 pmd = (pmd_t *)pgd;
224 if (pmd_none(*pmd))
225 goto free;
226 if (pmd_bad(*pmd)) {
227 pmd_ERROR(*pmd);
228 pmd_clear(pmd);
229 goto free;
230 }
231
232 pte = pmd_page(*pmd);
233 pmd_clear(pmd);
234 dec_page_state(nr_page_table_pages);
235 pte_free(pte);
236 pmd_free(pmd);
237free:
238 free_pages((unsigned long) pgd, 2);
239}
240
241/*
242 * Create a SECTION PGD between VIRT and PHYS in domain
243 * DOMAIN with protection PROT. This operates on half-
244 * pgdir entry increments.
245 */
246static inline void
247alloc_init_section(unsigned long virt, unsigned long phys, int prot)
248{
249 pmd_t *pmdp;
250
251 pmdp = pmd_offset(pgd_offset_k(virt), virt);
252 if (virt & (1 << 20))
253 pmdp++;
254
255 *pmdp = __pmd(phys | prot);
256 flush_pmd_entry(pmdp);
257}
258
259/*
260 * Create a SUPER SECTION PGD between VIRT and PHYS with protection PROT
261 */
262static inline void
263alloc_init_supersection(unsigned long virt, unsigned long phys, int prot)
264{
265 int i;
266
267 for (i = 0; i < 16; i += 1) {
268 alloc_init_section(virt, phys & SUPERSECTION_MASK,
269 prot | PMD_SECT_SUPER);
270
271 virt += (PGDIR_SIZE / 2);
272 phys += (PGDIR_SIZE / 2);
273 }
274}
275
276/*
277 * Add a PAGE mapping between VIRT and PHYS in domain
278 * DOMAIN with protection PROT. Note that due to the
279 * way we map the PTEs, we must allocate two PTE_SIZE'd
280 * blocks - one for the Linux pte table, and one for
281 * the hardware pte table.
282 */
283static inline void
284alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pgprot_t prot)
285{
286 pmd_t *pmdp;
287 pte_t *ptep;
288
289 pmdp = pmd_offset(pgd_offset_k(virt), virt);
290
291 if (pmd_none(*pmdp)) {
292 unsigned long pmdval;
293 ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE *
294 sizeof(pte_t));
295
296 pmdval = __pa(ptep) | prot_l1;
297 pmdp[0] = __pmd(pmdval);
298 pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));
299 flush_pmd_entry(pmdp);
300 }
301 ptep = pte_offset_kernel(pmdp, virt);
302
303 set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, prot));
304}
305
306/*
307 * Clear any PGD mapping. On a two-level page table system,
308 * the clearance is done by the middle-level functions (pmd)
309 * rather than the top-level (pgd) functions.
310 */
311static inline void clear_mapping(unsigned long virt)
312{
313 pmd_clear(pmd_offset(pgd_offset_k(virt), virt));
314}
315
316struct mem_types {
317 unsigned int prot_pte;
318 unsigned int prot_l1;
319 unsigned int prot_sect;
320 unsigned int domain;
321};
322
323static struct mem_types mem_types[] __initdata = {
324 [MT_DEVICE] = {
325 .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
326 L_PTE_WRITE,
327 .prot_l1 = PMD_TYPE_TABLE,
328 .prot_sect = PMD_TYPE_SECT | PMD_SECT_UNCACHED |
329 PMD_SECT_AP_WRITE,
330 .domain = DOMAIN_IO,
331 },
332 [MT_CACHECLEAN] = {
333 .prot_sect = PMD_TYPE_SECT,
334 .domain = DOMAIN_KERNEL,
335 },
336 [MT_MINICLEAN] = {
337 .prot_sect = PMD_TYPE_SECT | PMD_SECT_MINICACHE,
338 .domain = DOMAIN_KERNEL,
339 },
340 [MT_LOW_VECTORS] = {
341 .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
342 L_PTE_EXEC,
343 .prot_l1 = PMD_TYPE_TABLE,
344 .domain = DOMAIN_USER,
345 },
346 [MT_HIGH_VECTORS] = {
347 .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
348 L_PTE_USER | L_PTE_EXEC,
349 .prot_l1 = PMD_TYPE_TABLE,
350 .domain = DOMAIN_USER,
351 },
352 [MT_MEMORY] = {
353 .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
354 .domain = DOMAIN_KERNEL,
355 },
356 [MT_ROM] = {
357 .prot_sect = PMD_TYPE_SECT,
358 .domain = DOMAIN_KERNEL,
359 },
360 [MT_IXP2000_DEVICE] = { /* IXP2400 requires XCB=101 for on-chip I/O */
361 .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
362 L_PTE_WRITE,
363 .prot_l1 = PMD_TYPE_TABLE,
364 .prot_sect = PMD_TYPE_SECT | PMD_SECT_UNCACHED |
365 PMD_SECT_AP_WRITE | PMD_SECT_BUFFERABLE |
366 PMD_SECT_TEX(1),
367 .domain = DOMAIN_IO,
368 }
369};
370
371/*
372 * Adjust the PMD section entries according to the CPU in use.
373 */
374static void __init build_mem_type_table(void)
375{
376 struct cachepolicy *cp;
377 unsigned int cr = get_cr();
378 int cpu_arch = cpu_architecture();
379 int i;
380
381#if defined(CONFIG_CPU_DCACHE_DISABLE)
382 if (cachepolicy > CPOLICY_BUFFERED)
383 cachepolicy = CPOLICY_BUFFERED;
384#elif defined(CONFIG_CPU_DCACHE_WRITETHROUGH)
385 if (cachepolicy > CPOLICY_WRITETHROUGH)
386 cachepolicy = CPOLICY_WRITETHROUGH;
387#endif
388 if (cpu_arch < CPU_ARCH_ARMv5) {
389 if (cachepolicy >= CPOLICY_WRITEALLOC)
390 cachepolicy = CPOLICY_WRITEBACK;
391 ecc_mask = 0;
392 }
393
394 if (cpu_arch <= CPU_ARCH_ARMv5) {
395 for (i = 0; i < ARRAY_SIZE(mem_types); i++) {
396 if (mem_types[i].prot_l1)
397 mem_types[i].prot_l1 |= PMD_BIT4;
398 if (mem_types[i].prot_sect)
399 mem_types[i].prot_sect |= PMD_BIT4;
400 }
401 }
402
403 /*
404 * ARMv6 and above have extended page tables.
405 */
406 if (cpu_arch >= CPU_ARCH_ARMv6 && (cr & CR_XP)) {
407 /*
408 * bit 4 becomes XN which we must clear for the
409 * kernel memory mapping.
410 */
411 mem_types[MT_MEMORY].prot_sect &= ~PMD_BIT4;
412 mem_types[MT_ROM].prot_sect &= ~PMD_BIT4;
413 /*
414 * Mark cache clean areas read only from SVC mode
415 * and no access from userspace.
416 */
417 mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
418 mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
419 }
420
421 cp = &cache_policies[cachepolicy];
422
423 if (cpu_arch >= CPU_ARCH_ARMv5) {
424 mem_types[MT_LOW_VECTORS].prot_pte |= cp->pte & PTE_CACHEABLE;
425 mem_types[MT_HIGH_VECTORS].prot_pte |= cp->pte & PTE_CACHEABLE;
426 } else {
427 mem_types[MT_LOW_VECTORS].prot_pte |= cp->pte;
428 mem_types[MT_HIGH_VECTORS].prot_pte |= cp->pte;
429 mem_types[MT_MINICLEAN].prot_sect &= ~PMD_SECT_TEX(1);
430 }
431
432 mem_types[MT_LOW_VECTORS].prot_l1 |= ecc_mask;
433 mem_types[MT_HIGH_VECTORS].prot_l1 |= ecc_mask;
434 mem_types[MT_MEMORY].prot_sect |= ecc_mask | cp->pmd;
435 mem_types[MT_ROM].prot_sect |= cp->pmd;
436
437 for (i = 0; i < 16; i++) {
438 unsigned long v = pgprot_val(protection_map[i]);
439 v &= (~(PTE_BUFFERABLE|PTE_CACHEABLE)) | cp->pte;
440 protection_map[i] = __pgprot(v);
441 }
442
443 pgprot_kernel = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG |
444 L_PTE_DIRTY | L_PTE_WRITE |
445 L_PTE_EXEC | cp->pte);
446
447 switch (cp->pmd) {
448 case PMD_SECT_WT:
449 mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_WT;
450 break;
451 case PMD_SECT_WB:
452 case PMD_SECT_WBWA:
453 mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_WB;
454 break;
455 }
456 printk("Memory policy: ECC %sabled, Data cache %s\n",
457 ecc_mask ? "en" : "dis", cp->policy);
458}
459
460#define vectors_base() (vectors_high() ? 0xffff0000 : 0)
461
462/*
463 * Create the page directory entries and any necessary
464 * page tables for the mapping specified by `md'. We
465 * are able to cope here with varying sizes and address
466 * offsets, and we take full advantage of sections and
467 * supersections.
468 */
469static void __init create_mapping(struct map_desc *md)
470{
471 unsigned long virt, length;
472 int prot_sect, prot_l1, domain;
473 pgprot_t prot_pte;
474 long off;
475
476 if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {
477 printk(KERN_WARNING "BUG: not creating mapping for "
478 "0x%08lx at 0x%08lx in user region\n",
479 md->physical, md->virtual);
480 return;
481 }
482
483 if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
484 md->virtual >= PAGE_OFFSET && md->virtual < VMALLOC_END) {
485 printk(KERN_WARNING "BUG: mapping for 0x%08lx at 0x%08lx "
486 "overlaps vmalloc space\n",
487 md->physical, md->virtual);
488 }
489
490 domain = mem_types[md->type].domain;
491 prot_pte = __pgprot(mem_types[md->type].prot_pte);
492 prot_l1 = mem_types[md->type].prot_l1 | PMD_DOMAIN(domain);
493 prot_sect = mem_types[md->type].prot_sect | PMD_DOMAIN(domain);
494
495 virt = md->virtual;
496 off = md->physical - virt;
497 length = md->length;
498
499 if (mem_types[md->type].prot_l1 == 0 &&
500 (virt & 0xfffff || (virt + off) & 0xfffff || (virt + length) & 0xfffff)) {
501 printk(KERN_WARNING "BUG: map for 0x%08lx at 0x%08lx can not "
502 "be mapped using pages, ignoring.\n",
503 md->physical, md->virtual);
504 return;
505 }
506
507 while ((virt & 0xfffff || (virt + off) & 0xfffff) && length >= PAGE_SIZE) {
508 alloc_init_page(virt, virt + off, prot_l1, prot_pte);
509
510 virt += PAGE_SIZE;
511 length -= PAGE_SIZE;
512 }
513
514 /* N.B. ARMv6 supersections are only defined to work with domain 0.
515 * Since domain assignments can in fact be arbitrary, the
516 * 'domain == 0' check below is required to insure that ARMv6
517 * supersections are only allocated for domain 0 regardless
518 * of the actual domain assignments in use.
519 */
520 if (cpu_architecture() >= CPU_ARCH_ARMv6 && domain == 0) {
521 /* Align to supersection boundary */
522 while ((virt & ~SUPERSECTION_MASK || (virt + off) &
523 ~SUPERSECTION_MASK) && length >= (PGDIR_SIZE / 2)) {
524 alloc_init_section(virt, virt + off, prot_sect);
525
526 virt += (PGDIR_SIZE / 2);
527 length -= (PGDIR_SIZE / 2);
528 }
529
530 while (length >= SUPERSECTION_SIZE) {
531 alloc_init_supersection(virt, virt + off, prot_sect);
532
533 virt += SUPERSECTION_SIZE;
534 length -= SUPERSECTION_SIZE;
535 }
536 }
537
538 /*
539 * A section mapping covers half a "pgdir" entry.
540 */
541 while (length >= (PGDIR_SIZE / 2)) {
542 alloc_init_section(virt, virt + off, prot_sect);
543
544 virt += (PGDIR_SIZE / 2);
545 length -= (PGDIR_SIZE / 2);
546 }
547
548 while (length >= PAGE_SIZE) {
549 alloc_init_page(virt, virt + off, prot_l1, prot_pte);
550
551 virt += PAGE_SIZE;
552 length -= PAGE_SIZE;
553 }
554}
555
556/*
557 * In order to soft-boot, we need to insert a 1:1 mapping in place of
558 * the user-mode pages. This will then ensure that we have predictable
559 * results when turning the mmu off
560 */
561void setup_mm_for_reboot(char mode)
562{
563 unsigned long pmdval;
564 pgd_t *pgd;
565 pmd_t *pmd;
566 int i;
567 int cpu_arch = cpu_architecture();
568
569 if (current->mm && current->mm->pgd)
570 pgd = current->mm->pgd;
571 else
572 pgd = init_mm.pgd;
573
574 for (i = 0; i < FIRST_USER_PGD_NR + USER_PTRS_PER_PGD; i++) {
575 pmdval = (i << PGDIR_SHIFT) |
576 PMD_SECT_AP_WRITE | PMD_SECT_AP_READ |
577 PMD_TYPE_SECT;
578 if (cpu_arch <= CPU_ARCH_ARMv5)
579 pmdval |= PMD_BIT4;
580 pmd = pmd_offset(pgd + i, i << PGDIR_SHIFT);
581 pmd[0] = __pmd(pmdval);
582 pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
583 flush_pmd_entry(pmd);
584 }
585}
586
587extern void _stext, _etext;
588
589/*
590 * Setup initial mappings. We use the page we allocated for zero page to hold
591 * the mappings, which will get overwritten by the vectors in traps_init().
592 * The mappings must be in virtual address order.
593 */
594void __init memtable_init(struct meminfo *mi)
595{
596 struct map_desc *init_maps, *p, *q;
597 unsigned long address = 0;
598 int i;
599
600 build_mem_type_table();
601
602 init_maps = p = alloc_bootmem_low_pages(PAGE_SIZE);
603
604#ifdef CONFIG_XIP_KERNEL
605 p->physical = CONFIG_XIP_PHYS_ADDR & PMD_MASK;
606 p->virtual = (unsigned long)&_stext & PMD_MASK;
607 p->length = ((unsigned long)&_etext - p->virtual + ~PMD_MASK) & PMD_MASK;
608 p->type = MT_ROM;
609 p ++;
610#endif
611
612 for (i = 0; i < mi->nr_banks; i++) {
613 if (mi->bank[i].size == 0)
614 continue;
615
616 p->physical = mi->bank[i].start;
617 p->virtual = __phys_to_virt(p->physical);
618 p->length = mi->bank[i].size;
619 p->type = MT_MEMORY;
620 p ++;
621 }
622
623#ifdef FLUSH_BASE
624 p->physical = FLUSH_BASE_PHYS;
625 p->virtual = FLUSH_BASE;
626 p->length = PGDIR_SIZE;
627 p->type = MT_CACHECLEAN;
628 p ++;
629#endif
630
631#ifdef FLUSH_BASE_MINICACHE
632 p->physical = FLUSH_BASE_PHYS + PGDIR_SIZE;
633 p->virtual = FLUSH_BASE_MINICACHE;
634 p->length = PGDIR_SIZE;
635 p->type = MT_MINICLEAN;
636 p ++;
637#endif
638
639 /*
640 * Go through the initial mappings, but clear out any
641 * pgdir entries that are not in the description.
642 */
643 q = init_maps;
644 do {
645 if (address < q->virtual || q == p) {
646 clear_mapping(address);
647 address += PGDIR_SIZE;
648 } else {
649 create_mapping(q);
650
651 address = q->virtual + q->length;
652 address = (address + PGDIR_SIZE - 1) & PGDIR_MASK;
653
654 q ++;
655 }
656 } while (address != 0);
657
658 /*
659 * Create a mapping for the machine vectors at the high-vectors
660 * location (0xffff0000). If we aren't using high-vectors, also
661 * create a mapping at the low-vectors virtual address.
662 */
663 init_maps->physical = virt_to_phys(init_maps);
664 init_maps->virtual = 0xffff0000;
665 init_maps->length = PAGE_SIZE;
666 init_maps->type = MT_HIGH_VECTORS;
667 create_mapping(init_maps);
668
669 if (!vectors_high()) {
670 init_maps->virtual = 0;
671 init_maps->type = MT_LOW_VECTORS;
672 create_mapping(init_maps);
673 }
674
675 flush_cache_all();
676 flush_tlb_all();
677}
678
679/*
680 * Create the architecture specific mappings
681 */
682void __init iotable_init(struct map_desc *io_desc, int nr)
683{
684 int i;
685
686 for (i = 0; i < nr; i++)
687 create_mapping(io_desc + i);
688}
689
690static inline void
691free_memmap(int node, unsigned long start_pfn, unsigned long end_pfn)
692{
693 struct page *start_pg, *end_pg;
694 unsigned long pg, pgend;
695
696 /*
697 * Convert start_pfn/end_pfn to a struct page pointer.
698 */
699 start_pg = pfn_to_page(start_pfn);
700 end_pg = pfn_to_page(end_pfn);
701
702 /*
703 * Convert to physical addresses, and
704 * round start upwards and end downwards.
705 */
706 pg = PAGE_ALIGN(__pa(start_pg));
707 pgend = __pa(end_pg) & PAGE_MASK;
708
709 /*
710 * If there are free pages between these,
711 * free the section of the memmap array.
712 */
713 if (pg < pgend)
714 free_bootmem_node(NODE_DATA(node), pg, pgend - pg);
715}
716
717static inline void free_unused_memmap_node(int node, struct meminfo *mi)
718{
719 unsigned long bank_start, prev_bank_end = 0;
720 unsigned int i;
721
722 /*
723 * [FIXME] This relies on each bank being in address order. This
724 * may not be the case, especially if the user has provided the
725 * information on the command line.
726 */
727 for (i = 0; i < mi->nr_banks; i++) {
728 if (mi->bank[i].size == 0 || mi->bank[i].node != node)
729 continue;
730
731 bank_start = mi->bank[i].start >> PAGE_SHIFT;
732 if (bank_start < prev_bank_end) {
733 printk(KERN_ERR "MEM: unordered memory banks. "
734 "Not freeing memmap.\n");
735 break;
736 }
737
738 /*
739 * If we had a previous bank, and there is a space
740 * between the current bank and the previous, free it.
741 */
742 if (prev_bank_end && prev_bank_end != bank_start)
743 free_memmap(node, prev_bank_end, bank_start);
744
745 prev_bank_end = PAGE_ALIGN(mi->bank[i].start +
746 mi->bank[i].size) >> PAGE_SHIFT;
747 }
748}
749
750/*
751 * The mem_map array can get very big. Free
752 * the unused area of the memory map.
753 */
754void __init create_memmap_holes(struct meminfo *mi)
755{
756 int node;
757
758 for_each_online_node(node)
759 free_unused_memmap_node(node, mi);
760}
diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c
new file mode 100644
index 000000000000..32c4b0e35b37
--- /dev/null
+++ b/arch/arm/mm/mmap.c
@@ -0,0 +1,109 @@
1/*
2 * linux/arch/arm/mm/mmap.c
3 */
4#include <linux/config.h>
5#include <linux/fs.h>
6#include <linux/mm.h>
7#include <linux/mman.h>
8#include <linux/shm.h>
9
10#include <asm/system.h>
11
12#define COLOUR_ALIGN(addr,pgoff) \
13 ((((addr)+SHMLBA-1)&~(SHMLBA-1)) + \
14 (((pgoff)<<PAGE_SHIFT) & (SHMLBA-1)))
15
16/*
17 * We need to ensure that shared mappings are correctly aligned to
18 * avoid aliasing issues with VIPT caches. We need to ensure that
19 * a specific page of an object is always mapped at a multiple of
20 * SHMLBA bytes.
21 *
22 * We unconditionally provide this function for all cases, however
23 * in the VIVT case, we optimise out the alignment rules.
24 */
25unsigned long
26arch_get_unmapped_area(struct file *filp, unsigned long addr,
27 unsigned long len, unsigned long pgoff, unsigned long flags)
28{
29 struct mm_struct *mm = current->mm;
30 struct vm_area_struct *vma;
31 unsigned long start_addr;
32#ifdef CONFIG_CPU_V6
33 unsigned int cache_type;
34 int do_align = 0, aliasing = 0;
35
36 /*
37 * We only need to do colour alignment if either the I or D
38 * caches alias. This is indicated by bits 9 and 21 of the
39 * cache type register.
40 */
41 cache_type = read_cpuid(CPUID_CACHETYPE);
42 if (cache_type != read_cpuid(CPUID_ID)) {
43 aliasing = (cache_type | cache_type >> 12) & (1 << 11);
44 if (aliasing)
45 do_align = filp || flags & MAP_SHARED;
46 }
47#else
48#define do_align 0
49#define aliasing 0
50#endif
51
52 /*
53 * We should enforce the MAP_FIXED case. However, currently
54 * the generic kernel code doesn't allow us to handle this.
55 */
56 if (flags & MAP_FIXED) {
57 if (aliasing && flags & MAP_SHARED && addr & (SHMLBA - 1))
58 return -EINVAL;
59 return addr;
60 }
61
62 if (len > TASK_SIZE)
63 return -ENOMEM;
64
65 if (addr) {
66 if (do_align)
67 addr = COLOUR_ALIGN(addr, pgoff);
68 else
69 addr = PAGE_ALIGN(addr);
70
71 vma = find_vma(mm, addr);
72 if (TASK_SIZE - len >= addr &&
73 (!vma || addr + len <= vma->vm_start))
74 return addr;
75 }
76 start_addr = addr = mm->free_area_cache;
77
78full_search:
79 if (do_align)
80 addr = COLOUR_ALIGN(addr, pgoff);
81 else
82 addr = PAGE_ALIGN(addr);
83
84 for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
85 /* At this point: (!vma || addr < vma->vm_end). */
86 if (TASK_SIZE - len < addr) {
87 /*
88 * Start a new search - just in case we missed
89 * some holes.
90 */
91 if (start_addr != TASK_UNMAPPED_BASE) {
92 start_addr = addr = TASK_UNMAPPED_BASE;
93 goto full_search;
94 }
95 return -ENOMEM;
96 }
97 if (!vma || addr + len <= vma->vm_start) {
98 /*
99 * Remember the place where we stopped the search:
100 */
101 mm->free_area_cache = addr + len;
102 return addr;
103 }
104 addr = vma->vm_end;
105 if (do_align)
106 addr = COLOUR_ALIGN(addr, pgoff);
107 }
108}
109
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
new file mode 100644
index 000000000000..0d90227a0a32
--- /dev/null
+++ b/arch/arm/mm/mmu.c
@@ -0,0 +1,45 @@
1/*
2 * linux/arch/arm/mm/mmu.c
3 *
4 * Copyright (C) 2002-2003 Deep Blue Solutions Ltd, all rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/init.h>
11#include <linux/sched.h>
12#include <linux/mm.h>
13
14#include <asm/mmu_context.h>
15#include <asm/tlbflush.h>
16
17unsigned int cpu_last_asid = { 1 << ASID_BITS };
18
19/*
20 * We fork()ed a process, and we need a new context for the child
21 * to run in. We reserve version 0 for initial tasks so we will
22 * always allocate an ASID.
23 */
24void __init_new_context(struct task_struct *tsk, struct mm_struct *mm)
25{
26 mm->context.id = 0;
27}
28
29void __new_context(struct mm_struct *mm)
30{
31 unsigned int asid;
32
33 asid = ++cpu_last_asid;
34 if (asid == 0)
35 asid = cpu_last_asid = 1 << ASID_BITS;
36
37 /*
38 * If we've used up all our ASIDs, we need
39 * to start a new version and flush the TLB.
40 */
41 if ((asid & ~ASID_MASK) == 0)
42 flush_tlb_all();
43
44 mm->context.id = asid;
45}
diff --git a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S
new file mode 100644
index 000000000000..1f325231b9e4
--- /dev/null
+++ b/arch/arm/mm/proc-arm1020.S
@@ -0,0 +1,530 @@
1/*
2 * linux/arch/arm/mm/proc-arm1020.S: MMU functions for ARM1020
3 *
4 * Copyright (C) 2000 ARM Limited
5 * Copyright (C) 2000 Deep Blue Solutions Ltd.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 *
22 * These are the low level assembler for performing cache and TLB
23 * functions on the arm1020.
24 *
25 * CONFIG_CPU_ARM1020_CPU_IDLE -> nohlt
26 */
27#include <linux/linkage.h>
28#include <linux/config.h>
29#include <linux/init.h>
30#include <asm/assembler.h>
31#include <asm/constants.h>
32#include <asm/pgtable.h>
33#include <asm/procinfo.h>
34#include <asm/ptrace.h>
35#include <asm/hardware.h>
36
37/*
38 * This is the maximum size of an area which will be invalidated
39 * using the single invalidate entry instructions. Anything larger
40 * than this, and we go for the whole cache.
41 *
42 * This value should be chosen such that we choose the cheapest
43 * alternative.
44 */
45#define MAX_AREA_SIZE 32768
46
47/*
48 * The size of one data cache line.
49 */
50#define CACHE_DLINESIZE 32
51
52/*
53 * The number of data cache segments.
54 */
55#define CACHE_DSEGMENTS 16
56
57/*
58 * The number of lines in a cache segment.
59 */
60#define CACHE_DENTRIES 64
61
62/*
63 * This is the size at which it becomes more efficient to
64 * clean the whole cache, rather than using the individual
65 * cache line maintainence instructions.
66 */
67#define CACHE_DLIMIT 32768
68
69 .text
70/*
71 * cpu_arm1020_proc_init()
72 */
73ENTRY(cpu_arm1020_proc_init)
74 mov pc, lr
75
76/*
77 * cpu_arm1020_proc_fin()
78 */
79ENTRY(cpu_arm1020_proc_fin)
80 stmfd sp!, {lr}
81 mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
82 msr cpsr_c, ip
83 bl arm1020_flush_kern_cache_all
84 mrc p15, 0, r0, c1, c0, 0 @ ctrl register
85 bic r0, r0, #0x1000 @ ...i............
86 bic r0, r0, #0x000e @ ............wca.
87 mcr p15, 0, r0, c1, c0, 0 @ disable caches
88 ldmfd sp!, {pc}
89
90/*
91 * cpu_arm1020_reset(loc)
92 *
93 * Perform a soft reset of the system. Put the CPU into the
94 * same state as it would be if it had been reset, and branch
95 * to what would be the reset vector.
96 *
97 * loc: location to jump to for soft reset
98 */
99 .align 5
100ENTRY(cpu_arm1020_reset)
101 mov ip, #0
102 mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
103 mcr p15, 0, ip, c7, c10, 4 @ drain WB
104 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
105 mrc p15, 0, ip, c1, c0, 0 @ ctrl register
106 bic ip, ip, #0x000f @ ............wcam
107 bic ip, ip, #0x1100 @ ...i...s........
108 mcr p15, 0, ip, c1, c0, 0 @ ctrl register
109 mov pc, r0
110
111/*
112 * cpu_arm1020_do_idle()
113 */
114 .align 5
115ENTRY(cpu_arm1020_do_idle)
116 mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt
117 mov pc, lr
118
119/* ================================= CACHE ================================ */
120
121 .align 5
122/*
123 * flush_user_cache_all()
124 *
125 * Invalidate all cache entries in a particular address
126 * space.
127 */
128ENTRY(arm1020_flush_user_cache_all)
129 /* FALLTHROUGH */
130/*
131 * flush_kern_cache_all()
132 *
133 * Clean and invalidate the entire cache.
134 */
135ENTRY(arm1020_flush_kern_cache_all)
136 mov r2, #VM_EXEC
137 mov ip, #0
138__flush_whole_cache:
139#ifndef CONFIG_CPU_DCACHE_DISABLE
140 mcr p15, 0, ip, c7, c10, 4 @ drain WB
141 mov r1, #(CACHE_DSEGMENTS - 1) << 5 @ 16 segments
1421: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
1432: mcr p15, 0, r3, c7, c14, 2 @ clean+invalidate D index
144 mcr p15, 0, ip, c7, c10, 4 @ drain WB
145 subs r3, r3, #1 << 26
146 bcs 2b @ entries 63 to 0
147 subs r1, r1, #1 << 5
148 bcs 1b @ segments 15 to 0
149#endif
150 tst r2, #VM_EXEC
151#ifndef CONFIG_CPU_ICACHE_DISABLE
152 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
153#endif
154 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
155 mov pc, lr
156
157/*
158 * flush_user_cache_range(start, end, flags)
159 *
160 * Invalidate a range of cache entries in the specified
161 * address space.
162 *
163 * - start - start address (inclusive)
164 * - end - end address (exclusive)
165 * - flags - vm_flags for this space
166 */
167ENTRY(arm1020_flush_user_cache_range)
168 mov ip, #0
169 sub r3, r1, r0 @ calculate total size
170 cmp r3, #CACHE_DLIMIT
171 bhs __flush_whole_cache
172
173#ifndef CONFIG_CPU_DCACHE_DISABLE
174 mcr p15, 0, ip, c7, c10, 4
1751: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
176 mcr p15, 0, ip, c7, c10, 4 @ drain WB
177 add r0, r0, #CACHE_DLINESIZE
178 cmp r0, r1
179 blo 1b
180#endif
181 tst r2, #VM_EXEC
182#ifndef CONFIG_CPU_ICACHE_DISABLE
183 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
184#endif
185 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
186 mov pc, lr
187
188/*
189 * coherent_kern_range(start, end)
190 *
191 * Ensure coherency between the Icache and the Dcache in the
192 * region described by start. If you have non-snooping
193 * Harvard caches, you need to implement this function.
194 *
195 * - start - virtual start address
196 * - end - virtual end address
197 */
198ENTRY(arm1020_coherent_kern_range)
199 /* FALLTRHOUGH */
200
201/*
202 * coherent_user_range(start, end)
203 *
204 * Ensure coherency between the Icache and the Dcache in the
205 * region described by start. If you have non-snooping
206 * Harvard caches, you need to implement this function.
207 *
208 * - start - virtual start address
209 * - end - virtual end address
210 */
211ENTRY(arm1020_coherent_user_range)
212 mov ip, #0
213 bic r0, r0, #CACHE_DLINESIZE - 1
214 mcr p15, 0, ip, c7, c10, 4
2151:
216#ifndef CONFIG_CPU_DCACHE_DISABLE
217 mcr p15, 0, r0, c7, c10, 1 @ clean D entry
218 mcr p15, 0, ip, c7, c10, 4 @ drain WB
219#endif
220#ifndef CONFIG_CPU_ICACHE_DISABLE
221 mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry
222#endif
223 add r0, r0, #CACHE_DLINESIZE
224 cmp r0, r1
225 blo 1b
226 mcr p15, 0, ip, c7, c10, 4 @ drain WB
227 mov pc, lr
228
229/*
230 * flush_kern_dcache_page(void *page)
231 *
232 * Ensure no D cache aliasing occurs, either with itself or
233 * the I cache
234 *
235 * - page - page aligned address
236 */
237ENTRY(arm1020_flush_kern_dcache_page)
238 mov ip, #0
239#ifndef CONFIG_CPU_DCACHE_DISABLE
240 add r1, r0, #PAGE_SZ
2411: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
242 mcr p15, 0, ip, c7, c10, 4 @ drain WB
243 add r0, r0, #CACHE_DLINESIZE
244 cmp r0, r1
245 blo 1b
246#endif
247 mcr p15, 0, ip, c7, c10, 4 @ drain WB
248 mov pc, lr
249
250/*
251 * dma_inv_range(start, end)
252 *
253 * Invalidate (discard) the specified virtual address range.
254 * May not write back any entries. If 'start' or 'end'
255 * are not cache line aligned, those lines must be written
256 * back.
257 *
258 * - start - virtual start address
259 * - end - virtual end address
260 *
261 * (same as v4wb)
262 */
263ENTRY(arm1020_dma_inv_range)
264 mov ip, #0
265#ifndef CONFIG_CPU_DCACHE_DISABLE
266 tst r0, #CACHE_DLINESIZE - 1
267 bic r0, r0, #CACHE_DLINESIZE - 1
268 mcrne p15, 0, ip, c7, c10, 4
269 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
270 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
271 tst r1, #CACHE_DLINESIZE - 1
272 mcrne p15, 0, ip, c7, c10, 4
273 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry
274 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
2751: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
276 add r0, r0, #CACHE_DLINESIZE
277 cmp r0, r1
278 blo 1b
279#endif
280 mcr p15, 0, ip, c7, c10, 4 @ drain WB
281 mov pc, lr
282
283/*
284 * dma_clean_range(start, end)
285 *
286 * Clean the specified virtual address range.
287 *
288 * - start - virtual start address
289 * - end - virtual end address
290 *
291 * (same as v4wb)
292 */
293ENTRY(arm1020_dma_clean_range)
294 mov ip, #0
295#ifndef CONFIG_CPU_DCACHE_DISABLE
296 bic r0, r0, #CACHE_DLINESIZE - 1
2971: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
298 mcr p15, 0, ip, c7, c10, 4 @ drain WB
299 add r0, r0, #CACHE_DLINESIZE
300 cmp r0, r1
301 blo 1b
302#endif
303 mcr p15, 0, ip, c7, c10, 4 @ drain WB
304 mov pc, lr
305
306/*
307 * dma_flush_range(start, end)
308 *
309 * Clean and invalidate the specified virtual address range.
310 *
311 * - start - virtual start address
312 * - end - virtual end address
313 */
314ENTRY(arm1020_dma_flush_range)
315 mov ip, #0
316#ifndef CONFIG_CPU_DCACHE_DISABLE
317 bic r0, r0, #CACHE_DLINESIZE - 1
318 mcr p15, 0, ip, c7, c10, 4
3191: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
320 mcr p15, 0, ip, c7, c10, 4 @ drain WB
321 add r0, r0, #CACHE_DLINESIZE
322 cmp r0, r1
323 blo 1b
324#endif
325 mcr p15, 0, ip, c7, c10, 4 @ drain WB
326 mov pc, lr
327
328ENTRY(arm1020_cache_fns)
329 .long arm1020_flush_kern_cache_all
330 .long arm1020_flush_user_cache_all
331 .long arm1020_flush_user_cache_range
332 .long arm1020_coherent_kern_range
333 .long arm1020_coherent_user_range
334 .long arm1020_flush_kern_dcache_page
335 .long arm1020_dma_inv_range
336 .long arm1020_dma_clean_range
337 .long arm1020_dma_flush_range
338
339 .align 5
340ENTRY(cpu_arm1020_dcache_clean_area)
341#ifndef CONFIG_CPU_DCACHE_DISABLE
342 mov ip, #0
3431: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
344 mcr p15, 0, ip, c7, c10, 4 @ drain WB
345 add r0, r0, #CACHE_DLINESIZE
346 subs r1, r1, #CACHE_DLINESIZE
347 bhi 1b
348#endif
349 mov pc, lr
350
351/* =============================== PageTable ============================== */
352
353/*
354 * cpu_arm1020_switch_mm(pgd)
355 *
356 * Set the translation base pointer to be as described by pgd.
357 *
358 * pgd: new page tables
359 */
360 .align 5
361ENTRY(cpu_arm1020_switch_mm)
362#ifndef CONFIG_CPU_DCACHE_DISABLE
363 mcr p15, 0, r3, c7, c10, 4
364 mov r1, #0xF @ 16 segments
3651: mov r3, #0x3F @ 64 entries
3662: mov ip, r3, LSL #26 @ shift up entry
367 orr ip, ip, r1, LSL #5 @ shift in/up index
368 mcr p15, 0, ip, c7, c14, 2 @ Clean & Inval DCache entry
369 mov ip, #0
370 mcr p15, 0, ip, c7, c10, 4
371 subs r3, r3, #1
372 cmp r3, #0
373 bge 2b @ entries 3F to 0
374 subs r1, r1, #1
375 cmp r1, #0
376 bge 1b @ segments 15 to 0
377
378#endif
379 mov r1, #0
380#ifndef CONFIG_CPU_ICACHE_DISABLE
381 mcr p15, 0, r1, c7, c5, 0 @ invalidate I cache
382#endif
383 mcr p15, 0, r1, c7, c10, 4 @ drain WB
384 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
385 mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs
386 mov pc, lr
387
388/*
389 * cpu_arm1020_set_pte(ptep, pte)
390 *
391 * Set a PTE and flush it out
392 */
393 .align 5
394ENTRY(cpu_arm1020_set_pte)
395 str r1, [r0], #-2048 @ linux version
396
397 eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
398
399 bic r2, r1, #PTE_SMALL_AP_MASK
400 bic r2, r2, #PTE_TYPE_MASK
401 orr r2, r2, #PTE_TYPE_SMALL
402
403 tst r1, #L_PTE_USER @ User?
404 orrne r2, r2, #PTE_SMALL_AP_URO_SRW
405
406 tst r1, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty?
407 orreq r2, r2, #PTE_SMALL_AP_UNO_SRW
408
409 tst r1, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young?
410 movne r2, #0
411
412#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
413 eor r3, r1, #0x0a @ C & small page?
414 tst r3, #0x0b
415 biceq r2, r2, #4
416#endif
417 str r2, [r0] @ hardware version
418 mov r0, r0
419#ifndef CONFIG_CPU_DCACHE_DISABLE
420 mcr p15, 0, r0, c7, c10, 4
421 mcr p15, 0, r0, c7, c10, 1 @ clean D entry
422#endif
423 mcr p15, 0, r0, c7, c10, 4 @ drain WB
424 mov pc, lr
425
426 __INIT
427
428 .type __arm1020_setup, #function
429__arm1020_setup:
430 mov r0, #0
431 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
432 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
433 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
434 mrc p15, 0, r0, c1, c0 @ get control register v4
435 ldr r5, arm1020_cr1_clear
436 bic r0, r0, r5
437 ldr r5, arm1020_cr1_set
438 orr r0, r0, r5
439#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN
440 orr r0, r0, #0x4000 @ .R.. .... .... ....
441#endif
442 mov pc, lr
443 .size __arm1020_setup, . - __arm1020_setup
444
445 /*
446 * R
447 * .RVI ZFRS BLDP WCAM
448 * .0.1 1001 ..11 0101 /* FIXME: why no V bit? */
449 */
450 .type arm1020_cr1_clear, #object
451 .type arm1020_cr1_set, #object
452arm1020_cr1_clear:
453 .word 0x593f
454arm1020_cr1_set:
455 .word 0x1935
456
457 __INITDATA
458
459/*
460 * Purpose : Function pointers used to access above functions - all calls
461 * come through these
462 */
463 .type arm1020_processor_functions, #object
464arm1020_processor_functions:
465 .word v4t_early_abort
466 .word cpu_arm1020_proc_init
467 .word cpu_arm1020_proc_fin
468 .word cpu_arm1020_reset
469 .word cpu_arm1020_do_idle
470 .word cpu_arm1020_dcache_clean_area
471 .word cpu_arm1020_switch_mm
472 .word cpu_arm1020_set_pte
473 .size arm1020_processor_functions, . - arm1020_processor_functions
474
475 .section ".rodata"
476
477 .type cpu_arch_name, #object
478cpu_arch_name:
479 .asciz "armv5t"
480 .size cpu_arch_name, . - cpu_arch_name
481
482 .type cpu_elf_name, #object
483cpu_elf_name:
484 .asciz "v5"
485 .size cpu_elf_name, . - cpu_elf_name
486
487 .type cpu_arm1020_name, #object
488cpu_arm1020_name:
489 .ascii "ARM1020"
490#ifndef CONFIG_CPU_ICACHE_DISABLE
491 .ascii "i"
492#endif
493#ifndef CONFIG_CPU_DCACHE_DISABLE
494 .ascii "d"
495#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
496 .ascii "(wt)"
497#else
498 .ascii "(wb)"
499#endif
500#endif
501#ifndef CONFIG_CPU_BPREDICT_DISABLE
502 .ascii "B"
503#endif
504#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN
505 .ascii "RR"
506#endif
507 .ascii "\0"
508 .size cpu_arm1020_name, . - cpu_arm1020_name
509
510 .align
511
512 .section ".proc.info", #alloc, #execinstr
513
514 .type __arm1020_proc_info,#object
515__arm1020_proc_info:
516 .long 0x4104a200 @ ARM 1020T (Architecture v5T)
517 .long 0xff0ffff0
518 .long PMD_TYPE_SECT | \
519 PMD_SECT_AP_WRITE | \
520 PMD_SECT_AP_READ
521 b __arm1020_setup
522 .long cpu_arch_name
523 .long cpu_elf_name
524 .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
525 .long cpu_arm1020_name
526 .long arm1020_processor_functions
527 .long v4wbi_tlb_fns
528 .long v4wb_user_fns
529 .long arm1020_cache_fns
530 .size __arm1020_proc_info, . - __arm1020_proc_info
diff --git a/arch/arm/mm/proc-arm1020e.S b/arch/arm/mm/proc-arm1020e.S
new file mode 100644
index 000000000000..142a2c2d6f0b
--- /dev/null
+++ b/arch/arm/mm/proc-arm1020e.S
@@ -0,0 +1,513 @@
1/*
2 * linux/arch/arm/mm/proc-arm1020e.S: MMU functions for ARM1020
3 *
4 * Copyright (C) 2000 ARM Limited
5 * Copyright (C) 2000 Deep Blue Solutions Ltd.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 *
22 * These are the low level assembler for performing cache and TLB
23 * functions on the arm1020e.
24 *
25 * CONFIG_CPU_ARM1020_CPU_IDLE -> nohlt
26 */
27#include <linux/linkage.h>
28#include <linux/config.h>
29#include <linux/init.h>
30#include <asm/assembler.h>
31#include <asm/constants.h>
32#include <asm/pgtable.h>
33#include <asm/procinfo.h>
34#include <asm/ptrace.h>
35#include <asm/hardware.h>
36
37/*
38 * This is the maximum size of an area which will be invalidated
39 * using the single invalidate entry instructions. Anything larger
40 * than this, and we go for the whole cache.
41 *
42 * This value should be chosen such that we choose the cheapest
43 * alternative.
44 */
45#define MAX_AREA_SIZE 32768
46
47/*
48 * The size of one data cache line.
49 */
50#define CACHE_DLINESIZE 32
51
52/*
53 * The number of data cache segments.
54 */
55#define CACHE_DSEGMENTS 16
56
57/*
58 * The number of lines in a cache segment.
59 */
60#define CACHE_DENTRIES 64
61
62/*
63 * This is the size at which it becomes more efficient to
64 * clean the whole cache, rather than using the individual
65 * cache line maintainence instructions.
66 */
67#define CACHE_DLIMIT 32768
68
69 .text
70/*
71 * cpu_arm1020e_proc_init()
72 */
73ENTRY(cpu_arm1020e_proc_init)
74 mov pc, lr
75
76/*
77 * cpu_arm1020e_proc_fin()
78 */
79ENTRY(cpu_arm1020e_proc_fin)
80 stmfd sp!, {lr}
81 mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
82 msr cpsr_c, ip
83 bl arm1020e_flush_kern_cache_all
84 mrc p15, 0, r0, c1, c0, 0 @ ctrl register
85 bic r0, r0, #0x1000 @ ...i............
86 bic r0, r0, #0x000e @ ............wca.
87 mcr p15, 0, r0, c1, c0, 0 @ disable caches
88 ldmfd sp!, {pc}
89
90/*
91 * cpu_arm1020e_reset(loc)
92 *
93 * Perform a soft reset of the system. Put the CPU into the
94 * same state as it would be if it had been reset, and branch
95 * to what would be the reset vector.
96 *
97 * loc: location to jump to for soft reset
98 */
99 .align 5
100ENTRY(cpu_arm1020e_reset)
101 mov ip, #0
102 mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
103 mcr p15, 0, ip, c7, c10, 4 @ drain WB
104 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
105 mrc p15, 0, ip, c1, c0, 0 @ ctrl register
106 bic ip, ip, #0x000f @ ............wcam
107 bic ip, ip, #0x1100 @ ...i...s........
108 mcr p15, 0, ip, c1, c0, 0 @ ctrl register
109 mov pc, r0
110
111/*
112 * cpu_arm1020e_do_idle()
113 */
114 .align 5
115ENTRY(cpu_arm1020e_do_idle)
116 mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt
117 mov pc, lr
118
119/* ================================= CACHE ================================ */
120
121 .align 5
122/*
123 * flush_user_cache_all()
124 *
125 * Invalidate all cache entries in a particular address
126 * space.
127 */
128ENTRY(arm1020e_flush_user_cache_all)
129 /* FALLTHROUGH */
130/*
131 * flush_kern_cache_all()
132 *
133 * Clean and invalidate the entire cache.
134 */
135ENTRY(arm1020e_flush_kern_cache_all)
136 mov r2, #VM_EXEC
137 mov ip, #0
138__flush_whole_cache:
139#ifndef CONFIG_CPU_DCACHE_DISABLE
140 mcr p15, 0, ip, c7, c10, 4 @ drain WB
141 mov r1, #(CACHE_DSEGMENTS - 1) << 5 @ 16 segments
1421: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
1432: mcr p15, 0, r3, c7, c14, 2 @ clean+invalidate D index
144 subs r3, r3, #1 << 26
145 bcs 2b @ entries 63 to 0
146 subs r1, r1, #1 << 5
147 bcs 1b @ segments 15 to 0
148#endif
149 tst r2, #VM_EXEC
150#ifndef CONFIG_CPU_ICACHE_DISABLE
151 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
152#endif
153 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
154 mov pc, lr
155
156/*
157 * flush_user_cache_range(start, end, flags)
158 *
159 * Invalidate a range of cache entries in the specified
160 * address space.
161 *
162 * - start - start address (inclusive)
163 * - end - end address (exclusive)
164 * - flags - vm_flags for this space
165 */
166ENTRY(arm1020e_flush_user_cache_range)
167 mov ip, #0
168 sub r3, r1, r0 @ calculate total size
169 cmp r3, #CACHE_DLIMIT
170 bhs __flush_whole_cache
171
172#ifndef CONFIG_CPU_DCACHE_DISABLE
1731: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
174 add r0, r0, #CACHE_DLINESIZE
175 cmp r0, r1
176 blo 1b
177#endif
178 tst r2, #VM_EXEC
179#ifndef CONFIG_CPU_ICACHE_DISABLE
180 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
181#endif
182 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
183 mov pc, lr
184
185/*
186 * coherent_kern_range(start, end)
187 *
188 * Ensure coherency between the Icache and the Dcache in the
189 * region described by start. If you have non-snooping
190 * Harvard caches, you need to implement this function.
191 *
192 * - start - virtual start address
193 * - end - virtual end address
194 */
195ENTRY(arm1020e_coherent_kern_range)
196 /* FALLTHROUGH */
197/*
198 * coherent_user_range(start, end)
199 *
200 * Ensure coherency between the Icache and the Dcache in the
201 * region described by start. If you have non-snooping
202 * Harvard caches, you need to implement this function.
203 *
204 * - start - virtual start address
205 * - end - virtual end address
206 */
207ENTRY(arm1020e_coherent_user_range)
208 mov ip, #0
209 bic r0, r0, #CACHE_DLINESIZE - 1
2101:
211#ifndef CONFIG_CPU_DCACHE_DISABLE
212 mcr p15, 0, r0, c7, c10, 1 @ clean D entry
213#endif
214#ifndef CONFIG_CPU_ICACHE_DISABLE
215 mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry
216#endif
217 add r0, r0, #CACHE_DLINESIZE
218 cmp r0, r1
219 blo 1b
220 mcr p15, 0, ip, c7, c10, 4 @ drain WB
221 mov pc, lr
222
223/*
224 * flush_kern_dcache_page(void *page)
225 *
226 * Ensure no D cache aliasing occurs, either with itself or
227 * the I cache
228 *
229 * - page - page aligned address
230 */
231ENTRY(arm1020e_flush_kern_dcache_page)
232 mov ip, #0
233#ifndef CONFIG_CPU_DCACHE_DISABLE
234 add r1, r0, #PAGE_SZ
2351: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
236 add r0, r0, #CACHE_DLINESIZE
237 cmp r0, r1
238 blo 1b
239#endif
240 mcr p15, 0, ip, c7, c10, 4 @ drain WB
241 mov pc, lr
242
243/*
244 * dma_inv_range(start, end)
245 *
246 * Invalidate (discard) the specified virtual address range.
247 * May not write back any entries. If 'start' or 'end'
248 * are not cache line aligned, those lines must be written
249 * back.
250 *
251 * - start - virtual start address
252 * - end - virtual end address
253 *
254 * (same as v4wb)
255 */
256ENTRY(arm1020e_dma_inv_range)
257 mov ip, #0
258#ifndef CONFIG_CPU_DCACHE_DISABLE
259 tst r0, #CACHE_DLINESIZE - 1
260 bic r0, r0, #CACHE_DLINESIZE - 1
261 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
262 tst r1, #CACHE_DLINESIZE - 1
263 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry
2641: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
265 add r0, r0, #CACHE_DLINESIZE
266 cmp r0, r1
267 blo 1b
268#endif
269 mcr p15, 0, ip, c7, c10, 4 @ drain WB
270 mov pc, lr
271
272/*
273 * dma_clean_range(start, end)
274 *
275 * Clean the specified virtual address range.
276 *
277 * - start - virtual start address
278 * - end - virtual end address
279 *
280 * (same as v4wb)
281 */
282ENTRY(arm1020e_dma_clean_range)
283 mov ip, #0
284#ifndef CONFIG_CPU_DCACHE_DISABLE
285 bic r0, r0, #CACHE_DLINESIZE - 1
2861: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
287 add r0, r0, #CACHE_DLINESIZE
288 cmp r0, r1
289 blo 1b
290#endif
291 mcr p15, 0, ip, c7, c10, 4 @ drain WB
292 mov pc, lr
293
294/*
295 * dma_flush_range(start, end)
296 *
297 * Clean and invalidate the specified virtual address range.
298 *
299 * - start - virtual start address
300 * - end - virtual end address
301 */
302ENTRY(arm1020e_dma_flush_range)
303 mov ip, #0
304#ifndef CONFIG_CPU_DCACHE_DISABLE
305 bic r0, r0, #CACHE_DLINESIZE - 1
3061: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
307 add r0, r0, #CACHE_DLINESIZE
308 cmp r0, r1
309 blo 1b
310#endif
311 mcr p15, 0, ip, c7, c10, 4 @ drain WB
312 mov pc, lr
313
314ENTRY(arm1020e_cache_fns)
315 .long arm1020e_flush_kern_cache_all
316 .long arm1020e_flush_user_cache_all
317 .long arm1020e_flush_user_cache_range
318 .long arm1020e_coherent_kern_range
319 .long arm1020e_coherent_user_range
320 .long arm1020e_flush_kern_dcache_page
321 .long arm1020e_dma_inv_range
322 .long arm1020e_dma_clean_range
323 .long arm1020e_dma_flush_range
324
325 .align 5
326ENTRY(cpu_arm1020e_dcache_clean_area)
327#ifndef CONFIG_CPU_DCACHE_DISABLE
328 mov ip, #0
3291: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
330 add r0, r0, #CACHE_DLINESIZE
331 subs r1, r1, #CACHE_DLINESIZE
332 bhi 1b
333#endif
334 mov pc, lr
335
336/* =============================== PageTable ============================== */
337
338/*
339 * cpu_arm1020e_switch_mm(pgd)
340 *
341 * Set the translation base pointer to be as described by pgd.
342 *
343 * pgd: new page tables
344 */
345 .align 5
346ENTRY(cpu_arm1020e_switch_mm)
347#ifndef CONFIG_CPU_DCACHE_DISABLE
348 mcr p15, 0, r3, c7, c10, 4
349 mov r1, #0xF @ 16 segments
3501: mov r3, #0x3F @ 64 entries
3512: mov ip, r3, LSL #26 @ shift up entry
352 orr ip, ip, r1, LSL #5 @ shift in/up index
353 mcr p15, 0, ip, c7, c14, 2 @ Clean & Inval DCache entry
354 mov ip, #0
355 subs r3, r3, #1
356 cmp r3, #0
357 bge 2b @ entries 3F to 0
358 subs r1, r1, #1
359 cmp r1, #0
360 bge 1b @ segments 15 to 0
361
362#endif
363 mov r1, #0
364#ifndef CONFIG_CPU_ICACHE_DISABLE
365 mcr p15, 0, r1, c7, c5, 0 @ invalidate I cache
366#endif
367 mcr p15, 0, r1, c7, c10, 4 @ drain WB
368 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
369 mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs
370 mov pc, lr
371
372/*
373 * cpu_arm1020e_set_pte(ptep, pte)
374 *
375 * Set a PTE and flush it out
376 */
377 .align 5
378ENTRY(cpu_arm1020e_set_pte)
379 str r1, [r0], #-2048 @ linux version
380
381 eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
382
383 bic r2, r1, #PTE_SMALL_AP_MASK
384 bic r2, r2, #PTE_TYPE_MASK
385 orr r2, r2, #PTE_TYPE_SMALL
386
387 tst r1, #L_PTE_USER @ User?
388 orrne r2, r2, #PTE_SMALL_AP_URO_SRW
389
390 tst r1, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty?
391 orreq r2, r2, #PTE_SMALL_AP_UNO_SRW
392
393 tst r1, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young?
394 movne r2, #0
395
396#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
397 eor r3, r1, #0x0a @ C & small page?
398 tst r3, #0x0b
399 biceq r2, r2, #4
400#endif
401 str r2, [r0] @ hardware version
402 mov r0, r0
403#ifndef CONFIG_CPU_DCACHE_DISABLE
404 mcr p15, 0, r0, c7, c10, 1 @ clean D entry
405#endif
406 mov pc, lr
407
408 __INIT
409
410 .type __arm1020e_setup, #function
411__arm1020e_setup:
412 mov r0, #0
413 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
414 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
415 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
416 mrc p15, 0, r0, c1, c0 @ get control register v4
417 ldr r5, arm1020e_cr1_clear
418 bic r0, r0, r5
419 ldr r5, arm1020e_cr1_set
420 orr r0, r0, r5
421#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN
422 orr r0, r0, #0x4000 @ .R.. .... .... ....
423#endif
424 mov pc, lr
425 .size __arm1020e_setup, . - __arm1020e_setup
426
427 /*
428 * R
429 * .RVI ZFRS BLDP WCAM
430 * .0.1 1001 ..11 0101 /* FIXME: why no V bit? */
431 */
432 .type arm1020e_cr1_clear, #object
433 .type arm1020e_cr1_set, #object
434arm1020e_cr1_clear:
435 .word 0x5f3f
436arm1020e_cr1_set:
437 .word 0x1935
438
439 __INITDATA
440
441/*
442 * Purpose : Function pointers used to access above functions - all calls
443 * come through these
444 */
445 .type arm1020e_processor_functions, #object
446arm1020e_processor_functions:
447 .word v4t_early_abort
448 .word cpu_arm1020e_proc_init
449 .word cpu_arm1020e_proc_fin
450 .word cpu_arm1020e_reset
451 .word cpu_arm1020e_do_idle
452 .word cpu_arm1020e_dcache_clean_area
453 .word cpu_arm1020e_switch_mm
454 .word cpu_arm1020e_set_pte
455 .size arm1020e_processor_functions, . - arm1020e_processor_functions
456
457 .section ".rodata"
458
459 .type cpu_arch_name, #object
460cpu_arch_name:
461 .asciz "armv5te"
462 .size cpu_arch_name, . - cpu_arch_name
463
464 .type cpu_elf_name, #object
465cpu_elf_name:
466 .asciz "v5"
467 .size cpu_elf_name, . - cpu_elf_name
468
469 .type cpu_arm1020e_name, #object
470cpu_arm1020e_name:
471 .ascii "ARM1020E"
472#ifndef CONFIG_CPU_ICACHE_DISABLE
473 .ascii "i"
474#endif
475#ifndef CONFIG_CPU_DCACHE_DISABLE
476 .ascii "d"
477#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
478 .ascii "(wt)"
479#else
480 .ascii "(wb)"
481#endif
482#endif
483#ifndef CONFIG_CPU_BPREDICT_DISABLE
484 .ascii "B"
485#endif
486#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN
487 .ascii "RR"
488#endif
489 .ascii "\0"
490 .size cpu_arm1020e_name, . - cpu_arm1020e_name
491
492 .align
493
494 .section ".proc.info", #alloc, #execinstr
495
496 .type __arm1020e_proc_info,#object
497__arm1020e_proc_info:
498 .long 0x4105a200 @ ARM 1020TE (Architecture v5TE)
499 .long 0xff0ffff0
500 .long PMD_TYPE_SECT | \
501 PMD_BIT4 | \
502 PMD_SECT_AP_WRITE | \
503 PMD_SECT_AP_READ
504 b __arm1020e_setup
505 .long cpu_arch_name
506 .long cpu_elf_name
507 .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_EDSP
508 .long cpu_arm1020e_name
509 .long arm1020e_processor_functions
510 .long v4wbi_tlb_fns
511 .long v4wb_user_fns
512 .long arm1020e_cache_fns
513 .size __arm1020e_proc_info, . - __arm1020e_proc_info
diff --git a/arch/arm/mm/proc-arm1022.S b/arch/arm/mm/proc-arm1022.S
new file mode 100644
index 000000000000..747ed963e1df
--- /dev/null
+++ b/arch/arm/mm/proc-arm1022.S
@@ -0,0 +1,495 @@
1/*
2 * linux/arch/arm/mm/proc-arm1022.S: MMU functions for ARM1022E
3 *
4 * Copyright (C) 2000 ARM Limited
5 * Copyright (C) 2000 Deep Blue Solutions Ltd.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 *
13 * These are the low level assembler for performing cache and TLB
14 * functions on the ARM1022E.
15 */
16#include <linux/linkage.h>
17#include <linux/config.h>
18#include <linux/init.h>
19#include <asm/assembler.h>
20#include <asm/constants.h>
21#include <asm/pgtable.h>
22#include <asm/procinfo.h>
23#include <asm/ptrace.h>
24
25/*
26 * This is the maximum size of an area which will be invalidated
27 * using the single invalidate entry instructions. Anything larger
28 * than this, and we go for the whole cache.
29 *
30 * This value should be chosen such that we choose the cheapest
31 * alternative.
32 */
33#define MAX_AREA_SIZE 32768
34
35/*
36 * The size of one data cache line.
37 */
38#define CACHE_DLINESIZE 32
39
40/*
41 * The number of data cache segments.
42 */
43#define CACHE_DSEGMENTS 16
44
45/*
46 * The number of lines in a cache segment.
47 */
48#define CACHE_DENTRIES 64
49
50/*
51 * This is the size at which it becomes more efficient to
52 * clean the whole cache, rather than using the individual
53 * cache line maintainence instructions.
54 */
55#define CACHE_DLIMIT 32768
56
57 .text
58/*
59 * cpu_arm1022_proc_init()
60 */
61ENTRY(cpu_arm1022_proc_init)
62 mov pc, lr
63
64/*
65 * cpu_arm1022_proc_fin()
66 */
67ENTRY(cpu_arm1022_proc_fin)
68 stmfd sp!, {lr}
69 mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
70 msr cpsr_c, ip
71 bl arm1022_flush_kern_cache_all
72 mrc p15, 0, r0, c1, c0, 0 @ ctrl register
73 bic r0, r0, #0x1000 @ ...i............
74 bic r0, r0, #0x000e @ ............wca.
75 mcr p15, 0, r0, c1, c0, 0 @ disable caches
76 ldmfd sp!, {pc}
77
78/*
79 * cpu_arm1022_reset(loc)
80 *
81 * Perform a soft reset of the system. Put the CPU into the
82 * same state as it would be if it had been reset, and branch
83 * to what would be the reset vector.
84 *
85 * loc: location to jump to for soft reset
86 */
87 .align 5
88ENTRY(cpu_arm1022_reset)
89 mov ip, #0
90 mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
91 mcr p15, 0, ip, c7, c10, 4 @ drain WB
92 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
93 mrc p15, 0, ip, c1, c0, 0 @ ctrl register
94 bic ip, ip, #0x000f @ ............wcam
95 bic ip, ip, #0x1100 @ ...i...s........
96 mcr p15, 0, ip, c1, c0, 0 @ ctrl register
97 mov pc, r0
98
99/*
100 * cpu_arm1022_do_idle()
101 */
102 .align 5
103ENTRY(cpu_arm1022_do_idle)
104 mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt
105 mov pc, lr
106
107/* ================================= CACHE ================================ */
108
109 .align 5
110/*
111 * flush_user_cache_all()
112 *
113 * Invalidate all cache entries in a particular address
114 * space.
115 */
116ENTRY(arm1022_flush_user_cache_all)
117 /* FALLTHROUGH */
118/*
119 * flush_kern_cache_all()
120 *
121 * Clean and invalidate the entire cache.
122 */
123ENTRY(arm1022_flush_kern_cache_all)
124 mov r2, #VM_EXEC
125 mov ip, #0
126__flush_whole_cache:
127#ifndef CONFIG_CPU_DCACHE_DISABLE
128 mov r1, #(CACHE_DSEGMENTS - 1) << 5 @ 16 segments
1291: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
1302: mcr p15, 0, r3, c7, c14, 2 @ clean+invalidate D index
131 subs r3, r3, #1 << 26
132 bcs 2b @ entries 63 to 0
133 subs r1, r1, #1 << 5
134 bcs 1b @ segments 15 to 0
135#endif
136 tst r2, #VM_EXEC
137#ifndef CONFIG_CPU_ICACHE_DISABLE
138 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
139#endif
140 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
141 mov pc, lr
142
143/*
144 * flush_user_cache_range(start, end, flags)
145 *
146 * Invalidate a range of cache entries in the specified
147 * address space.
148 *
149 * - start - start address (inclusive)
150 * - end - end address (exclusive)
151 * - flags - vm_flags for this space
152 */
153ENTRY(arm1022_flush_user_cache_range)
154 mov ip, #0
155 sub r3, r1, r0 @ calculate total size
156 cmp r3, #CACHE_DLIMIT
157 bhs __flush_whole_cache
158
159#ifndef CONFIG_CPU_DCACHE_DISABLE
1601: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
161 add r0, r0, #CACHE_DLINESIZE
162 cmp r0, r1
163 blo 1b
164#endif
165 tst r2, #VM_EXEC
166#ifndef CONFIG_CPU_ICACHE_DISABLE
167 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
168#endif
169 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
170 mov pc, lr
171
172/*
173 * coherent_kern_range(start, end)
174 *
175 * Ensure coherency between the Icache and the Dcache in the
176 * region described by start. If you have non-snooping
177 * Harvard caches, you need to implement this function.
178 *
179 * - start - virtual start address
180 * - end - virtual end address
181 */
182ENTRY(arm1022_coherent_kern_range)
183 /* FALLTHROUGH */
184
185/*
186 * coherent_user_range(start, end)
187 *
188 * Ensure coherency between the Icache and the Dcache in the
189 * region described by start. If you have non-snooping
190 * Harvard caches, you need to implement this function.
191 *
192 * - start - virtual start address
193 * - end - virtual end address
194 */
195ENTRY(arm1022_coherent_user_range)
196 mov ip, #0
197 bic r0, r0, #CACHE_DLINESIZE - 1
1981:
199#ifndef CONFIG_CPU_DCACHE_DISABLE
200 mcr p15, 0, r0, c7, c10, 1 @ clean D entry
201#endif
202#ifndef CONFIG_CPU_ICACHE_DISABLE
203 mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry
204#endif
205 add r0, r0, #CACHE_DLINESIZE
206 cmp r0, r1
207 blo 1b
208 mcr p15, 0, ip, c7, c10, 4 @ drain WB
209 mov pc, lr
210
211/*
212 * flush_kern_dcache_page(void *page)
213 *
214 * Ensure no D cache aliasing occurs, either with itself or
215 * the I cache
216 *
217 * - page - page aligned address
218 */
219ENTRY(arm1022_flush_kern_dcache_page)
220 mov ip, #0
221#ifndef CONFIG_CPU_DCACHE_DISABLE
222 add r1, r0, #PAGE_SZ
2231: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
224 add r0, r0, #CACHE_DLINESIZE
225 cmp r0, r1
226 blo 1b
227#endif
228 mcr p15, 0, ip, c7, c10, 4 @ drain WB
229 mov pc, lr
230
231/*
232 * dma_inv_range(start, end)
233 *
234 * Invalidate (discard) the specified virtual address range.
235 * May not write back any entries. If 'start' or 'end'
236 * are not cache line aligned, those lines must be written
237 * back.
238 *
239 * - start - virtual start address
240 * - end - virtual end address
241 *
242 * (same as v4wb)
243 */
244ENTRY(arm1022_dma_inv_range)
245 mov ip, #0
246#ifndef CONFIG_CPU_DCACHE_DISABLE
247 tst r0, #CACHE_DLINESIZE - 1
248 bic r0, r0, #CACHE_DLINESIZE - 1
249 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
250 tst r1, #CACHE_DLINESIZE - 1
251 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry
2521: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
253 add r0, r0, #CACHE_DLINESIZE
254 cmp r0, r1
255 blo 1b
256#endif
257 mcr p15, 0, ip, c7, c10, 4 @ drain WB
258 mov pc, lr
259
260/*
261 * dma_clean_range(start, end)
262 *
263 * Clean the specified virtual address range.
264 *
265 * - start - virtual start address
266 * - end - virtual end address
267 *
268 * (same as v4wb)
269 */
270ENTRY(arm1022_dma_clean_range)
271 mov ip, #0
272#ifndef CONFIG_CPU_DCACHE_DISABLE
273 bic r0, r0, #CACHE_DLINESIZE - 1
2741: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
275 add r0, r0, #CACHE_DLINESIZE
276 cmp r0, r1
277 blo 1b
278#endif
279 mcr p15, 0, ip, c7, c10, 4 @ drain WB
280 mov pc, lr
281
282/*
283 * dma_flush_range(start, end)
284 *
285 * Clean and invalidate the specified virtual address range.
286 *
287 * - start - virtual start address
288 * - end - virtual end address
289 */
290ENTRY(arm1022_dma_flush_range)
291 mov ip, #0
292#ifndef CONFIG_CPU_DCACHE_DISABLE
293 bic r0, r0, #CACHE_DLINESIZE - 1
2941: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
295 add r0, r0, #CACHE_DLINESIZE
296 cmp r0, r1
297 blo 1b
298#endif
299 mcr p15, 0, ip, c7, c10, 4 @ drain WB
300 mov pc, lr
301
302ENTRY(arm1022_cache_fns)
303 .long arm1022_flush_kern_cache_all
304 .long arm1022_flush_user_cache_all
305 .long arm1022_flush_user_cache_range
306 .long arm1022_coherent_kern_range
307 .long arm1022_coherent_user_range
308 .long arm1022_flush_kern_dcache_page
309 .long arm1022_dma_inv_range
310 .long arm1022_dma_clean_range
311 .long arm1022_dma_flush_range
312
313 .align 5
314ENTRY(cpu_arm1022_dcache_clean_area)
315#ifndef CONFIG_CPU_DCACHE_DISABLE
316 mov ip, #0
3171: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
318 add r0, r0, #CACHE_DLINESIZE
319 subs r1, r1, #CACHE_DLINESIZE
320 bhi 1b
321#endif
322 mov pc, lr
323
324/* =============================== PageTable ============================== */
325
326/*
327 * cpu_arm1022_switch_mm(pgd)
328 *
329 * Set the translation base pointer to be as described by pgd.
330 *
331 * pgd: new page tables
332 */
333 .align 5
334ENTRY(cpu_arm1022_switch_mm)
335#ifndef CONFIG_CPU_DCACHE_DISABLE
336 mov r1, #(CACHE_DSEGMENTS - 1) << 5 @ 16 segments
3371: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
3382: mcr p15, 0, r3, c7, c14, 2 @ clean+invalidate D index
339 subs r3, r3, #1 << 26
340 bcs 2b @ entries 63 to 0
341 subs r1, r1, #1 << 5
342 bcs 1b @ segments 15 to 0
343#endif
344 mov r1, #0
345#ifndef CONFIG_CPU_ICACHE_DISABLE
346 mcr p15, 0, r1, c7, c5, 0 @ invalidate I cache
347#endif
348 mcr p15, 0, r1, c7, c10, 4 @ drain WB
349 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
350 mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs
351 mov pc, lr
352
353/*
354 * cpu_arm1022_set_pte(ptep, pte)
355 *
356 * Set a PTE and flush it out
357 */
358 .align 5
359ENTRY(cpu_arm1022_set_pte)
360 str r1, [r0], #-2048 @ linux version
361
362 eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
363
364 bic r2, r1, #PTE_SMALL_AP_MASK
365 bic r2, r2, #PTE_TYPE_MASK
366 orr r2, r2, #PTE_TYPE_SMALL
367
368 tst r1, #L_PTE_USER @ User?
369 orrne r2, r2, #PTE_SMALL_AP_URO_SRW
370
371 tst r1, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty?
372 orreq r2, r2, #PTE_SMALL_AP_UNO_SRW
373
374 tst r1, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young?
375 movne r2, #0
376
377#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
378 eor r3, r1, #0x0a @ C & small page?
379 tst r3, #0x0b
380 biceq r2, r2, #4
381#endif
382 str r2, [r0] @ hardware version
383 mov r0, r0
384#ifndef CONFIG_CPU_DCACHE_DISABLE
385 mcr p15, 0, r0, c7, c10, 1 @ clean D entry
386#endif
387 mov pc, lr
388
389 __INIT
390
391 .type __arm1022_setup, #function
392__arm1022_setup:
393 mov r0, #0
394 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
395 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
396 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
397 mrc p15, 0, r0, c1, c0 @ get control register v4
398 ldr r5, arm1022_cr1_clear
399 bic r0, r0, r5
400 ldr r5, arm1022_cr1_set
401 orr r0, r0, r5
402#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN
403 orr r0, r0, #0x4000 @ .R..............
404#endif
405 mov pc, lr
406 .size __arm1022_setup, . - __arm1022_setup
407
408 /*
409 * R
410 * .RVI ZFRS BLDP WCAM
411 * .011 1001 ..11 0101
412 *
413 */
414 .type arm1022_cr1_clear, #object
415 .type arm1022_cr1_set, #object
416arm1022_cr1_clear:
417 .word 0x7f3f
418arm1022_cr1_set:
419 .word 0x3935
420
421 __INITDATA
422
423/*
424 * Purpose : Function pointers used to access above functions - all calls
425 * come through these
426 */
427 .type arm1022_processor_functions, #object
428arm1022_processor_functions:
429 .word v4t_early_abort
430 .word cpu_arm1022_proc_init
431 .word cpu_arm1022_proc_fin
432 .word cpu_arm1022_reset
433 .word cpu_arm1022_do_idle
434 .word cpu_arm1022_dcache_clean_area
435 .word cpu_arm1022_switch_mm
436 .word cpu_arm1022_set_pte
437 .size arm1022_processor_functions, . - arm1022_processor_functions
438
439 .section ".rodata"
440
441 .type cpu_arch_name, #object
442cpu_arch_name:
443 .asciz "armv5te"
444 .size cpu_arch_name, . - cpu_arch_name
445
446 .type cpu_elf_name, #object
447cpu_elf_name:
448 .asciz "v5"
449 .size cpu_elf_name, . - cpu_elf_name
450
451 .type cpu_arm1022_name, #object
452cpu_arm1022_name:
453 .ascii "arm1022"
454#ifndef CONFIG_CPU_ICACHE_DISABLE
455 .ascii "i"
456#endif
457#ifndef CONFIG_CPU_DCACHE_DISABLE
458 .ascii "d"
459#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
460 .ascii "(wt)"
461#else
462 .ascii "(wb)"
463#endif
464#endif
465#ifndef CONFIG_CPU_BPREDICT_DISABLE
466 .ascii "B"
467#endif
468#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN
469 .ascii "RR"
470#endif
471 .ascii "\0"
472 .size cpu_arm1022_name, . - cpu_arm1022_name
473
474 .align
475
476 .section ".proc.info", #alloc, #execinstr
477
478 .type __arm1022_proc_info,#object
479__arm1022_proc_info:
480 .long 0x4105a220 @ ARM 1022E (v5TE)
481 .long 0xff0ffff0
482 .long PMD_TYPE_SECT | \
483 PMD_BIT4 | \
484 PMD_SECT_AP_WRITE | \
485 PMD_SECT_AP_READ
486 b __arm1022_setup
487 .long cpu_arch_name
488 .long cpu_elf_name
489 .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_EDSP
490 .long cpu_arm1022_name
491 .long arm1022_processor_functions
492 .long v4wbi_tlb_fns
493 .long v4wb_user_fns
494 .long arm1022_cache_fns
495 .size __arm1022_proc_info, . - __arm1022_proc_info
diff --git a/arch/arm/mm/proc-arm1026.S b/arch/arm/mm/proc-arm1026.S
new file mode 100644
index 000000000000..248110c9cf13
--- /dev/null
+++ b/arch/arm/mm/proc-arm1026.S
@@ -0,0 +1,491 @@
1/*
2 * linux/arch/arm/mm/proc-arm1026.S: MMU functions for ARM1026EJ-S
3 *
4 * Copyright (C) 2000 ARM Limited
5 * Copyright (C) 2000 Deep Blue Solutions Ltd.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 *
13 * These are the low level assembler for performing cache and TLB
14 * functions on the ARM1026EJ-S.
15 */
16#include <linux/linkage.h>
17#include <linux/config.h>
18#include <linux/init.h>
19#include <asm/assembler.h>
20#include <asm/constants.h>
21#include <asm/pgtable.h>
22#include <asm/procinfo.h>
23#include <asm/ptrace.h>
24
25/*
26 * This is the maximum size of an area which will be invalidated
27 * using the single invalidate entry instructions. Anything larger
28 * than this, and we go for the whole cache.
29 *
30 * This value should be chosen such that we choose the cheapest
31 * alternative.
32 */
33#define MAX_AREA_SIZE 32768
34
35/*
36 * The size of one data cache line.
37 */
38#define CACHE_DLINESIZE 32
39
40/*
41 * The number of data cache segments.
42 */
43#define CACHE_DSEGMENTS 16
44
45/*
46 * The number of lines in a cache segment.
47 */
48#define CACHE_DENTRIES 64
49
50/*
51 * This is the size at which it becomes more efficient to
52 * clean the whole cache, rather than using the individual
53 * cache line maintainence instructions.
54 */
55#define CACHE_DLIMIT 32768
56
57 .text
58/*
59 * cpu_arm1026_proc_init()
60 */
61ENTRY(cpu_arm1026_proc_init)
62 mov pc, lr
63
64/*
65 * cpu_arm1026_proc_fin()
66 */
67ENTRY(cpu_arm1026_proc_fin)
68 stmfd sp!, {lr}
69 mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
70 msr cpsr_c, ip
71 bl arm1026_flush_kern_cache_all
72 mrc p15, 0, r0, c1, c0, 0 @ ctrl register
73 bic r0, r0, #0x1000 @ ...i............
74 bic r0, r0, #0x000e @ ............wca.
75 mcr p15, 0, r0, c1, c0, 0 @ disable caches
76 ldmfd sp!, {pc}
77
78/*
79 * cpu_arm1026_reset(loc)
80 *
81 * Perform a soft reset of the system. Put the CPU into the
82 * same state as it would be if it had been reset, and branch
83 * to what would be the reset vector.
84 *
85 * loc: location to jump to for soft reset
86 */
87 .align 5
88ENTRY(cpu_arm1026_reset)
89 mov ip, #0
90 mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
91 mcr p15, 0, ip, c7, c10, 4 @ drain WB
92 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
93 mrc p15, 0, ip, c1, c0, 0 @ ctrl register
94 bic ip, ip, #0x000f @ ............wcam
95 bic ip, ip, #0x1100 @ ...i...s........
96 mcr p15, 0, ip, c1, c0, 0 @ ctrl register
97 mov pc, r0
98
99/*
100 * cpu_arm1026_do_idle()
101 */
102 .align 5
103ENTRY(cpu_arm1026_do_idle)
104 mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt
105 mov pc, lr
106
107/* ================================= CACHE ================================ */
108
109 .align 5
110/*
111 * flush_user_cache_all()
112 *
113 * Invalidate all cache entries in a particular address
114 * space.
115 */
116ENTRY(arm1026_flush_user_cache_all)
117 /* FALLTHROUGH */
118/*
119 * flush_kern_cache_all()
120 *
121 * Clean and invalidate the entire cache.
122 */
123ENTRY(arm1026_flush_kern_cache_all)
124 mov r2, #VM_EXEC
125 mov ip, #0
126__flush_whole_cache:
127#ifndef CONFIG_CPU_DCACHE_DISABLE
1281: mrc p15, 0, r15, c7, c14, 3 @ test, clean, invalidate
129 bne 1b
130#endif
131 tst r2, #VM_EXEC
132#ifndef CONFIG_CPU_ICACHE_DISABLE
133 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
134#endif
135 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
136 mov pc, lr
137
138/*
139 * flush_user_cache_range(start, end, flags)
140 *
141 * Invalidate a range of cache entries in the specified
142 * address space.
143 *
144 * - start - start address (inclusive)
145 * - end - end address (exclusive)
146 * - flags - vm_flags for this space
147 */
148ENTRY(arm1026_flush_user_cache_range)
149 mov ip, #0
150 sub r3, r1, r0 @ calculate total size
151 cmp r3, #CACHE_DLIMIT
152 bhs __flush_whole_cache
153
154#ifndef CONFIG_CPU_DCACHE_DISABLE
1551: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
156 add r0, r0, #CACHE_DLINESIZE
157 cmp r0, r1
158 blo 1b
159#endif
160 tst r2, #VM_EXEC
161#ifndef CONFIG_CPU_ICACHE_DISABLE
162 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
163#endif
164 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
165 mov pc, lr
166
167/*
168 * coherent_kern_range(start, end)
169 *
170 * Ensure coherency between the Icache and the Dcache in the
171 * region described by start. If you have non-snooping
172 * Harvard caches, you need to implement this function.
173 *
174 * - start - virtual start address
175 * - end - virtual end address
176 */
177ENTRY(arm1026_coherent_kern_range)
178 /* FALLTHROUGH */
179/*
180 * coherent_user_range(start, end)
181 *
182 * Ensure coherency between the Icache and the Dcache in the
183 * region described by start. If you have non-snooping
184 * Harvard caches, you need to implement this function.
185 *
186 * - start - virtual start address
187 * - end - virtual end address
188 */
189ENTRY(arm1026_coherent_user_range)
190 mov ip, #0
191 bic r0, r0, #CACHE_DLINESIZE - 1
1921:
193#ifndef CONFIG_CPU_DCACHE_DISABLE
194 mcr p15, 0, r0, c7, c10, 1 @ clean D entry
195#endif
196#ifndef CONFIG_CPU_ICACHE_DISABLE
197 mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry
198#endif
199 add r0, r0, #CACHE_DLINESIZE
200 cmp r0, r1
201 blo 1b
202 mcr p15, 0, ip, c7, c10, 4 @ drain WB
203 mov pc, lr
204
205/*
206 * flush_kern_dcache_page(void *page)
207 *
208 * Ensure no D cache aliasing occurs, either with itself or
209 * the I cache
210 *
211 * - page - page aligned address
212 */
213ENTRY(arm1026_flush_kern_dcache_page)
214 mov ip, #0
215#ifndef CONFIG_CPU_DCACHE_DISABLE
216 add r1, r0, #PAGE_SZ
2171: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
218 add r0, r0, #CACHE_DLINESIZE
219 cmp r0, r1
220 blo 1b
221#endif
222 mcr p15, 0, ip, c7, c10, 4 @ drain WB
223 mov pc, lr
224
225/*
226 * dma_inv_range(start, end)
227 *
228 * Invalidate (discard) the specified virtual address range.
229 * May not write back any entries. If 'start' or 'end'
230 * are not cache line aligned, those lines must be written
231 * back.
232 *
233 * - start - virtual start address
234 * - end - virtual end address
235 *
236 * (same as v4wb)
237 */
238ENTRY(arm1026_dma_inv_range)
239 mov ip, #0
240#ifndef CONFIG_CPU_DCACHE_DISABLE
241 tst r0, #CACHE_DLINESIZE - 1
242 bic r0, r0, #CACHE_DLINESIZE - 1
243 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
244 tst r1, #CACHE_DLINESIZE - 1
245 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry
2461: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
247 add r0, r0, #CACHE_DLINESIZE
248 cmp r0, r1
249 blo 1b
250#endif
251 mcr p15, 0, ip, c7, c10, 4 @ drain WB
252 mov pc, lr
253
254/*
255 * dma_clean_range(start, end)
256 *
257 * Clean the specified virtual address range.
258 *
259 * - start - virtual start address
260 * - end - virtual end address
261 *
262 * (same as v4wb)
263 */
264ENTRY(arm1026_dma_clean_range)
265 mov ip, #0
266#ifndef CONFIG_CPU_DCACHE_DISABLE
267 bic r0, r0, #CACHE_DLINESIZE - 1
2681: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
269 add r0, r0, #CACHE_DLINESIZE
270 cmp r0, r1
271 blo 1b
272#endif
273 mcr p15, 0, ip, c7, c10, 4 @ drain WB
274 mov pc, lr
275
276/*
277 * dma_flush_range(start, end)
278 *
279 * Clean and invalidate the specified virtual address range.
280 *
281 * - start - virtual start address
282 * - end - virtual end address
283 */
284ENTRY(arm1026_dma_flush_range)
285 mov ip, #0
286#ifndef CONFIG_CPU_DCACHE_DISABLE
287 bic r0, r0, #CACHE_DLINESIZE - 1
2881: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
289 add r0, r0, #CACHE_DLINESIZE
290 cmp r0, r1
291 blo 1b
292#endif
293 mcr p15, 0, ip, c7, c10, 4 @ drain WB
294 mov pc, lr
295
296ENTRY(arm1026_cache_fns)
297 .long arm1026_flush_kern_cache_all
298 .long arm1026_flush_user_cache_all
299 .long arm1026_flush_user_cache_range
300 .long arm1026_coherent_kern_range
301 .long arm1026_coherent_user_range
302 .long arm1026_flush_kern_dcache_page
303 .long arm1026_dma_inv_range
304 .long arm1026_dma_clean_range
305 .long arm1026_dma_flush_range
306
307 .align 5
308ENTRY(cpu_arm1026_dcache_clean_area)
309#ifndef CONFIG_CPU_DCACHE_DISABLE
310 mov ip, #0
3111: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
312 add r0, r0, #CACHE_DLINESIZE
313 subs r1, r1, #CACHE_DLINESIZE
314 bhi 1b
315#endif
316 mov pc, lr
317
318/* =============================== PageTable ============================== */
319
320/*
321 * cpu_arm1026_switch_mm(pgd)
322 *
323 * Set the translation base pointer to be as described by pgd.
324 *
325 * pgd: new page tables
326 */
327 .align 5
328ENTRY(cpu_arm1026_switch_mm)
329 mov r1, #0
330#ifndef CONFIG_CPU_DCACHE_DISABLE
3311: mrc p15, 0, r15, c7, c14, 3 @ test, clean, invalidate
332 bne 1b
333#endif
334#ifndef CONFIG_CPU_ICACHE_DISABLE
335 mcr p15, 0, r1, c7, c5, 0 @ invalidate I cache
336#endif
337 mcr p15, 0, r1, c7, c10, 4 @ drain WB
338 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
339 mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs
340 mov pc, lr
341
342/*
343 * cpu_arm1026_set_pte(ptep, pte)
344 *
345 * Set a PTE and flush it out
346 */
347 .align 5
348ENTRY(cpu_arm1026_set_pte)
349 str r1, [r0], #-2048 @ linux version
350
351 eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
352
353 bic r2, r1, #PTE_SMALL_AP_MASK
354 bic r2, r2, #PTE_TYPE_MASK
355 orr r2, r2, #PTE_TYPE_SMALL
356
357 tst r1, #L_PTE_USER @ User?
358 orrne r2, r2, #PTE_SMALL_AP_URO_SRW
359
360 tst r1, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty?
361 orreq r2, r2, #PTE_SMALL_AP_UNO_SRW
362
363 tst r1, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young?
364 movne r2, #0
365
366#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
367 eor r3, r1, #0x0a @ C & small page?
368 tst r3, #0x0b
369 biceq r2, r2, #4
370#endif
371 str r2, [r0] @ hardware version
372 mov r0, r0
373#ifndef CONFIG_CPU_DCACHE_DISABLE
374 mcr p15, 0, r0, c7, c10, 1 @ clean D entry
375#endif
376 mov pc, lr
377
378
379 __INIT
380
381 .type __arm1026_setup, #function
382__arm1026_setup:
383 mov r0, #0
384 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
385 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
386 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
387 mcr p15, 0, r4, c2, c0 @ load page table pointer
388#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
389 mov r0, #4 @ explicitly disable writeback
390 mcr p15, 7, r0, c15, c0, 0
391#endif
392 mrc p15, 0, r0, c1, c0 @ get control register v4
393 ldr r5, arm1026_cr1_clear
394 bic r0, r0, r5
395 ldr r5, arm1026_cr1_set
396 orr r0, r0, r5
397#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN
398 orr r0, r0, #0x4000 @ .R.. .... .... ....
399#endif
400 mov pc, lr
401 .size __arm1026_setup, . - __arm1026_setup
402
403 /*
404 * R
405 * .RVI ZFRS BLDP WCAM
406 * .011 1001 ..11 0101
407 *
408 */
409 .type arm1026_cr1_clear, #object
410 .type arm1026_cr1_set, #object
411arm1026_cr1_clear:
412 .word 0x7f3f
413arm1026_cr1_set:
414 .word 0x3935
415
416 __INITDATA
417
418/*
419 * Purpose : Function pointers used to access above functions - all calls
420 * come through these
421 */
422 .type arm1026_processor_functions, #object
423arm1026_processor_functions:
424 .word v5t_early_abort
425 .word cpu_arm1026_proc_init
426 .word cpu_arm1026_proc_fin
427 .word cpu_arm1026_reset
428 .word cpu_arm1026_do_idle
429 .word cpu_arm1026_dcache_clean_area
430 .word cpu_arm1026_switch_mm
431 .word cpu_arm1026_set_pte
432 .size arm1026_processor_functions, . - arm1026_processor_functions
433
434 .section .rodata
435
436 .type cpu_arch_name, #object
437cpu_arch_name:
438 .asciz "armv5tej"
439 .size cpu_arch_name, . - cpu_arch_name
440
441 .type cpu_elf_name, #object
442cpu_elf_name:
443 .asciz "v5"
444 .size cpu_elf_name, . - cpu_elf_name
445 .align
446
447 .type cpu_arm1026_name, #object
448cpu_arm1026_name:
449 .ascii "ARM1026EJ-S"
450#ifndef CONFIG_CPU_ICACHE_DISABLE
451 .ascii "i"
452#endif
453#ifndef CONFIG_CPU_DCACHE_DISABLE
454 .ascii "d"
455#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
456 .ascii "(wt)"
457#else
458 .ascii "(wb)"
459#endif
460#endif
461#ifndef CONFIG_CPU_BPREDICT_DISABLE
462 .ascii "B"
463#endif
464#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN
465 .ascii "RR"
466#endif
467 .ascii "\0"
468 .size cpu_arm1026_name, . - cpu_arm1026_name
469
470 .align
471
472 .section ".proc.info", #alloc, #execinstr
473
474 .type __arm1026_proc_info,#object
475__arm1026_proc_info:
476 .long 0x4106a260 @ ARM 1026EJ-S (v5TEJ)
477 .long 0xff0ffff0
478 .long PMD_TYPE_SECT | \
479 PMD_BIT4 | \
480 PMD_SECT_AP_WRITE | \
481 PMD_SECT_AP_READ
482 b __arm1026_setup
483 .long cpu_arch_name
484 .long cpu_elf_name
485 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_JAVA
486 .long cpu_arm1026_name
487 .long arm1026_processor_functions
488 .long v4wbi_tlb_fns
489 .long v4wb_user_fns
490 .long arm1026_cache_fns
491 .size __arm1026_proc_info, . - __arm1026_proc_info
diff --git a/arch/arm/mm/proc-arm6_7.S b/arch/arm/mm/proc-arm6_7.S
new file mode 100644
index 000000000000..0ee214b824ff
--- /dev/null
+++ b/arch/arm/mm/proc-arm6_7.S
@@ -0,0 +1,404 @@
1/*
2 * linux/arch/arm/mm/proc-arm6,7.S
3 *
4 * Copyright (C) 1997-2000 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * These are the low level assembler for performing cache and TLB
11 * functions on the ARM610 & ARM710.
12 */
13#include <linux/linkage.h>
14#include <linux/init.h>
15#include <asm/assembler.h>
16#include <asm/constants.h>
17#include <asm/pgtable.h>
18#include <asm/procinfo.h>
19#include <asm/ptrace.h>
20
21ENTRY(cpu_arm6_dcache_clean_area)
22ENTRY(cpu_arm7_dcache_clean_area)
23 mov pc, lr
24
25/*
26 * Function: arm6_7_data_abort ()
27 *
28 * Params : r2 = address of aborted instruction
29 * : sp = pointer to registers
30 *
31 * Purpose : obtain information about current aborted instruction
32 *
33 * Returns : r0 = address of abort
34 * : r1 = FSR
35 */
36
37ENTRY(cpu_arm7_data_abort)
38 mrc p15, 0, r1, c5, c0, 0 @ get FSR
39 mrc p15, 0, r0, c6, c0, 0 @ get FAR
40 ldr r8, [r0] @ read arm instruction
41 tst r8, #1 << 20 @ L = 1 -> write?
42 orreq r1, r1, #1 << 8 @ yes.
43 and r7, r8, #15 << 24
44 add pc, pc, r7, lsr #22 @ Now branch to the relevant processing routine
45 nop
46
47/* 0 */ b .data_unknown
48/* 1 */ mov pc, lr @ swp
49/* 2 */ b .data_unknown
50/* 3 */ b .data_unknown
51/* 4 */ b .data_arm_lateldrpostconst @ ldr rd, [rn], #m
52/* 5 */ b .data_arm_lateldrpreconst @ ldr rd, [rn, #m]
53/* 6 */ b .data_arm_lateldrpostreg @ ldr rd, [rn], rm
54/* 7 */ b .data_arm_lateldrprereg @ ldr rd, [rn, rm]
55/* 8 */ b .data_arm_ldmstm @ ldm*a rn, <rlist>
56/* 9 */ b .data_arm_ldmstm @ ldm*b rn, <rlist>
57/* a */ b .data_unknown
58/* b */ b .data_unknown
59/* c */ mov pc, lr @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m
60/* d */ mov pc, lr @ ldc rd, [rn, #m]
61/* e */ b .data_unknown
62/* f */
63.data_unknown: @ Part of jumptable
64 mov r0, r2
65 mov r1, r8
66 mov r2, sp
67 bl baddataabort
68 b ret_from_exception
69
70ENTRY(cpu_arm6_data_abort)
71 mrc p15, 0, r1, c5, c0, 0 @ get FSR
72 mrc p15, 0, r0, c6, c0, 0 @ get FAR
73 ldr r8, [r2] @ read arm instruction
74 tst r8, #1 << 20 @ L = 1 -> write?
75 orreq r1, r1, #1 << 8 @ yes.
76 and r7, r8, #14 << 24
77 teq r7, #8 << 24 @ was it ldm/stm
78 movne pc, lr
79
80.data_arm_ldmstm:
81 tst r8, #1 << 21 @ check writeback bit
82 moveq pc, lr @ no writeback -> no fixup
83 mov r7, #0x11
84 orr r7, r7, #0x1100
85 and r6, r8, r7
86 and r2, r8, r7, lsl #1
87 add r6, r6, r2, lsr #1
88 and r2, r8, r7, lsl #2
89 add r6, r6, r2, lsr #2
90 and r2, r8, r7, lsl #3
91 add r6, r6, r2, lsr #3
92 add r6, r6, r6, lsr #8
93 add r6, r6, r6, lsr #4
94 and r6, r6, #15 @ r6 = no. of registers to transfer.
95 and r5, r8, #15 << 16 @ Extract 'n' from instruction
96 ldr r7, [sp, r5, lsr #14] @ Get register 'Rn'
97 tst r8, #1 << 23 @ Check U bit
98 subne r7, r7, r6, lsl #2 @ Undo increment
99 addeq r7, r7, r6, lsl #2 @ Undo decrement
100 str r7, [sp, r5, lsr #14] @ Put register 'Rn'
101 mov pc, lr
102
103.data_arm_apply_r6_and_rn:
104 and r5, r8, #15 << 16 @ Extract 'n' from instruction
105 ldr r7, [sp, r5, lsr #14] @ Get register 'Rn'
106 tst r8, #1 << 23 @ Check U bit
107 subne r7, r7, r6 @ Undo incrmenet
108 addeq r7, r7, r6 @ Undo decrement
109 str r7, [sp, r5, lsr #14] @ Put register 'Rn'
110 mov pc, lr
111
112.data_arm_lateldrpreconst:
113 tst r8, #1 << 21 @ check writeback bit
114 moveq pc, lr @ no writeback -> no fixup
115.data_arm_lateldrpostconst:
116 movs r2, r8, lsl #20 @ Get offset
117 moveq pc, lr @ zero -> no fixup
118 and r5, r8, #15 << 16 @ Extract 'n' from instruction
119 ldr r7, [sp, r5, lsr #14] @ Get register 'Rn'
120 tst r8, #1 << 23 @ Check U bit
121 subne r7, r7, r2, lsr #20 @ Undo increment
122 addeq r7, r7, r2, lsr #20 @ Undo decrement
123 str r7, [sp, r5, lsr #14] @ Put register 'Rn'
124 mov pc, lr
125
126.data_arm_lateldrprereg:
127 tst r8, #1 << 21 @ check writeback bit
128 moveq pc, lr @ no writeback -> no fixup
129.data_arm_lateldrpostreg:
130 and r7, r8, #15 @ Extract 'm' from instruction
131 ldr r6, [sp, r7, lsl #2] @ Get register 'Rm'
132 mov r5, r8, lsr #7 @ get shift count
133 ands r5, r5, #31
134 and r7, r8, #0x70 @ get shift type
135 orreq r7, r7, #8 @ shift count = 0
136 add pc, pc, r7
137 nop
138
139 mov r6, r6, lsl r5 @ 0: LSL #!0
140 b .data_arm_apply_r6_and_rn
141 b .data_arm_apply_r6_and_rn @ 1: LSL #0
142 nop
143 b .data_unknown @ 2: MUL?
144 nop
145 b .data_unknown @ 3: MUL?
146 nop
147 mov r6, r6, lsr r5 @ 4: LSR #!0
148 b .data_arm_apply_r6_and_rn
149 mov r6, r6, lsr #32 @ 5: LSR #32
150 b .data_arm_apply_r6_and_rn
151 b .data_unknown @ 6: MUL?
152 nop
153 b .data_unknown @ 7: MUL?
154 nop
155 mov r6, r6, asr r5 @ 8: ASR #!0
156 b .data_arm_apply_r6_and_rn
157 mov r6, r6, asr #32 @ 9: ASR #32
158 b .data_arm_apply_r6_and_rn
159 b .data_unknown @ A: MUL?
160 nop
161 b .data_unknown @ B: MUL?
162 nop
163 mov r6, r6, ror r5 @ C: ROR #!0
164 b .data_arm_apply_r6_and_rn
165 mov r6, r6, rrx @ D: RRX
166 b .data_arm_apply_r6_and_rn
167 b .data_unknown @ E: MUL?
168 nop
169 b .data_unknown @ F: MUL?
170
171/*
172 * Function: arm6_7_proc_init (void)
173 * : arm6_7_proc_fin (void)
174 *
175 * Notes : This processor does not require these
176 */
177ENTRY(cpu_arm6_proc_init)
178ENTRY(cpu_arm7_proc_init)
179 mov pc, lr
180
181ENTRY(cpu_arm6_proc_fin)
182ENTRY(cpu_arm7_proc_fin)
183 mov r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
184 msr cpsr_c, r0
185 mov r0, #0x31 @ ....S..DP...M
186 mcr p15, 0, r0, c1, c0, 0 @ disable caches
187 mov pc, lr
188
189ENTRY(cpu_arm6_do_idle)
190ENTRY(cpu_arm7_do_idle)
191 mov pc, lr
192
193/*
194 * Function: arm6_7_switch_mm(unsigned long pgd_phys)
195 * Params : pgd_phys Physical address of page table
196 * Purpose : Perform a task switch, saving the old processes state, and restoring
197 * the new.
198 */
199ENTRY(cpu_arm6_switch_mm)
200ENTRY(cpu_arm7_switch_mm)
201 mov r1, #0
202 mcr p15, 0, r1, c7, c0, 0 @ flush cache
203 mcr p15, 0, r0, c2, c0, 0 @ update page table ptr
204 mcr p15, 0, r1, c5, c0, 0 @ flush TLBs
205 mov pc, lr
206
207/*
208 * Function: arm6_7_set_pte(pte_t *ptep, pte_t pte)
209 * Params : r0 = Address to set
210 * : r1 = value to set
211 * Purpose : Set a PTE and flush it out of any WB cache
212 */
213 .align 5
214ENTRY(cpu_arm6_set_pte)
215ENTRY(cpu_arm7_set_pte)
216 str r1, [r0], #-2048 @ linux version
217
218 eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
219
220 bic r2, r1, #PTE_SMALL_AP_MASK
221 bic r2, r2, #PTE_TYPE_MASK
222 orr r2, r2, #PTE_TYPE_SMALL
223
224 tst r1, #L_PTE_USER @ User?
225 orrne r2, r2, #PTE_SMALL_AP_URO_SRW
226
227 tst r1, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty?
228 orreq r2, r2, #PTE_SMALL_AP_UNO_SRW
229
230 tst r1, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young
231 movne r2, #0
232
233 str r2, [r0] @ hardware version
234 mov pc, lr
235
236/*
237 * Function: _arm6_7_reset
238 * Params : r0 = address to jump to
239 * Notes : This sets up everything for a reset
240 */
241ENTRY(cpu_arm6_reset)
242ENTRY(cpu_arm7_reset)
243 mov r1, #0
244 mcr p15, 0, r1, c7, c0, 0 @ flush cache
245 mcr p15, 0, r1, c5, c0, 0 @ flush TLB
246 mov r1, #0x30
247 mcr p15, 0, r1, c1, c0, 0 @ turn off MMU etc
248 mov pc, r0
249
250 __INIT
251
252 .type __arm6_setup, #function
253__arm6_setup: mov r0, #0
254 mcr p15, 0, r0, c7, c0 @ flush caches on v3
255 mcr p15, 0, r0, c5, c0 @ flush TLBs on v3
256 mov r0, #0x3d @ . ..RS BLDP WCAM
257 orr r0, r0, #0x100 @ . ..01 0011 1101
258 mov pc, lr
259 .size __arm6_setup, . - __arm6_setup
260
261 .type __arm7_setup, #function
262__arm7_setup: mov r0, #0
263 mcr p15, 0, r0, c7, c0 @ flush caches on v3
264 mcr p15, 0, r0, c5, c0 @ flush TLBs on v3
265 mcr p15, 0, r0, c3, c0 @ load domain access register
266 mov r0, #0x7d @ . ..RS BLDP WCAM
267 orr r0, r0, #0x100 @ . ..01 0111 1101
268 mov pc, lr
269 .size __arm7_setup, . - __arm7_setup
270
271 __INITDATA
272
273/*
274 * Purpose : Function pointers used to access above functions - all calls
275 * come through these
276 */
277 .type arm6_processor_functions, #object
278ENTRY(arm6_processor_functions)
279 .word cpu_arm6_data_abort
280 .word cpu_arm6_proc_init
281 .word cpu_arm6_proc_fin
282 .word cpu_arm6_reset
283 .word cpu_arm6_do_idle
284 .word cpu_arm6_dcache_clean_area
285 .word cpu_arm6_switch_mm
286 .word cpu_arm6_set_pte
287 .size arm6_processor_functions, . - arm6_processor_functions
288
289/*
290 * Purpose : Function pointers used to access above functions - all calls
291 * come through these
292 */
293 .type arm7_processor_functions, #object
294ENTRY(arm7_processor_functions)
295 .word cpu_arm7_data_abort
296 .word cpu_arm7_proc_init
297 .word cpu_arm7_proc_fin
298 .word cpu_arm7_reset
299 .word cpu_arm7_do_idle
300 .word cpu_arm7_dcache_clean_area
301 .word cpu_arm7_switch_mm
302 .word cpu_arm7_set_pte
303 .size arm7_processor_functions, . - arm7_processor_functions
304
305 .section ".rodata"
306
307 .type cpu_arch_name, #object
308cpu_arch_name: .asciz "armv3"
309 .size cpu_arch_name, . - cpu_arch_name
310
311 .type cpu_elf_name, #object
312cpu_elf_name: .asciz "v3"
313 .size cpu_elf_name, . - cpu_elf_name
314
315 .type cpu_arm6_name, #object
316cpu_arm6_name: .asciz "ARM6"
317 .size cpu_arm6_name, . - cpu_arm6_name
318
319 .type cpu_arm610_name, #object
320cpu_arm610_name:
321 .asciz "ARM610"
322 .size cpu_arm610_name, . - cpu_arm610_name
323
324 .type cpu_arm7_name, #object
325cpu_arm7_name: .asciz "ARM7"
326 .size cpu_arm7_name, . - cpu_arm7_name
327
328 .type cpu_arm710_name, #object
329cpu_arm710_name:
330 .asciz "ARM710"
331 .size cpu_arm710_name, . - cpu_arm710_name
332
333 .align
334
335 .section ".proc.info", #alloc, #execinstr
336
337 .type __arm6_proc_info, #object
338__arm6_proc_info:
339 .long 0x41560600
340 .long 0xfffffff0
341 .long 0x00000c1e
342 b __arm6_setup
343 .long cpu_arch_name
344 .long cpu_elf_name
345 .long HWCAP_SWP | HWCAP_26BIT
346 .long cpu_arm6_name
347 .long arm6_processor_functions
348 .long v3_tlb_fns
349 .long v3_user_fns
350 .long v3_cache_fns
351 .size __arm6_proc_info, . - __arm6_proc_info
352
353 .type __arm610_proc_info, #object
354__arm610_proc_info:
355 .long 0x41560610
356 .long 0xfffffff0
357 .long 0x00000c1e
358 b __arm6_setup
359 .long cpu_arch_name
360 .long cpu_elf_name
361 .long HWCAP_SWP | HWCAP_26BIT
362 .long cpu_arm610_name
363 .long arm6_processor_functions
364 .long v3_tlb_fns
365 .long v3_user_fns
366 .long v3_cache_fns
367 .size __arm610_proc_info, . - __arm610_proc_info
368
369 .type __arm7_proc_info, #object
370__arm7_proc_info:
371 .long 0x41007000
372 .long 0xffffff00
373 .long 0x00000c1e
374 b __arm7_setup
375 .long cpu_arch_name
376 .long cpu_elf_name
377 .long HWCAP_SWP | HWCAP_26BIT
378 .long cpu_arm7_name
379 .long arm7_processor_functions
380 .long v3_tlb_fns
381 .long v3_user_fns
382 .long v3_cache_fns
383 .size __arm7_proc_info, . - __arm7_proc_info
384
385 .type __arm710_proc_info, #object
386__arm710_proc_info:
387 .long 0x41007100
388 .long 0xfff8ff00
389 .long PMD_TYPE_SECT | \
390 PMD_SECT_BUFFERABLE | \
391 PMD_SECT_CACHEABLE | \
392 PMD_BIT4 | \
393 PMD_SECT_AP_WRITE | \
394 PMD_SECT_AP_READ
395 b __arm7_setup
396 .long cpu_arch_name
397 .long cpu_elf_name
398 .long HWCAP_SWP | HWCAP_26BIT
399 .long cpu_arm710_name
400 .long arm7_processor_functions
401 .long v3_tlb_fns
402 .long v3_user_fns
403 .long v3_cache_fns
404 .size __arm710_proc_info, . - __arm710_proc_info
diff --git a/arch/arm/mm/proc-arm720.S b/arch/arm/mm/proc-arm720.S
new file mode 100644
index 000000000000..57cfa6a2f54f
--- /dev/null
+++ b/arch/arm/mm/proc-arm720.S
@@ -0,0 +1,267 @@
1/*
2 * linux/arch/arm/mm/proc-arm720.S: MMU functions for ARM720
3 *
4 * Copyright (C) 2000 Steve Hill (sjhill@cotw.com)
5 * Rob Scott (rscott@mtrob.fdns.net)
6 * Copyright (C) 2000 ARM Limited, Deep Blue Solutions Ltd.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 *
23 * These are the low level assembler for performing cache and TLB
24 * functions on the ARM720T. The ARM720T has a writethrough IDC
25 * cache, so we don't need to clean it.
26 *
27 * Changelog:
28 * 05-09-2000 SJH Created by moving 720 specific functions
29 * out of 'proc-arm6,7.S' per RMK discussion
30 * 07-25-2000 SJH Added idle function.
31 * 08-25-2000 DBS Updated for integration of ARM Ltd version.
32 */
33#include <linux/linkage.h>
34#include <linux/init.h>
35#include <asm/assembler.h>
36#include <asm/constants.h>
37#include <asm/pgtable.h>
38#include <asm/procinfo.h>
39#include <asm/ptrace.h>
40#include <asm/hardware.h>
41
42/*
43 * Function: arm720_proc_init (void)
44 * : arm720_proc_fin (void)
45 *
46 * Notes : This processor does not require these
47 */
48ENTRY(cpu_arm720_dcache_clean_area)
49ENTRY(cpu_arm720_proc_init)
50 mov pc, lr
51
52ENTRY(cpu_arm720_proc_fin)
53 stmfd sp!, {lr}
54 mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
55 msr cpsr_c, ip
56 mrc p15, 0, r0, c1, c0, 0
57 bic r0, r0, #0x1000 @ ...i............
58 bic r0, r0, #0x000e @ ............wca.
59 mcr p15, 0, r0, c1, c0, 0 @ disable caches
60 mcr p15, 0, r1, c7, c7, 0 @ invalidate cache
61 ldmfd sp!, {pc}
62
63/*
64 * Function: arm720_proc_do_idle(void)
65 * Params : r0 = unused
66 * Purpose : put the processer in proper idle mode
67 */
68ENTRY(cpu_arm720_do_idle)
69 mov pc, lr
70
71/*
72 * Function: arm720_switch_mm(unsigned long pgd_phys)
73 * Params : pgd_phys Physical address of page table
74 * Purpose : Perform a task switch, saving the old process' state and restoring
75 * the new.
76 */
77ENTRY(cpu_arm720_switch_mm)
78 mov r1, #0
79 mcr p15, 0, r1, c7, c7, 0 @ invalidate cache
80 mcr p15, 0, r0, c2, c0, 0 @ update page table ptr
81 mcr p15, 0, r1, c8, c7, 0 @ flush TLB (v4)
82 mov pc, lr
83
84/*
85 * Function: arm720_set_pte(pte_t *ptep, pte_t pte)
86 * Params : r0 = Address to set
87 * : r1 = value to set
88 * Purpose : Set a PTE and flush it out of any WB cache
89 */
90 .align 5
91ENTRY(cpu_arm720_set_pte)
92 str r1, [r0], #-2048 @ linux version
93
94 eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
95
96 bic r2, r1, #PTE_SMALL_AP_MASK
97 bic r2, r2, #PTE_TYPE_MASK
98 orr r2, r2, #PTE_TYPE_SMALL
99
100 tst r1, #L_PTE_USER @ User?
101 orrne r2, r2, #PTE_SMALL_AP_URO_SRW
102
103 tst r1, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty?
104 orreq r2, r2, #PTE_SMALL_AP_UNO_SRW
105
106 tst r1, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young
107 movne r2, #0
108
109 str r2, [r0] @ hardware version
110 mov pc, lr
111
112/*
113 * Function: arm720_reset
114 * Params : r0 = address to jump to
115 * Notes : This sets up everything for a reset
116 */
117ENTRY(cpu_arm720_reset)
118 mov ip, #0
119 mcr p15, 0, ip, c7, c7, 0 @ invalidate cache
120 mcr p15, 0, ip, c8, c7, 0 @ flush TLB (v4)
121 mrc p15, 0, ip, c1, c0, 0 @ get ctrl register
122 bic ip, ip, #0x000f @ ............wcam
123 bic ip, ip, #0x2100 @ ..v....s........
124 mcr p15, 0, ip, c1, c0, 0 @ ctrl register
125 mov pc, r0
126
127 __INIT
128
129 .type __arm710_setup, #function
130__arm710_setup:
131 mov r0, #0
132 mcr p15, 0, r0, c7, c7, 0 @ invalidate caches
133 mcr p15, 0, r0, c8, c7, 0 @ flush TLB (v4)
134 mrc p15, 0, r0, c1, c0 @ get control register
135 ldr r5, arm710_cr1_clear
136 bic r0, r0, r5
137 ldr r5, arm710_cr1_set
138 orr r0, r0, r5
139 mov pc, lr @ __ret (head.S)
140 .size __arm710_setup, . - __arm710_setup
141
142 /*
143 * R
144 * .RVI ZFRS BLDP WCAM
145 * .... 0001 ..11 1101
146 *
147 */
148 .type arm710_cr1_clear, #object
149 .type arm710_cr1_set, #object
150arm710_cr1_clear:
151 .word 0x0f3f
152arm710_cr1_set:
153 .word 0x013d
154
155 .type __arm720_setup, #function
156__arm720_setup:
157 mov r0, #0
158 mcr p15, 0, r0, c7, c7, 0 @ invalidate caches
159 mcr p15, 0, r0, c8, c7, 0 @ flush TLB (v4)
160 mrc p15, 0, r0, c1, c0 @ get control register
161 ldr r5, arm720_cr1_clear
162 bic r0, r0, r5
163 ldr r5, arm720_cr1_set
164 orr r0, r0, r5
165 mov pc, lr @ __ret (head.S)
166 .size __arm720_setup, . - __arm720_setup
167
168 /*
169 * R
170 * .RVI ZFRS BLDP WCAM
171 * ..1. 1001 ..11 1101
172 *
173 */
174 .type arm720_cr1_clear, #object
175 .type arm720_cr1_set, #object
176arm720_cr1_clear:
177 .word 0x2f3f
178arm720_cr1_set:
179 .word 0x213d
180
181 __INITDATA
182
183/*
184 * Purpose : Function pointers used to access above functions - all calls
185 * come through these
186 */
187 .type arm720_processor_functions, #object
188ENTRY(arm720_processor_functions)
189 .word v4t_late_abort
190 .word cpu_arm720_proc_init
191 .word cpu_arm720_proc_fin
192 .word cpu_arm720_reset
193 .word cpu_arm720_do_idle
194 .word cpu_arm720_dcache_clean_area
195 .word cpu_arm720_switch_mm
196 .word cpu_arm720_set_pte
197 .size arm720_processor_functions, . - arm720_processor_functions
198
199 .section ".rodata"
200
201 .type cpu_arch_name, #object
202cpu_arch_name: .asciz "armv4t"
203 .size cpu_arch_name, . - cpu_arch_name
204
205 .type cpu_elf_name, #object
206cpu_elf_name: .asciz "v4"
207 .size cpu_elf_name, . - cpu_elf_name
208
209 .type cpu_arm710_name, #object
210cpu_arm710_name:
211 .asciz "ARM710T"
212 .size cpu_arm710_name, . - cpu_arm710_name
213
214 .type cpu_arm720_name, #object
215cpu_arm720_name:
216 .asciz "ARM720T"
217 .size cpu_arm720_name, . - cpu_arm720_name
218
219 .align
220
221/*
222 * See linux/include/asm-arm/procinfo.h for a definition of this structure.
223 */
224
225 .section ".proc.info", #alloc, #execinstr
226
227 .type __arm710_proc_info, #object
228__arm710_proc_info:
229 .long 0x41807100 @ cpu_val
230 .long 0xffffff00 @ cpu_mask
231 .long PMD_TYPE_SECT | \
232 PMD_SECT_BUFFERABLE | \
233 PMD_SECT_CACHEABLE | \
234 PMD_BIT4 | \
235 PMD_SECT_AP_WRITE | \
236 PMD_SECT_AP_READ
237 b __arm710_setup @ cpu_flush
238 .long cpu_arch_name @ arch_name
239 .long cpu_elf_name @ elf_name
240 .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB @ elf_hwcap
241 .long cpu_arm710_name @ name
242 .long arm720_processor_functions
243 .long v4_tlb_fns
244 .long v4wt_user_fns
245 .long v4_cache_fns
246 .size __arm710_proc_info, . - __arm710_proc_info
247
248 .type __arm720_proc_info, #object
249__arm720_proc_info:
250 .long 0x41807200 @ cpu_val
251 .long 0xffffff00 @ cpu_mask
252 .long PMD_TYPE_SECT | \
253 PMD_SECT_BUFFERABLE | \
254 PMD_SECT_CACHEABLE | \
255 PMD_BIT4 | \
256 PMD_SECT_AP_WRITE | \
257 PMD_SECT_AP_READ
258 b __arm720_setup @ cpu_flush
259 .long cpu_arch_name @ arch_name
260 .long cpu_elf_name @ elf_name
261 .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB @ elf_hwcap
262 .long cpu_arm720_name @ name
263 .long arm720_processor_functions
264 .long v4_tlb_fns
265 .long v4wt_user_fns
266 .long v4_cache_fns
267 .size __arm720_proc_info, . - __arm720_proc_info
diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S
new file mode 100644
index 000000000000..0f490a0fcb71
--- /dev/null
+++ b/arch/arm/mm/proc-arm920.S
@@ -0,0 +1,480 @@
1/*
2 * linux/arch/arm/mm/proc-arm920.S: MMU functions for ARM920
3 *
4 * Copyright (C) 1999,2000 ARM Limited
5 * Copyright (C) 2000 Deep Blue Solutions Ltd.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 *
22 * These are the low level assembler for performing cache and TLB
23 * functions on the arm920.
24 *
25 * CONFIG_CPU_ARM920_CPU_IDLE -> nohlt
26 */
27#include <linux/linkage.h>
28#include <linux/config.h>
29#include <linux/init.h>
30#include <asm/assembler.h>
31#include <asm/pgtable.h>
32#include <asm/procinfo.h>
33#include <asm/hardware.h>
34#include <asm/page.h>
35#include <asm/ptrace.h>
36#include "proc-macros.S"
37
38/*
39 * The size of one data cache line.
40 */
41#define CACHE_DLINESIZE 32
42
43/*
44 * The number of data cache segments.
45 */
46#define CACHE_DSEGMENTS 8
47
48/*
49 * The number of lines in a cache segment.
50 */
51#define CACHE_DENTRIES 64
52
53/*
54 * This is the size at which it becomes more efficient to
55 * clean the whole cache, rather than using the individual
56 * cache line maintainence instructions.
57 */
58#define CACHE_DLIMIT 65536
59
60
61 .text
62/*
63 * cpu_arm920_proc_init()
64 */
65ENTRY(cpu_arm920_proc_init)
66 mov pc, lr
67
68/*
69 * cpu_arm920_proc_fin()
70 */
71ENTRY(cpu_arm920_proc_fin)
72 stmfd sp!, {lr}
73 mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
74 msr cpsr_c, ip
75#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
76 bl arm920_flush_kern_cache_all
77#else
78 bl v4wt_flush_kern_cache_all
79#endif
80 mrc p15, 0, r0, c1, c0, 0 @ ctrl register
81 bic r0, r0, #0x1000 @ ...i............
82 bic r0, r0, #0x000e @ ............wca.
83 mcr p15, 0, r0, c1, c0, 0 @ disable caches
84 ldmfd sp!, {pc}
85
86/*
87 * cpu_arm920_reset(loc)
88 *
89 * Perform a soft reset of the system. Put the CPU into the
90 * same state as it would be if it had been reset, and branch
91 * to what would be the reset vector.
92 *
93 * loc: location to jump to for soft reset
94 */
95 .align 5
96ENTRY(cpu_arm920_reset)
97 mov ip, #0
98 mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
99 mcr p15, 0, ip, c7, c10, 4 @ drain WB
100 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
101 mrc p15, 0, ip, c1, c0, 0 @ ctrl register
102 bic ip, ip, #0x000f @ ............wcam
103 bic ip, ip, #0x1100 @ ...i...s........
104 mcr p15, 0, ip, c1, c0, 0 @ ctrl register
105 mov pc, r0
106
107/*
108 * cpu_arm920_do_idle()
109 */
110 .align 5
111ENTRY(cpu_arm920_do_idle)
112 mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt
113 mov pc, lr
114
115
116#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
117
118/*
119 * flush_user_cache_all()
120 *
121 * Invalidate all cache entries in a particular address
122 * space.
123 */
124ENTRY(arm920_flush_user_cache_all)
125 /* FALLTHROUGH */
126
127/*
128 * flush_kern_cache_all()
129 *
130 * Clean and invalidate the entire cache.
131 */
132ENTRY(arm920_flush_kern_cache_all)
133 mov r2, #VM_EXEC
134 mov ip, #0
135__flush_whole_cache:
136 mov r1, #(CACHE_DSEGMENTS - 1) << 5 @ 8 segments
1371: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
1382: mcr p15, 0, r3, c7, c14, 2 @ clean+invalidate D index
139 subs r3, r3, #1 << 26
140 bcs 2b @ entries 63 to 0
141 subs r1, r1, #1 << 5
142 bcs 1b @ segments 7 to 0
143 tst r2, #VM_EXEC
144 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
145 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
146 mov pc, lr
147
148/*
149 * flush_user_cache_range(start, end, flags)
150 *
151 * Invalidate a range of cache entries in the specified
152 * address space.
153 *
154 * - start - start address (inclusive)
155 * - end - end address (exclusive)
156 * - flags - vm_flags for address space
157 */
158ENTRY(arm920_flush_user_cache_range)
159 mov ip, #0
160 sub r3, r1, r0 @ calculate total size
161 cmp r3, #CACHE_DLIMIT
162 bhs __flush_whole_cache
163
1641: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
165 tst r2, #VM_EXEC
166 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
167 add r0, r0, #CACHE_DLINESIZE
168 cmp r0, r1
169 blo 1b
170 tst r2, #VM_EXEC
171 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
172 mov pc, lr
173
174/*
175 * coherent_kern_range(start, end)
176 *
177 * Ensure coherency between the Icache and the Dcache in the
178 * region described by start, end. If you have non-snooping
179 * Harvard caches, you need to implement this function.
180 *
181 * - start - virtual start address
182 * - end - virtual end address
183 */
184ENTRY(arm920_coherent_kern_range)
185 /* FALLTHROUGH */
186
187/*
188 * coherent_user_range(start, end)
189 *
190 * Ensure coherency between the Icache and the Dcache in the
191 * region described by start, end. If you have non-snooping
192 * Harvard caches, you need to implement this function.
193 *
194 * - start - virtual start address
195 * - end - virtual end address
196 */
197ENTRY(arm920_coherent_user_range)
198 bic r0, r0, #CACHE_DLINESIZE - 1
1991: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
200 mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry
201 add r0, r0, #CACHE_DLINESIZE
202 cmp r0, r1
203 blo 1b
204 mcr p15, 0, r0, c7, c10, 4 @ drain WB
205 mov pc, lr
206
207/*
208 * flush_kern_dcache_page(void *page)
209 *
210 * Ensure no D cache aliasing occurs, either with itself or
211 * the I cache
212 *
213 * - addr - page aligned address
214 */
215ENTRY(arm920_flush_kern_dcache_page)
216 add r1, r0, #PAGE_SZ
2171: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
218 add r0, r0, #CACHE_DLINESIZE
219 cmp r0, r1
220 blo 1b
221 mov r0, #0
222 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
223 mcr p15, 0, r0, c7, c10, 4 @ drain WB
224 mov pc, lr
225
226/*
227 * dma_inv_range(start, end)
228 *
229 * Invalidate (discard) the specified virtual address range.
230 * May not write back any entries. If 'start' or 'end'
231 * are not cache line aligned, those lines must be written
232 * back.
233 *
234 * - start - virtual start address
235 * - end - virtual end address
236 *
237 * (same as v4wb)
238 */
239ENTRY(arm920_dma_inv_range)
240 tst r0, #CACHE_DLINESIZE - 1
241 bic r0, r0, #CACHE_DLINESIZE - 1
242 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
243 tst r1, #CACHE_DLINESIZE - 1
244 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry
2451: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
246 add r0, r0, #CACHE_DLINESIZE
247 cmp r0, r1
248 blo 1b
249 mcr p15, 0, r0, c7, c10, 4 @ drain WB
250 mov pc, lr
251
252/*
253 * dma_clean_range(start, end)
254 *
255 * Clean the specified virtual address range.
256 *
257 * - start - virtual start address
258 * - end - virtual end address
259 *
260 * (same as v4wb)
261 */
262ENTRY(arm920_dma_clean_range)
263 bic r0, r0, #CACHE_DLINESIZE - 1
2641: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
265 add r0, r0, #CACHE_DLINESIZE
266 cmp r0, r1
267 blo 1b
268 mcr p15, 0, r0, c7, c10, 4 @ drain WB
269 mov pc, lr
270
271/*
272 * dma_flush_range(start, end)
273 *
274 * Clean and invalidate the specified virtual address range.
275 *
276 * - start - virtual start address
277 * - end - virtual end address
278 */
279ENTRY(arm920_dma_flush_range)
280 bic r0, r0, #CACHE_DLINESIZE - 1
2811: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
282 add r0, r0, #CACHE_DLINESIZE
283 cmp r0, r1
284 blo 1b
285 mcr p15, 0, r0, c7, c10, 4 @ drain WB
286 mov pc, lr
287
288ENTRY(arm920_cache_fns)
289 .long arm920_flush_kern_cache_all
290 .long arm920_flush_user_cache_all
291 .long arm920_flush_user_cache_range
292 .long arm920_coherent_kern_range
293 .long arm920_coherent_user_range
294 .long arm920_flush_kern_dcache_page
295 .long arm920_dma_inv_range
296 .long arm920_dma_clean_range
297 .long arm920_dma_flush_range
298
299#endif
300
301
302ENTRY(cpu_arm920_dcache_clean_area)
3031: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
304 add r0, r0, #CACHE_DLINESIZE
305 subs r1, r1, #CACHE_DLINESIZE
306 bhi 1b
307 mov pc, lr
308
309/* =============================== PageTable ============================== */
310
311/*
312 * cpu_arm920_switch_mm(pgd)
313 *
314 * Set the translation base pointer to be as described by pgd.
315 *
316 * pgd: new page tables
317 */
318 .align 5
319ENTRY(cpu_arm920_switch_mm)
320 mov ip, #0
321#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
322 mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache
323#else
324@ && 'Clean & Invalidate whole DCache'
325@ && Re-written to use Index Ops.
326@ && Uses registers r1, r3 and ip
327
328 mov r1, #(CACHE_DSEGMENTS - 1) << 5 @ 8 segments
3291: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
3302: mcr p15, 0, r3, c7, c14, 2 @ clean & invalidate D index
331 subs r3, r3, #1 << 26
332 bcs 2b @ entries 63 to 0
333 subs r1, r1, #1 << 5
334 bcs 1b @ segments 7 to 0
335#endif
336 mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache
337 mcr p15, 0, ip, c7, c10, 4 @ drain WB
338 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
339 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
340 mov pc, lr
341
342/*
343 * cpu_arm920_set_pte(ptep, pte)
344 *
345 * Set a PTE and flush it out
346 */
347 .align 5
348ENTRY(cpu_arm920_set_pte)
349 str r1, [r0], #-2048 @ linux version
350
351 eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
352
353 bic r2, r1, #PTE_SMALL_AP_MASK
354 bic r2, r2, #PTE_TYPE_MASK
355 orr r2, r2, #PTE_TYPE_SMALL
356
357 tst r1, #L_PTE_USER @ User?
358 orrne r2, r2, #PTE_SMALL_AP_URO_SRW
359
360 tst r1, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty?
361 orreq r2, r2, #PTE_SMALL_AP_UNO_SRW
362
363 tst r1, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young?
364 movne r2, #0
365
366#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
367 eor r3, r2, #0x0a @ C & small page?
368 tst r3, #0x0b
369 biceq r2, r2, #4
370#endif
371 str r2, [r0] @ hardware version
372 mov r0, r0
373 mcr p15, 0, r0, c7, c10, 1 @ clean D entry
374 mcr p15, 0, r0, c7, c10, 4 @ drain WB
375 mov pc, lr
376
377 __INIT
378
379 .type __arm920_setup, #function
380__arm920_setup:
381 mov r0, #0
382 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
383 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
384 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
385 mrc p15, 0, r0, c1, c0 @ get control register v4
386 ldr r5, arm920_cr1_clear
387 bic r0, r0, r5
388 ldr r5, arm920_cr1_set
389 orr r0, r0, r5
390 mov pc, lr
391 .size __arm920_setup, . - __arm920_setup
392
393 /*
394 * R
395 * .RVI ZFRS BLDP WCAM
396 * ..11 0001 ..11 0101
397 *
398 */
399 .type arm920_cr1_clear, #object
400 .type arm920_cr1_set, #object
401arm920_cr1_clear:
402 .word 0x3f3f
403arm920_cr1_set:
404 .word 0x3135
405
406 __INITDATA
407
408/*
409 * Purpose : Function pointers used to access above functions - all calls
410 * come through these
411 */
412 .type arm920_processor_functions, #object
413arm920_processor_functions:
414 .word v4t_early_abort
415 .word cpu_arm920_proc_init
416 .word cpu_arm920_proc_fin
417 .word cpu_arm920_reset
418 .word cpu_arm920_do_idle
419 .word cpu_arm920_dcache_clean_area
420 .word cpu_arm920_switch_mm
421 .word cpu_arm920_set_pte
422 .size arm920_processor_functions, . - arm920_processor_functions
423
424 .section ".rodata"
425
426 .type cpu_arch_name, #object
427cpu_arch_name:
428 .asciz "armv4t"
429 .size cpu_arch_name, . - cpu_arch_name
430
431 .type cpu_elf_name, #object
432cpu_elf_name:
433 .asciz "v4"
434 .size cpu_elf_name, . - cpu_elf_name
435
436 .type cpu_arm920_name, #object
437cpu_arm920_name:
438 .ascii "ARM920T"
439#ifndef CONFIG_CPU_ICACHE_DISABLE
440 .ascii "i"
441#endif
442#ifndef CONFIG_CPU_DCACHE_DISABLE
443 .ascii "d"
444#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
445 .ascii "(wt)"
446#else
447 .ascii "(wb)"
448#endif
449#endif
450 .ascii "\0"
451 .size cpu_arm920_name, . - cpu_arm920_name
452
453 .align
454
455 .section ".proc.info", #alloc, #execinstr
456
457 .type __arm920_proc_info,#object
458__arm920_proc_info:
459 .long 0x41009200
460 .long 0xff00fff0
461 .long PMD_TYPE_SECT | \
462 PMD_SECT_BUFFERABLE | \
463 PMD_SECT_CACHEABLE | \
464 PMD_BIT4 | \
465 PMD_SECT_AP_WRITE | \
466 PMD_SECT_AP_READ
467 b __arm920_setup
468 .long cpu_arch_name
469 .long cpu_elf_name
470 .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
471 .long cpu_arm920_name
472 .long arm920_processor_functions
473 .long v4wbi_tlb_fns
474 .long v4wb_user_fns
475#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
476 .long arm920_cache_fns
477#else
478 .long v4wt_cache_fns
479#endif
480 .size __arm920_proc_info, . - __arm920_proc_info
diff --git a/arch/arm/mm/proc-arm922.S b/arch/arm/mm/proc-arm922.S
new file mode 100644
index 000000000000..62bc34a139ee
--- /dev/null
+++ b/arch/arm/mm/proc-arm922.S
@@ -0,0 +1,484 @@
1/*
2 * linux/arch/arm/mm/proc-arm922.S: MMU functions for ARM922
3 *
4 * Copyright (C) 1999,2000 ARM Limited
5 * Copyright (C) 2000 Deep Blue Solutions Ltd.
6 * Copyright (C) 2001 Altera Corporation
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 *
23 * These are the low level assembler for performing cache and TLB
24 * functions on the arm922.
25 *
26 * CONFIG_CPU_ARM922_CPU_IDLE -> nohlt
27 */
28#include <linux/linkage.h>
29#include <linux/config.h>
30#include <linux/init.h>
31#include <asm/assembler.h>
32#include <asm/pgtable.h>
33#include <asm/procinfo.h>
34#include <asm/hardware.h>
35#include <asm/page.h>
36#include <asm/ptrace.h>
37#include "proc-macros.S"
38
39/*
40 * The size of one data cache line.
41 */
42#define CACHE_DLINESIZE 32
43
44/*
45 * The number of data cache segments.
46 */
47#define CACHE_DSEGMENTS 4
48
49/*
50 * The number of lines in a cache segment.
51 */
52#define CACHE_DENTRIES 64
53
54/*
55 * This is the size at which it becomes more efficient to
56 * clean the whole cache, rather than using the individual
57 * cache line maintainence instructions. (I think this should
58 * be 32768).
59 */
60#define CACHE_DLIMIT 8192
61
62
63 .text
64/*
65 * cpu_arm922_proc_init()
66 */
67ENTRY(cpu_arm922_proc_init)
68 mov pc, lr
69
70/*
71 * cpu_arm922_proc_fin()
72 */
73ENTRY(cpu_arm922_proc_fin)
74 stmfd sp!, {lr}
75 mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
76 msr cpsr_c, ip
77#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
78 bl arm922_flush_kern_cache_all
79#else
80 bl v4wt_flush_kern_cache_all
81#endif
82 mrc p15, 0, r0, c1, c0, 0 @ ctrl register
83 bic r0, r0, #0x1000 @ ...i............
84 bic r0, r0, #0x000e @ ............wca.
85 mcr p15, 0, r0, c1, c0, 0 @ disable caches
86 ldmfd sp!, {pc}
87
88/*
89 * cpu_arm922_reset(loc)
90 *
91 * Perform a soft reset of the system. Put the CPU into the
92 * same state as it would be if it had been reset, and branch
93 * to what would be the reset vector.
94 *
95 * loc: location to jump to for soft reset
96 */
97 .align 5
98ENTRY(cpu_arm922_reset)
99 mov ip, #0
100 mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
101 mcr p15, 0, ip, c7, c10, 4 @ drain WB
102 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
103 mrc p15, 0, ip, c1, c0, 0 @ ctrl register
104 bic ip, ip, #0x000f @ ............wcam
105 bic ip, ip, #0x1100 @ ...i...s........
106 mcr p15, 0, ip, c1, c0, 0 @ ctrl register
107 mov pc, r0
108
109/*
110 * cpu_arm922_do_idle()
111 */
112 .align 5
113ENTRY(cpu_arm922_do_idle)
114 mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt
115 mov pc, lr
116
117
118#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
119
120/*
121 * flush_user_cache_all()
122 *
123 * Clean and invalidate all cache entries in a particular
124 * address space.
125 */
126ENTRY(arm922_flush_user_cache_all)
127 /* FALLTHROUGH */
128
129/*
130 * flush_kern_cache_all()
131 *
132 * Clean and invalidate the entire cache.
133 */
134ENTRY(arm922_flush_kern_cache_all)
135 mov r2, #VM_EXEC
136 mov ip, #0
137__flush_whole_cache:
138 mov r1, #(CACHE_DSEGMENTS - 1) << 5 @ 8 segments
1391: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
1402: mcr p15, 0, r3, c7, c14, 2 @ clean+invalidate D index
141 subs r3, r3, #1 << 26
142 bcs 2b @ entries 63 to 0
143 subs r1, r1, #1 << 5
144 bcs 1b @ segments 7 to 0
145 tst r2, #VM_EXEC
146 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
147 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
148 mov pc, lr
149
150/*
151 * flush_user_cache_range(start, end, flags)
152 *
153 * Clean and invalidate a range of cache entries in the
154 * specified address range.
155 *
156 * - start - start address (inclusive)
157 * - end - end address (exclusive)
158 * - flags - vm_flags describing address space
159 */
160ENTRY(arm922_flush_user_cache_range)
161 mov ip, #0
162 sub r3, r1, r0 @ calculate total size
163 cmp r3, #CACHE_DLIMIT
164 bhs __flush_whole_cache
165
1661: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
167 tst r2, #VM_EXEC
168 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
169 add r0, r0, #CACHE_DLINESIZE
170 cmp r0, r1
171 blo 1b
172 tst r2, #VM_EXEC
173 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
174 mov pc, lr
175
176/*
177 * coherent_kern_range(start, end)
178 *
179 * Ensure coherency between the Icache and the Dcache in the
180 * region described by start, end. If you have non-snooping
181 * Harvard caches, you need to implement this function.
182 *
183 * - start - virtual start address
184 * - end - virtual end address
185 */
186ENTRY(arm922_coherent_kern_range)
187 /* FALLTHROUGH */
188
189/*
190 * coherent_user_range(start, end)
191 *
192 * Ensure coherency between the Icache and the Dcache in the
193 * region described by start, end. If you have non-snooping
194 * Harvard caches, you need to implement this function.
195 *
196 * - start - virtual start address
197 * - end - virtual end address
198 */
199ENTRY(arm922_coherent_user_range)
200 bic r0, r0, #CACHE_DLINESIZE - 1
2011: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
202 mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry
203 add r0, r0, #CACHE_DLINESIZE
204 cmp r0, r1
205 blo 1b
206 mcr p15, 0, r0, c7, c10, 4 @ drain WB
207 mov pc, lr
208
209/*
210 * flush_kern_dcache_page(void *page)
211 *
212 * Ensure no D cache aliasing occurs, either with itself or
213 * the I cache
214 *
215 * - addr - page aligned address
216 */
217ENTRY(arm922_flush_kern_dcache_page)
218 add r1, r0, #PAGE_SZ
2191: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
220 add r0, r0, #CACHE_DLINESIZE
221 cmp r0, r1
222 blo 1b
223 mov r0, #0
224 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
225 mcr p15, 0, r0, c7, c10, 4 @ drain WB
226 mov pc, lr
227
228/*
229 * dma_inv_range(start, end)
230 *
231 * Invalidate (discard) the specified virtual address range.
232 * May not write back any entries. If 'start' or 'end'
233 * are not cache line aligned, those lines must be written
234 * back.
235 *
236 * - start - virtual start address
237 * - end - virtual end address
238 *
239 * (same as v4wb)
240 */
241ENTRY(arm922_dma_inv_range)
242 tst r0, #CACHE_DLINESIZE - 1
243 bic r0, r0, #CACHE_DLINESIZE - 1
244 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
245 tst r1, #CACHE_DLINESIZE - 1
246 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry
2471: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
248 add r0, r0, #CACHE_DLINESIZE
249 cmp r0, r1
250 blo 1b
251 mcr p15, 0, r0, c7, c10, 4 @ drain WB
252 mov pc, lr
253
254/*
255 * dma_clean_range(start, end)
256 *
257 * Clean the specified virtual address range.
258 *
259 * - start - virtual start address
260 * - end - virtual end address
261 *
262 * (same as v4wb)
263 */
264ENTRY(arm922_dma_clean_range)
265 bic r0, r0, #CACHE_DLINESIZE - 1
2661: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
267 add r0, r0, #CACHE_DLINESIZE
268 cmp r0, r1
269 blo 1b
270 mcr p15, 0, r0, c7, c10, 4 @ drain WB
271 mov pc, lr
272
273/*
274 * dma_flush_range(start, end)
275 *
276 * Clean and invalidate the specified virtual address range.
277 *
278 * - start - virtual start address
279 * - end - virtual end address
280 */
281ENTRY(arm922_dma_flush_range)
282 bic r0, r0, #CACHE_DLINESIZE - 1
2831: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
284 add r0, r0, #CACHE_DLINESIZE
285 cmp r0, r1
286 blo 1b
287 mcr p15, 0, r0, c7, c10, 4 @ drain WB
288 mov pc, lr
289
290ENTRY(arm922_cache_fns)
291 .long arm922_flush_kern_cache_all
292 .long arm922_flush_user_cache_all
293 .long arm922_flush_user_cache_range
294 .long arm922_coherent_kern_range
295 .long arm922_coherent_user_range
296 .long arm922_flush_kern_dcache_page
297 .long arm922_dma_inv_range
298 .long arm922_dma_clean_range
299 .long arm922_dma_flush_range
300
301#endif
302
303
304ENTRY(cpu_arm922_dcache_clean_area)
305#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
3061: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
307 add r0, r0, #CACHE_DLINESIZE
308 subs r1, r1, #CACHE_DLINESIZE
309 bhi 1b
310#endif
311 mov pc, lr
312
313/* =============================== PageTable ============================== */
314
315/*
316 * cpu_arm922_switch_mm(pgd)
317 *
318 * Set the translation base pointer to be as described by pgd.
319 *
320 * pgd: new page tables
321 */
322 .align 5
323ENTRY(cpu_arm922_switch_mm)
324 mov ip, #0
325#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
326 mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache
327#else
328@ && 'Clean & Invalidate whole DCache'
329@ && Re-written to use Index Ops.
330@ && Uses registers r1, r3 and ip
331
332 mov r1, #(CACHE_DSEGMENTS - 1) << 5 @ 4 segments
3331: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
3342: mcr p15, 0, r3, c7, c14, 2 @ clean & invalidate D index
335 subs r3, r3, #1 << 26
336 bcs 2b @ entries 63 to 0
337 subs r1, r1, #1 << 5
338 bcs 1b @ segments 7 to 0
339#endif
340 mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache
341 mcr p15, 0, ip, c7, c10, 4 @ drain WB
342 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
343 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
344 mov pc, lr
345
346/*
347 * cpu_arm922_set_pte(ptep, pte)
348 *
349 * Set a PTE and flush it out
350 */
351 .align 5
352ENTRY(cpu_arm922_set_pte)
353 str r1, [r0], #-2048 @ linux version
354
355 eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
356
357 bic r2, r1, #PTE_SMALL_AP_MASK
358 bic r2, r2, #PTE_TYPE_MASK
359 orr r2, r2, #PTE_TYPE_SMALL
360
361 tst r1, #L_PTE_USER @ User?
362 orrne r2, r2, #PTE_SMALL_AP_URO_SRW
363
364 tst r1, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty?
365 orreq r2, r2, #PTE_SMALL_AP_UNO_SRW
366
367 tst r1, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young?
368 movne r2, #0
369
370#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
371 eor r3, r2, #0x0a @ C & small page?
372 tst r3, #0x0b
373 biceq r2, r2, #4
374#endif
375 str r2, [r0] @ hardware version
376 mov r0, r0
377 mcr p15, 0, r0, c7, c10, 1 @ clean D entry
378 mcr p15, 0, r0, c7, c10, 4 @ drain WB
379 mov pc, lr
380
381 __INIT
382
383 .type __arm922_setup, #function
384__arm922_setup:
385 mov r0, #0
386 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
387 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
388 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
389 mrc p15, 0, r0, c1, c0 @ get control register v4
390 ldr r5, arm922_cr1_clear
391 bic r0, r0, r5
392 ldr r5, arm922_cr1_set
393 orr r0, r0, r5
394 mov pc, lr
395 .size __arm922_setup, . - __arm922_setup
396
397 /*
398 * R
399 * .RVI ZFRS BLDP WCAM
400 * ..11 0001 ..11 0101
401 *
402 */
403 .type arm922_cr1_clear, #object
404 .type arm922_cr1_set, #object
405arm922_cr1_clear:
406 .word 0x3f3f
407arm922_cr1_set:
408 .word 0x3135
409
410 __INITDATA
411
412/*
413 * Purpose : Function pointers used to access above functions - all calls
414 * come through these
415 */
416 .type arm922_processor_functions, #object
417arm922_processor_functions:
418 .word v4t_early_abort
419 .word cpu_arm922_proc_init
420 .word cpu_arm922_proc_fin
421 .word cpu_arm922_reset
422 .word cpu_arm922_do_idle
423 .word cpu_arm922_dcache_clean_area
424 .word cpu_arm922_switch_mm
425 .word cpu_arm922_set_pte
426 .size arm922_processor_functions, . - arm922_processor_functions
427
428 .section ".rodata"
429
430 .type cpu_arch_name, #object
431cpu_arch_name:
432 .asciz "armv4t"
433 .size cpu_arch_name, . - cpu_arch_name
434
435 .type cpu_elf_name, #object
436cpu_elf_name:
437 .asciz "v4"
438 .size cpu_elf_name, . - cpu_elf_name
439
440 .type cpu_arm922_name, #object
441cpu_arm922_name:
442 .ascii "ARM922T"
443#ifndef CONFIG_CPU_ICACHE_DISABLE
444 .ascii "i"
445#endif
446#ifndef CONFIG_CPU_DCACHE_DISABLE
447 .ascii "d"
448#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
449 .ascii "(wt)"
450#else
451 .ascii "(wb)"
452#endif
453#endif
454 .ascii "\0"
455 .size cpu_arm922_name, . - cpu_arm922_name
456
457 .align
458
459 .section ".proc.info", #alloc, #execinstr
460
461 .type __arm922_proc_info,#object
462__arm922_proc_info:
463 .long 0x41009220
464 .long 0xff00fff0
465 .long PMD_TYPE_SECT | \
466 PMD_SECT_BUFFERABLE | \
467 PMD_SECT_CACHEABLE | \
468 PMD_BIT4 | \
469 PMD_SECT_AP_WRITE | \
470 PMD_SECT_AP_READ
471 b __arm922_setup
472 .long cpu_arch_name
473 .long cpu_elf_name
474 .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
475 .long cpu_arm922_name
476 .long arm922_processor_functions
477 .long v4wbi_tlb_fns
478 .long v4wb_user_fns
479#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
480 .long arm922_cache_fns
481#else
482 .long v4wt_cache_fns
483#endif
484 .size __arm922_proc_info, . - __arm922_proc_info
diff --git a/arch/arm/mm/proc-arm925.S b/arch/arm/mm/proc-arm925.S
new file mode 100644
index 000000000000..ee49aa2ca781
--- /dev/null
+++ b/arch/arm/mm/proc-arm925.S
@@ -0,0 +1,562 @@
1/*
2 * linux/arch/arm/mm/arm925.S: MMU functions for ARM925
3 *
4 * Copyright (C) 1999,2000 ARM Limited
5 * Copyright (C) 2000 Deep Blue Solutions Ltd.
6 * Copyright (C) 2002 RidgeRun, Inc.
7 * Copyright (C) 2002-2003 MontaVista Software, Inc.
8 *
9 * Update for Linux-2.6 and cache flush improvements
10 * Copyright (C) 2004 Nokia Corporation by Tony Lindgren <tony@atomide.com>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 *
26 *
27 * These are the low level assembler for performing cache and TLB
28 * functions on the arm925.
29 *
30 * CONFIG_CPU_ARM925_CPU_IDLE -> nohlt
31 *
32 * Some additional notes based on deciphering the TI TRM on OMAP-5910:
33 *
34 * NOTE1: The TI925T Configuration Register bit "D-cache clean and flush
35 * entry mode" must be 0 to flush the entries in both segments
36 * at once. This is the default value. See TRM 2-20 and 2-24 for
37 * more information.
38 *
39 * NOTE2: Default is the "D-cache clean and flush entry mode". It looks
40 * like the "Transparent mode" must be on for partial cache flushes
41 * to work in this mode. This mode only works with 16-bit external
42 * memory. See TRM 2-24 for more information.
43 *
44 * NOTE3: Write-back cache flushing seems to be flakey with devices using
45 * direct memory access, such as USB OHCI. The workaround is to use
46 * write-through cache with CONFIG_CPU_DCACHE_WRITETHROUGH (this is
47 * the default for OMAP-1510).
48 */
49
50#include <linux/linkage.h>
51#include <linux/config.h>
52#include <linux/init.h>
53#include <asm/assembler.h>
54#include <asm/pgtable.h>
55#include <asm/procinfo.h>
56#include <asm/hardware.h>
57#include <asm/page.h>
58#include <asm/ptrace.h>
59#include "proc-macros.S"
60
61/*
62 * The size of one data cache line.
63 */
64#define CACHE_DLINESIZE 16
65
66/*
67 * The number of data cache segments.
68 */
69#define CACHE_DSEGMENTS 2
70
71/*
72 * The number of lines in a cache segment.
73 */
74#define CACHE_DENTRIES 256
75
76/*
77 * This is the size at which it becomes more efficient to
78 * clean the whole cache, rather than using the individual
79 * cache line maintainence instructions.
80 */
81#define CACHE_DLIMIT 8192
82
83 .text
84/*
85 * cpu_arm925_proc_init()
86 */
87ENTRY(cpu_arm925_proc_init)
88 mov pc, lr
89
90/*
91 * cpu_arm925_proc_fin()
92 */
93ENTRY(cpu_arm925_proc_fin)
94 stmfd sp!, {lr}
95 mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
96 msr cpsr_c, ip
97 bl arm925_flush_kern_cache_all
98 mrc p15, 0, r0, c1, c0, 0 @ ctrl register
99 bic r0, r0, #0x1000 @ ...i............
100 bic r0, r0, #0x000e @ ............wca.
101 mcr p15, 0, r0, c1, c0, 0 @ disable caches
102 ldmfd sp!, {pc}
103
104/*
105 * cpu_arm925_reset(loc)
106 *
107 * Perform a soft reset of the system. Put the CPU into the
108 * same state as it would be if it had been reset, and branch
109 * to what would be the reset vector.
110 *
111 * loc: location to jump to for soft reset
112 */
113 .align 5
114ENTRY(cpu_arm925_reset)
115 /* Send software reset to MPU and DSP */
116 mov ip, #0xff000000
117 orr ip, ip, #0x00fe0000
118 orr ip, ip, #0x0000ce00
119 mov r4, #1
120 strh r4, [ip, #0x10]
121
122 mov ip, #0
123 mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
124 mcr p15, 0, ip, c7, c10, 4 @ drain WB
125 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
126 mrc p15, 0, ip, c1, c0, 0 @ ctrl register
127 bic ip, ip, #0x000f @ ............wcam
128 bic ip, ip, #0x1100 @ ...i...s........
129 mcr p15, 0, ip, c1, c0, 0 @ ctrl register
130 mov pc, r0
131
132/*
133 * cpu_arm925_do_idle()
134 *
135 * Called with IRQs disabled
136 */
137 .align 10
138ENTRY(cpu_arm925_do_idle)
139 mov r0, #0
140 mrc p15, 0, r1, c1, c0, 0 @ Read control register
141 mcr p15, 0, r0, c7, c10, 4 @ Drain write buffer
142 bic r2, r1, #1 << 12
143 mcr p15, 0, r2, c1, c0, 0 @ Disable I cache
144 mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt
145 mcr p15, 0, r1, c1, c0, 0 @ Restore ICache enable
146 mov pc, lr
147
148/*
149 * flush_user_cache_all()
150 *
151 * Clean and invalidate all cache entries in a particular
152 * address space.
153 */
154ENTRY(arm925_flush_user_cache_all)
155 /* FALLTHROUGH */
156
157/*
158 * flush_kern_cache_all()
159 *
160 * Clean and invalidate the entire cache.
161 */
162ENTRY(arm925_flush_kern_cache_all)
163 mov r2, #VM_EXEC
164 mov ip, #0
165__flush_whole_cache:
166#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
167 mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache
168#else
169 /* Flush entries in both segments at once, see NOTE1 above */
170 mov r3, #(CACHE_DENTRIES - 1) << 4 @ 256 entries in segment
1712: mcr p15, 0, r3, c7, c14, 2 @ clean+invalidate D index
172 subs r3, r3, #1 << 4
173 bcs 2b @ entries 255 to 0
174#endif
175 tst r2, #VM_EXEC
176 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
177 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
178 mov pc, lr
179
180/*
181 * flush_user_cache_range(start, end, flags)
182 *
183 * Clean and invalidate a range of cache entries in the
184 * specified address range.
185 *
186 * - start - start address (inclusive)
187 * - end - end address (exclusive)
188 * - flags - vm_flags describing address space
189 */
190ENTRY(arm925_flush_user_cache_range)
191 mov ip, #0
192 sub r3, r1, r0 @ calculate total size
193 cmp r3, #CACHE_DLIMIT
194 bgt __flush_whole_cache
1951: tst r2, #VM_EXEC
196#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
197 mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
198 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
199 add r0, r0, #CACHE_DLINESIZE
200 mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
201 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
202 add r0, r0, #CACHE_DLINESIZE
203#else
204 mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry
205 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
206 add r0, r0, #CACHE_DLINESIZE
207 mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry
208 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
209 add r0, r0, #CACHE_DLINESIZE
210#endif
211 cmp r0, r1
212 blo 1b
213 tst r2, #VM_EXEC
214 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
215 mov pc, lr
216
217/*
218 * coherent_kern_range(start, end)
219 *
220 * Ensure coherency between the Icache and the Dcache in the
221 * region described by start, end. If you have non-snooping
222 * Harvard caches, you need to implement this function.
223 *
224 * - start - virtual start address
225 * - end - virtual end address
226 */
227ENTRY(arm925_coherent_kern_range)
228 /* FALLTHROUGH */
229
230/*
231 * coherent_user_range(start, end)
232 *
233 * Ensure coherency between the Icache and the Dcache in the
234 * region described by start, end. If you have non-snooping
235 * Harvard caches, you need to implement this function.
236 *
237 * - start - virtual start address
238 * - end - virtual end address
239 */
240ENTRY(arm925_coherent_user_range)
241 bic r0, r0, #CACHE_DLINESIZE - 1
2421: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
243 mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry
244 add r0, r0, #CACHE_DLINESIZE
245 cmp r0, r1
246 blo 1b
247 mcr p15, 0, r0, c7, c10, 4 @ drain WB
248 mov pc, lr
249
250/*
251 * flush_kern_dcache_page(void *page)
252 *
253 * Ensure no D cache aliasing occurs, either with itself or
254 * the I cache
255 *
256 * - addr - page aligned address
257 */
258ENTRY(arm925_flush_kern_dcache_page)
259 add r1, r0, #PAGE_SZ
2601: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
261 add r0, r0, #CACHE_DLINESIZE
262 cmp r0, r1
263 blo 1b
264 mov r0, #0
265 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
266 mcr p15, 0, r0, c7, c10, 4 @ drain WB
267 mov pc, lr
268
269/*
270 * dma_inv_range(start, end)
271 *
272 * Invalidate (discard) the specified virtual address range.
273 * May not write back any entries. If 'start' or 'end'
274 * are not cache line aligned, those lines must be written
275 * back.
276 *
277 * - start - virtual start address
278 * - end - virtual end address
279 *
280 * (same as v4wb)
281 */
282ENTRY(arm925_dma_inv_range)
283#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
284 tst r0, #CACHE_DLINESIZE - 1
285 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
286 tst r1, #CACHE_DLINESIZE - 1
287 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry
288#endif
289 bic r0, r0, #CACHE_DLINESIZE - 1
2901: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
291 add r0, r0, #CACHE_DLINESIZE
292 cmp r0, r1
293 blo 1b
294 mcr p15, 0, r0, c7, c10, 4 @ drain WB
295 mov pc, lr
296
297/*
298 * dma_clean_range(start, end)
299 *
300 * Clean the specified virtual address range.
301 *
302 * - start - virtual start address
303 * - end - virtual end address
304 *
305 * (same as v4wb)
306 */
307ENTRY(arm925_dma_clean_range)
308#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
309 bic r0, r0, #CACHE_DLINESIZE - 1
3101: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
311 add r0, r0, #CACHE_DLINESIZE
312 cmp r0, r1
313 blo 1b
314#endif
315 mcr p15, 0, r0, c7, c10, 4 @ drain WB
316 mov pc, lr
317
318/*
319 * dma_flush_range(start, end)
320 *
321 * Clean and invalidate the specified virtual address range.
322 *
323 * - start - virtual start address
324 * - end - virtual end address
325 */
326ENTRY(arm925_dma_flush_range)
327 bic r0, r0, #CACHE_DLINESIZE - 1
3281:
329#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
330 mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
331#else
332 mcr p15, 0, r0, c7, c10, 1 @ clean D entry
333#endif
334 add r0, r0, #CACHE_DLINESIZE
335 cmp r0, r1
336 blo 1b
337 mcr p15, 0, r0, c7, c10, 4 @ drain WB
338 mov pc, lr
339
340ENTRY(arm925_cache_fns)
341 .long arm925_flush_kern_cache_all
342 .long arm925_flush_user_cache_all
343 .long arm925_flush_user_cache_range
344 .long arm925_coherent_kern_range
345 .long arm925_coherent_user_range
346 .long arm925_flush_kern_dcache_page
347 .long arm925_dma_inv_range
348 .long arm925_dma_clean_range
349 .long arm925_dma_flush_range
350
351ENTRY(cpu_arm925_dcache_clean_area)
352#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
3531: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
354 add r0, r0, #CACHE_DLINESIZE
355 subs r1, r1, #CACHE_DLINESIZE
356 bhi 1b
357#endif
358 mcr p15, 0, r0, c7, c10, 4 @ drain WB
359 mov pc, lr
360
361/* =============================== PageTable ============================== */
362
363/*
364 * cpu_arm925_switch_mm(pgd)
365 *
366 * Set the translation base pointer to be as described by pgd.
367 *
368 * pgd: new page tables
369 */
370 .align 5
371ENTRY(cpu_arm925_switch_mm)
372 mov ip, #0
373#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
374 mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache
375#else
376 /* Flush entries in bothe segments at once, see NOTE1 above */
377 mov r3, #(CACHE_DENTRIES - 1) << 4 @ 256 entries in segment
3782: mcr p15, 0, r3, c7, c14, 2 @ clean & invalidate D index
379 subs r3, r3, #1 << 4
380 bcs 2b @ entries 255 to 0
381#endif
382 mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache
383 mcr p15, 0, ip, c7, c10, 4 @ drain WB
384 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
385 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
386 mov pc, lr
387
388/*
389 * cpu_arm925_set_pte(ptep, pte)
390 *
391 * Set a PTE and flush it out
392 */
393 .align 5
394ENTRY(cpu_arm925_set_pte)
395 str r1, [r0], #-2048 @ linux version
396
397 eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
398
399 bic r2, r1, #PTE_SMALL_AP_MASK
400 bic r2, r2, #PTE_TYPE_MASK
401 orr r2, r2, #PTE_TYPE_SMALL
402
403 tst r1, #L_PTE_USER @ User?
404 orrne r2, r2, #PTE_SMALL_AP_URO_SRW
405
406 tst r1, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty?
407 orreq r2, r2, #PTE_SMALL_AP_UNO_SRW
408
409 tst r1, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young?
410 movne r2, #0
411
412#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
413 eor r3, r2, #0x0a @ C & small page?
414 tst r3, #0x0b
415 biceq r2, r2, #4
416#endif
417 str r2, [r0] @ hardware version
418 mov r0, r0
419#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
420 mcr p15, 0, r0, c7, c10, 1 @ clean D entry
421#endif
422 mcr p15, 0, r0, c7, c10, 4 @ drain WB
423 mov pc, lr
424
425 __INIT
426
427 .type __arm925_setup, #function
428__arm925_setup:
429 mov r0, #0
430#if defined(CONFIG_CPU_ICACHE_STREAMING_DISABLE)
431 orr r0,r0,#1 << 7
432#endif
433
434 /* Transparent on, D-cache clean & flush mode. See NOTE2 above */
435 orr r0,r0,#1 << 1 @ transparent mode on
436 mcr p15, 0, r0, c15, c1, 0 @ write TI config register
437
438 mov r0, #0
439 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
440 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
441 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
442
443#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
444 mov r0, #4 @ disable write-back on caches explicitly
445 mcr p15, 7, r0, c15, c0, 0
446#endif
447
448 mrc p15, 0, r0, c1, c0 @ get control register v4
449 ldr r5, arm925_cr1_clear
450 bic r0, r0, r5
451 ldr r5, arm925_cr1_set
452 orr r0, r0, r5
453#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN
454 orr r0, r0, #0x4000 @ .1.. .... .... ....
455#endif
456 mov pc, lr
457 .size __arm925_setup, . - __arm925_setup
458
459 /*
460 * R
461 * .RVI ZFRS BLDP WCAM
462 * .011 0001 ..11 1101
463 *
464 */
465 .type arm925_cr1_clear, #object
466 .type arm925_cr1_set, #object
467arm925_cr1_clear:
468 .word 0x7f3f
469arm925_cr1_set:
470 .word 0x313d
471
472 __INITDATA
473
474/*
475 * Purpose : Function pointers used to access above functions - all calls
476 * come through these
477 */
478 .type arm925_processor_functions, #object
479arm925_processor_functions:
480 .word v4t_early_abort
481 .word cpu_arm925_proc_init
482 .word cpu_arm925_proc_fin
483 .word cpu_arm925_reset
484 .word cpu_arm925_do_idle
485 .word cpu_arm925_dcache_clean_area
486 .word cpu_arm925_switch_mm
487 .word cpu_arm925_set_pte
488 .size arm925_processor_functions, . - arm925_processor_functions
489
490 .section ".rodata"
491
492 .type cpu_arch_name, #object
493cpu_arch_name:
494 .asciz "armv4t"
495 .size cpu_arch_name, . - cpu_arch_name
496
497 .type cpu_elf_name, #object
498cpu_elf_name:
499 .asciz "v4"
500 .size cpu_elf_name, . - cpu_elf_name
501
502 .type cpu_arm925_name, #object
503cpu_arm925_name:
504 .ascii "ARM925T"
505#ifndef CONFIG_CPU_ICACHE_DISABLE
506 .ascii "i"
507#endif
508#ifndef CONFIG_CPU_DCACHE_DISABLE
509 .ascii "d"
510#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
511 .ascii "(wt)"
512#else
513 .ascii "(wb)"
514#endif
515#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN
516 .ascii "RR"
517#endif
518#endif
519 .ascii "\0"
520 .size cpu_arm925_name, . - cpu_arm925_name
521
522 .align
523
524 .section ".proc.info", #alloc, #execinstr
525
526 .type __arm925_proc_info,#object
527__arm925_proc_info:
528 .long 0x54029250
529 .long 0xfffffff0
530 .long PMD_TYPE_SECT | \
531 PMD_BIT4 | \
532 PMD_SECT_AP_WRITE | \
533 PMD_SECT_AP_READ
534 b __arm925_setup
535 .long cpu_arch_name
536 .long cpu_elf_name
537 .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
538 .long cpu_arm925_name
539 .long arm925_processor_functions
540 .long v4wbi_tlb_fns
541 .long v4wb_user_fns
542 .long arm925_cache_fns
543 .size __arm925_proc_info, . - __arm925_proc_info
544
545 .type __arm915_proc_info,#object
546__arm915_proc_info:
547 .long 0x54029150
548 .long 0xfffffff0
549 .long PMD_TYPE_SECT | \
550 PMD_BIT4 | \
551 PMD_SECT_AP_WRITE | \
552 PMD_SECT_AP_READ
553 b __arm925_setup
554 .long cpu_arch_name
555 .long cpu_elf_name
556 .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
557 .long cpu_arm925_name
558 .long arm925_processor_functions
559 .long v4wbi_tlb_fns
560 .long v4wb_user_fns
561 .long arm925_cache_fns
562 .size __arm925_proc_info, . - __arm925_proc_info
diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S
new file mode 100644
index 000000000000..bb95cc9fed03
--- /dev/null
+++ b/arch/arm/mm/proc-arm926.S
@@ -0,0 +1,495 @@
1/*
2 * linux/arch/arm/mm/proc-arm926.S: MMU functions for ARM926EJ-S
3 *
4 * Copyright (C) 1999-2001 ARM Limited
5 * Copyright (C) 2000 Deep Blue Solutions Ltd.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 *
22 * These are the low level assembler for performing cache and TLB
23 * functions on the arm926.
24 *
25 * CONFIG_CPU_ARM926_CPU_IDLE -> nohlt
26 */
27#include <linux/linkage.h>
28#include <linux/config.h>
29#include <linux/init.h>
30#include <asm/assembler.h>
31#include <asm/pgtable.h>
32#include <asm/procinfo.h>
33#include <asm/hardware.h>
34#include <asm/page.h>
35#include <asm/ptrace.h>
36#include "proc-macros.S"
37
38/*
39 * This is the maximum size of an area which will be invalidated
40 * using the single invalidate entry instructions. Anything larger
41 * than this, and we go for the whole cache.
42 *
43 * This value should be chosen such that we choose the cheapest
44 * alternative.
45 */
46#define CACHE_DLIMIT 16384
47
48/*
49 * the cache line size of the I and D cache
50 */
51#define CACHE_DLINESIZE 32
52
53 .text
54/*
55 * cpu_arm926_proc_init()
56 */
57ENTRY(cpu_arm926_proc_init)
58 mov pc, lr
59
60/*
61 * cpu_arm926_proc_fin()
62 */
63ENTRY(cpu_arm926_proc_fin)
64 stmfd sp!, {lr}
65 mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
66 msr cpsr_c, ip
67 bl arm926_flush_kern_cache_all
68 mrc p15, 0, r0, c1, c0, 0 @ ctrl register
69 bic r0, r0, #0x1000 @ ...i............
70 bic r0, r0, #0x000e @ ............wca.
71 mcr p15, 0, r0, c1, c0, 0 @ disable caches
72 ldmfd sp!, {pc}
73
74/*
75 * cpu_arm926_reset(loc)
76 *
77 * Perform a soft reset of the system. Put the CPU into the
78 * same state as it would be if it had been reset, and branch
79 * to what would be the reset vector.
80 *
81 * loc: location to jump to for soft reset
82 */
83 .align 5
84ENTRY(cpu_arm926_reset)
85 mov ip, #0
86 mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
87 mcr p15, 0, ip, c7, c10, 4 @ drain WB
88 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
89 mrc p15, 0, ip, c1, c0, 0 @ ctrl register
90 bic ip, ip, #0x000f @ ............wcam
91 bic ip, ip, #0x1100 @ ...i...s........
92 mcr p15, 0, ip, c1, c0, 0 @ ctrl register
93 mov pc, r0
94
95/*
96 * cpu_arm926_do_idle()
97 *
98 * Called with IRQs disabled
99 */
100 .align 10
101ENTRY(cpu_arm926_do_idle)
102 mov r0, #0
103 mrc p15, 0, r1, c1, c0, 0 @ Read control register
104 mcr p15, 0, r0, c7, c10, 4 @ Drain write buffer
105 bic r2, r1, #1 << 12
106 mcr p15, 0, r2, c1, c0, 0 @ Disable I cache
107 mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt
108 mcr p15, 0, r1, c1, c0, 0 @ Restore ICache enable
109 mov pc, lr
110
111/*
112 * flush_user_cache_all()
113 *
114 * Clean and invalidate all cache entries in a particular
115 * address space.
116 */
117ENTRY(arm926_flush_user_cache_all)
118 /* FALLTHROUGH */
119
120/*
121 * flush_kern_cache_all()
122 *
123 * Clean and invalidate the entire cache.
124 */
125ENTRY(arm926_flush_kern_cache_all)
126 mov r2, #VM_EXEC
127 mov ip, #0
128__flush_whole_cache:
129#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
130 mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache
131#else
1321: mrc p15, 0, r15, c7, c14, 3 @ test,clean,invalidate
133 bne 1b
134#endif
135 tst r2, #VM_EXEC
136 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
137 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
138 mov pc, lr
139
140/*
141 * flush_user_cache_range(start, end, flags)
142 *
143 * Clean and invalidate a range of cache entries in the
144 * specified address range.
145 *
146 * - start - start address (inclusive)
147 * - end - end address (exclusive)
148 * - flags - vm_flags describing address space
149 */
150ENTRY(arm926_flush_user_cache_range)
151 mov ip, #0
152 sub r3, r1, r0 @ calculate total size
153 cmp r3, #CACHE_DLIMIT
154 bgt __flush_whole_cache
1551: tst r2, #VM_EXEC
156#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
157 mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
158 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
159 add r0, r0, #CACHE_DLINESIZE
160 mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
161 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
162 add r0, r0, #CACHE_DLINESIZE
163#else
164 mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry
165 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
166 add r0, r0, #CACHE_DLINESIZE
167 mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry
168 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
169 add r0, r0, #CACHE_DLINESIZE
170#endif
171 cmp r0, r1
172 blo 1b
173 tst r2, #VM_EXEC
174 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
175 mov pc, lr
176
177/*
178 * coherent_kern_range(start, end)
179 *
180 * Ensure coherency between the Icache and the Dcache in the
181 * region described by start, end. If you have non-snooping
182 * Harvard caches, you need to implement this function.
183 *
184 * - start - virtual start address
185 * - end - virtual end address
186 */
187ENTRY(arm926_coherent_kern_range)
188 /* FALLTHROUGH */
189
190/*
191 * coherent_user_range(start, end)
192 *
193 * Ensure coherency between the Icache and the Dcache in the
194 * region described by start, end. If you have non-snooping
195 * Harvard caches, you need to implement this function.
196 *
197 * - start - virtual start address
198 * - end - virtual end address
199 */
200ENTRY(arm926_coherent_user_range)
201 bic r0, r0, #CACHE_DLINESIZE - 1
2021: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
203 mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry
204 add r0, r0, #CACHE_DLINESIZE
205 cmp r0, r1
206 blo 1b
207 mcr p15, 0, r0, c7, c10, 4 @ drain WB
208 mov pc, lr
209
210/*
211 * flush_kern_dcache_page(void *page)
212 *
213 * Ensure no D cache aliasing occurs, either with itself or
214 * the I cache
215 *
216 * - addr - page aligned address
217 */
218ENTRY(arm926_flush_kern_dcache_page)
219 add r1, r0, #PAGE_SZ
2201: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
221 add r0, r0, #CACHE_DLINESIZE
222 cmp r0, r1
223 blo 1b
224 mov r0, #0
225 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
226 mcr p15, 0, r0, c7, c10, 4 @ drain WB
227 mov pc, lr
228
229/*
230 * dma_inv_range(start, end)
231 *
232 * Invalidate (discard) the specified virtual address range.
233 * May not write back any entries. If 'start' or 'end'
234 * are not cache line aligned, those lines must be written
235 * back.
236 *
237 * - start - virtual start address
238 * - end - virtual end address
239 *
240 * (same as v4wb)
241 */
242ENTRY(arm926_dma_inv_range)
243#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
244 tst r0, #CACHE_DLINESIZE - 1
245 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
246 tst r1, #CACHE_DLINESIZE - 1
247 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry
248#endif
249 bic r0, r0, #CACHE_DLINESIZE - 1
2501: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
251 add r0, r0, #CACHE_DLINESIZE
252 cmp r0, r1
253 blo 1b
254 mcr p15, 0, r0, c7, c10, 4 @ drain WB
255 mov pc, lr
256
257/*
258 * dma_clean_range(start, end)
259 *
260 * Clean the specified virtual address range.
261 *
262 * - start - virtual start address
263 * - end - virtual end address
264 *
265 * (same as v4wb)
266 */
267ENTRY(arm926_dma_clean_range)
268#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
269 bic r0, r0, #CACHE_DLINESIZE - 1
2701: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
271 add r0, r0, #CACHE_DLINESIZE
272 cmp r0, r1
273 blo 1b
274#endif
275 mcr p15, 0, r0, c7, c10, 4 @ drain WB
276 mov pc, lr
277
278/*
279 * dma_flush_range(start, end)
280 *
281 * Clean and invalidate the specified virtual address range.
282 *
283 * - start - virtual start address
284 * - end - virtual end address
285 */
286ENTRY(arm926_dma_flush_range)
287 bic r0, r0, #CACHE_DLINESIZE - 1
2881:
289#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
290 mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
291#else
292 mcr p15, 0, r0, c7, c10, 1 @ clean D entry
293#endif
294 add r0, r0, #CACHE_DLINESIZE
295 cmp r0, r1
296 blo 1b
297 mcr p15, 0, r0, c7, c10, 4 @ drain WB
298 mov pc, lr
299
300ENTRY(arm926_cache_fns)
301 .long arm926_flush_kern_cache_all
302 .long arm926_flush_user_cache_all
303 .long arm926_flush_user_cache_range
304 .long arm926_coherent_kern_range
305 .long arm926_coherent_user_range
306 .long arm926_flush_kern_dcache_page
307 .long arm926_dma_inv_range
308 .long arm926_dma_clean_range
309 .long arm926_dma_flush_range
310
311ENTRY(cpu_arm926_dcache_clean_area)
312#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
3131: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
314 add r0, r0, #CACHE_DLINESIZE
315 subs r1, r1, #CACHE_DLINESIZE
316 bhi 1b
317#endif
318 mcr p15, 0, r0, c7, c10, 4 @ drain WB
319 mov pc, lr
320
321/* =============================== PageTable ============================== */
322
323/*
324 * cpu_arm926_switch_mm(pgd)
325 *
326 * Set the translation base pointer to be as described by pgd.
327 *
328 * pgd: new page tables
329 */
330 .align 5
331ENTRY(cpu_arm926_switch_mm)
332 mov ip, #0
333#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
334 mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache
335#else
336@ && 'Clean & Invalidate whole DCache'
3371: mrc p15, 0, r15, c7, c14, 3 @ test,clean,invalidate
338 bne 1b
339#endif
340 mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache
341 mcr p15, 0, ip, c7, c10, 4 @ drain WB
342 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
343 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
344 mov pc, lr
345
346/*
347 * cpu_arm926_set_pte(ptep, pte)
348 *
349 * Set a PTE and flush it out
350 */
351 .align 5
352ENTRY(cpu_arm926_set_pte)
353 str r1, [r0], #-2048 @ linux version
354
355 eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
356
357 bic r2, r1, #PTE_SMALL_AP_MASK
358 bic r2, r2, #PTE_TYPE_MASK
359 orr r2, r2, #PTE_TYPE_SMALL
360
361 tst r1, #L_PTE_USER @ User?
362 orrne r2, r2, #PTE_SMALL_AP_URO_SRW
363
364 tst r1, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty?
365 orreq r2, r2, #PTE_SMALL_AP_UNO_SRW
366
367 tst r1, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young?
368 movne r2, #0
369
370#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
371 eor r3, r2, #0x0a @ C & small page?
372 tst r3, #0x0b
373 biceq r2, r2, #4
374#endif
375 str r2, [r0] @ hardware version
376 mov r0, r0
377#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
378 mcr p15, 0, r0, c7, c10, 1 @ clean D entry
379#endif
380 mcr p15, 0, r0, c7, c10, 4 @ drain WB
381 mov pc, lr
382
383 __INIT
384
385 .type __arm926_setup, #function
386__arm926_setup:
387 mov r0, #0
388 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
389 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
390 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
391
392
393#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
394 mov r0, #4 @ disable write-back on caches explicitly
395 mcr p15, 7, r0, c15, c0, 0
396#endif
397
398 mrc p15, 0, r0, c1, c0 @ get control register v4
399 ldr r5, arm926_cr1_clear
400 bic r0, r0, r5
401 ldr r5, arm926_cr1_set
402 orr r0, r0, r5
403#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN
404 orr r0, r0, #0x4000 @ .1.. .... .... ....
405#endif
406 mov pc, lr
407 .size __arm926_setup, . - __arm926_setup
408
409 /*
410 * R
411 * .RVI ZFRS BLDP WCAM
412 * .011 0001 ..11 0101
413 *
414 */
415 .type arm926_cr1_clear, #object
416 .type arm926_cr1_set, #object
417arm926_cr1_clear:
418 .word 0x7f3f
419arm926_cr1_set:
420 .word 0x3135
421
422 __INITDATA
423
424/*
425 * Purpose : Function pointers used to access above functions - all calls
426 * come through these
427 */
428 .type arm926_processor_functions, #object
429arm926_processor_functions:
430 .word v5tj_early_abort
431 .word cpu_arm926_proc_init
432 .word cpu_arm926_proc_fin
433 .word cpu_arm926_reset
434 .word cpu_arm926_do_idle
435 .word cpu_arm926_dcache_clean_area
436 .word cpu_arm926_switch_mm
437 .word cpu_arm926_set_pte
438 .size arm926_processor_functions, . - arm926_processor_functions
439
440 .section ".rodata"
441
442 .type cpu_arch_name, #object
443cpu_arch_name:
444 .asciz "armv5tej"
445 .size cpu_arch_name, . - cpu_arch_name
446
447 .type cpu_elf_name, #object
448cpu_elf_name:
449 .asciz "v5"
450 .size cpu_elf_name, . - cpu_elf_name
451
452 .type cpu_arm926_name, #object
453cpu_arm926_name:
454 .ascii "ARM926EJ-S"
455#ifndef CONFIG_CPU_ICACHE_DISABLE
456 .ascii "i"
457#endif
458#ifndef CONFIG_CPU_DCACHE_DISABLE
459 .ascii "d"
460#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
461 .ascii "(wt)"
462#else
463 .ascii "(wb)"
464#endif
465#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN
466 .ascii "RR"
467#endif
468#endif
469 .ascii "\0"
470 .size cpu_arm926_name, . - cpu_arm926_name
471
472 .align
473
474 .section ".proc.info", #alloc, #execinstr
475
476 .type __arm926_proc_info,#object
477__arm926_proc_info:
478 .long 0x41069260 @ ARM926EJ-S (v5TEJ)
479 .long 0xff0ffff0
480 .long PMD_TYPE_SECT | \
481 PMD_SECT_BUFFERABLE | \
482 PMD_SECT_CACHEABLE | \
483 PMD_BIT4 | \
484 PMD_SECT_AP_WRITE | \
485 PMD_SECT_AP_READ
486 b __arm926_setup
487 .long cpu_arch_name
488 .long cpu_elf_name
489 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_JAVA
490 .long cpu_arm926_name
491 .long arm926_processor_functions
492 .long v4wbi_tlb_fns
493 .long v4wb_user_fns
494 .long arm926_cache_fns
495 .size __arm926_proc_info, . - __arm926_proc_info
diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S
new file mode 100644
index 000000000000..9137fe563599
--- /dev/null
+++ b/arch/arm/mm/proc-macros.S
@@ -0,0 +1,51 @@
1/*
2 * We need constants.h for:
3 * VMA_VM_MM
4 * VMA_VM_FLAGS
5 * VM_EXEC
6 */
7#include <asm/constants.h>
8#include <asm/thread_info.h>
9
10/*
11 * vma_vm_mm - get mm pointer from vma pointer (vma->vm_mm)
12 */
13 .macro vma_vm_mm, rd, rn
14 ldr \rd, [\rn, #VMA_VM_MM]
15 .endm
16
17/*
18 * vma_vm_flags - get vma->vm_flags
19 */
20 .macro vma_vm_flags, rd, rn
21 ldr \rd, [\rn, #VMA_VM_FLAGS]
22 .endm
23
24 .macro tsk_mm, rd, rn
25 ldr \rd, [\rn, #TI_TASK]
26 ldr \rd, [\rd, #TSK_ACTIVE_MM]
27 .endm
28
29/*
30 * act_mm - get current->active_mm
31 */
32 .macro act_mm, rd
33 bic \rd, sp, #8128
34 bic \rd, \rd, #63
35 ldr \rd, [\rd, #TI_TASK]
36 ldr \rd, [\rd, #TSK_ACTIVE_MM]
37 .endm
38
39/*
40 * mmid - get context id from mm pointer (mm->context.id)
41 */
42 .macro mmid, rd, rn
43 ldr \rd, [\rn, #MM_CONTEXT_ID]
44 .endm
45
46/*
47 * mask_asid - mask the ASID from the context ID
48 */
49 .macro asid, rd, rn
50 and \rd, \rn, #255
51 .endm
diff --git a/arch/arm/mm/proc-sa110.S b/arch/arm/mm/proc-sa110.S
new file mode 100644
index 000000000000..360cae905692
--- /dev/null
+++ b/arch/arm/mm/proc-sa110.S
@@ -0,0 +1,272 @@
1/*
2 * linux/arch/arm/mm/proc-sa110.S
3 *
4 * Copyright (C) 1997-2002 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * MMU functions for SA110
11 *
12 * These are the low level assembler for performing cache and TLB
13 * functions on the StrongARM-110.
14 */
15#include <linux/linkage.h>
16#include <linux/init.h>
17#include <asm/assembler.h>
18#include <asm/constants.h>
19#include <asm/procinfo.h>
20#include <asm/hardware.h>
21#include <asm/pgtable.h>
22#include <asm/ptrace.h>
23
24/*
25 * the cache line size of the I and D cache
26 */
27#define DCACHELINESIZE 32
28#define FLUSH_OFFSET 32768
29
30 .macro flush_110_dcache rd, ra, re
31 ldr \rd, =flush_base
32 ldr \ra, [\rd]
33 eor \ra, \ra, #FLUSH_OFFSET
34 str \ra, [\rd]
35 add \re, \ra, #16384 @ only necessary for 16k
361001: ldr \rd, [\ra], #DCACHELINESIZE
37 teq \re, \ra
38 bne 1001b
39 .endm
40
41 .data
42flush_base:
43 .long FLUSH_BASE
44 .text
45
46/*
47 * cpu_sa110_proc_init()
48 */
49ENTRY(cpu_sa110_proc_init)
50 mov r0, #0
51 mcr p15, 0, r0, c15, c1, 2 @ Enable clock switching
52 mov pc, lr
53
54/*
55 * cpu_sa110_proc_fin()
56 */
57ENTRY(cpu_sa110_proc_fin)
58 stmfd sp!, {lr}
59 mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
60 msr cpsr_c, ip
61 bl v4wb_flush_kern_cache_all @ clean caches
621: mov r0, #0
63 mcr p15, 0, r0, c15, c2, 2 @ Disable clock switching
64 mrc p15, 0, r0, c1, c0, 0 @ ctrl register
65 bic r0, r0, #0x1000 @ ...i............
66 bic r0, r0, #0x000e @ ............wca.
67 mcr p15, 0, r0, c1, c0, 0 @ disable caches
68 ldmfd sp!, {pc}
69
70/*
71 * cpu_sa110_reset(loc)
72 *
73 * Perform a soft reset of the system. Put the CPU into the
74 * same state as it would be if it had been reset, and branch
75 * to what would be the reset vector.
76 *
77 * loc: location to jump to for soft reset
78 */
79 .align 5
80ENTRY(cpu_sa110_reset)
81 mov ip, #0
82 mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
83 mcr p15, 0, ip, c7, c10, 4 @ drain WB
84 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
85 mrc p15, 0, ip, c1, c0, 0 @ ctrl register
86 bic ip, ip, #0x000f @ ............wcam
87 bic ip, ip, #0x1100 @ ...i...s........
88 mcr p15, 0, ip, c1, c0, 0 @ ctrl register
89 mov pc, r0
90
91/*
92 * cpu_sa110_do_idle(type)
93 *
94 * Cause the processor to idle
95 *
96 * type: call type:
97 * 0 = slow idle
98 * 1 = fast idle
99 * 2 = switch to slow processor clock
100 * 3 = switch to fast processor clock
101 */
102 .align 5
103
104ENTRY(cpu_sa110_do_idle)
105 mcr p15, 0, ip, c15, c2, 2 @ disable clock switching
106 ldr r1, =UNCACHEABLE_ADDR @ load from uncacheable loc
107 ldr r1, [r1, #0] @ force switch to MCLK
108 mov r0, r0 @ safety
109 mov r0, r0 @ safety
110 mov r0, r0 @ safety
111 mcr p15, 0, r0, c15, c8, 2 @ Wait for interrupt, cache aligned
112 mov r0, r0 @ safety
113 mov r0, r0 @ safety
114 mov r0, r0 @ safety
115 mcr p15, 0, r0, c15, c1, 2 @ enable clock switching
116 mov pc, lr
117
118/* ================================= CACHE ================================ */
119
120/*
121 * cpu_sa110_dcache_clean_area(addr,sz)
122 *
123 * Clean the specified entry of any caches such that the MMU
124 * translation fetches will obtain correct data.
125 *
126 * addr: cache-unaligned virtual address
127 */
128 .align 5
129ENTRY(cpu_sa110_dcache_clean_area)
1301: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
131 add r0, r0, #DCACHELINESIZE
132 subs r1, r1, #DCACHELINESIZE
133 bhi 1b
134 mov pc, lr
135
136/* =============================== PageTable ============================== */
137
138/*
139 * cpu_sa110_switch_mm(pgd)
140 *
141 * Set the translation base pointer to be as described by pgd.
142 *
143 * pgd: new page tables
144 */
145 .align 5
146ENTRY(cpu_sa110_switch_mm)
147 flush_110_dcache r3, ip, r1
148 mov r1, #0
149 mcr p15, 0, r1, c7, c5, 0 @ invalidate I cache
150 mcr p15, 0, r1, c7, c10, 4 @ drain WB
151 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
152 mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs
153 mov pc, lr
154
155/*
156 * cpu_sa110_set_pte(ptep, pte)
157 *
158 * Set a PTE and flush it out
159 */
160 .align 5
161ENTRY(cpu_sa110_set_pte)
162 str r1, [r0], #-2048 @ linux version
163
164 eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
165
166 bic r2, r1, #PTE_SMALL_AP_MASK
167 bic r2, r2, #PTE_TYPE_MASK
168 orr r2, r2, #PTE_TYPE_SMALL
169
170 tst r1, #L_PTE_USER @ User?
171 orrne r2, r2, #PTE_SMALL_AP_URO_SRW
172
173 tst r1, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty?
174 orreq r2, r2, #PTE_SMALL_AP_UNO_SRW
175
176 tst r1, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young?
177 movne r2, #0
178
179 str r2, [r0] @ hardware version
180 mov r0, r0
181 mcr p15, 0, r0, c7, c10, 1 @ clean D entry
182 mcr p15, 0, r0, c7, c10, 4 @ drain WB
183 mov pc, lr
184
185 __INIT
186
187 .type __sa110_setup, #function
188__sa110_setup:
189 mov r10, #0
190 mcr p15, 0, r10, c7, c7 @ invalidate I,D caches on v4
191 mcr p15, 0, r10, c7, c10, 4 @ drain write buffer on v4
192 mcr p15, 0, r10, c8, c7 @ invalidate I,D TLBs on v4
193 mrc p15, 0, r0, c1, c0 @ get control register v4
194 ldr r5, sa110_cr1_clear
195 bic r0, r0, r5
196 ldr r5, sa110_cr1_set
197 orr r0, r0, r5
198 mov pc, lr
199 .size __sa110_setup, . - __sa110_setup
200
201 /*
202 * R
203 * .RVI ZFRS BLDP WCAM
204 * ..01 0001 ..11 1101
205 *
206 */
207 .type sa110_cr1_clear, #object
208 .type sa110_cr1_set, #object
209sa110_cr1_clear:
210 .word 0x3f3f
211sa110_cr1_set:
212 .word 0x113d
213
214 __INITDATA
215
216/*
217 * Purpose : Function pointers used to access above functions - all calls
218 * come through these
219 */
220
221 .type sa110_processor_functions, #object
222ENTRY(sa110_processor_functions)
223 .word v4_early_abort
224 .word cpu_sa110_proc_init
225 .word cpu_sa110_proc_fin
226 .word cpu_sa110_reset
227 .word cpu_sa110_do_idle
228 .word cpu_sa110_dcache_clean_area
229 .word cpu_sa110_switch_mm
230 .word cpu_sa110_set_pte
231 .size sa110_processor_functions, . - sa110_processor_functions
232
233 .section ".rodata"
234
235 .type cpu_arch_name, #object
236cpu_arch_name:
237 .asciz "armv4"
238 .size cpu_arch_name, . - cpu_arch_name
239
240 .type cpu_elf_name, #object
241cpu_elf_name:
242 .asciz "v4"
243 .size cpu_elf_name, . - cpu_elf_name
244
245 .type cpu_sa110_name, #object
246cpu_sa110_name:
247 .asciz "StrongARM-110"
248 .size cpu_sa110_name, . - cpu_sa110_name
249
250 .align
251
252 .section ".proc.info", #alloc, #execinstr
253
254 .type __sa110_proc_info,#object
255__sa110_proc_info:
256 .long 0x4401a100
257 .long 0xfffffff0
258 .long PMD_TYPE_SECT | \
259 PMD_SECT_BUFFERABLE | \
260 PMD_SECT_CACHEABLE | \
261 PMD_SECT_AP_WRITE | \
262 PMD_SECT_AP_READ
263 b __sa110_setup
264 .long cpu_arch_name
265 .long cpu_elf_name
266 .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT
267 .long cpu_sa110_name
268 .long sa110_processor_functions
269 .long v4wb_tlb_fns
270 .long v4wb_user_fns
271 .long v4wb_cache_fns
272 .size __sa110_proc_info, . - __sa110_proc_info
diff --git a/arch/arm/mm/proc-sa1100.S b/arch/arm/mm/proc-sa1100.S
new file mode 100644
index 000000000000..d447cd5f3dd9
--- /dev/null
+++ b/arch/arm/mm/proc-sa1100.S
@@ -0,0 +1,323 @@
1/*
2 * linux/arch/arm/mm/proc-sa1100.S
3 *
4 * Copyright (C) 1997-2002 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * MMU functions for SA110
11 *
12 * These are the low level assembler for performing cache and TLB
13 * functions on the StrongARM-1100 and StrongARM-1110.
14 *
15 * Note that SA1100 and SA1110 share everything but their name and CPU ID.
16 *
17 * 12-jun-2000, Erik Mouw (J.A.K.Mouw@its.tudelft.nl):
18 * Flush the read buffer at context switches
19 */
20#include <linux/linkage.h>
21#include <linux/init.h>
22#include <asm/assembler.h>
23#include <asm/constants.h>
24#include <asm/procinfo.h>
25#include <asm/hardware.h>
26#include <asm/pgtable.h>
27
28/*
29 * the cache line size of the I and D cache
30 */
31#define DCACHELINESIZE 32
32#define FLUSH_OFFSET 32768
33
34 .macro flush_1100_dcache rd, ra, re
35 ldr \rd, =flush_base
36 ldr \ra, [\rd]
37 eor \ra, \ra, #FLUSH_OFFSET
38 str \ra, [\rd]
39 add \re, \ra, #8192 @ only necessary for 8k
401001: ldr \rd, [\ra], #DCACHELINESIZE
41 teq \re, \ra
42 bne 1001b
43#ifdef FLUSH_BASE_MINICACHE
44 add \ra, \ra, #FLUSH_BASE_MINICACHE - FLUSH_BASE
45 add \re, \ra, #512 @ only 512 bytes
461002: ldr \rd, [\ra], #DCACHELINESIZE
47 teq \re, \ra
48 bne 1002b
49#endif
50 .endm
51
52 .data
53flush_base:
54 .long FLUSH_BASE
55 .text
56
57 __INIT
58
59/*
60 * cpu_sa1100_proc_init()
61 */
62ENTRY(cpu_sa1100_proc_init)
63 mov r0, #0
64 mcr p15, 0, r0, c15, c1, 2 @ Enable clock switching
65 mcr p15, 0, r0, c9, c0, 5 @ Allow read-buffer operations from userland
66 mov pc, lr
67
68 .previous
69
70/*
71 * cpu_sa1100_proc_fin()
72 *
73 * Prepare the CPU for reset:
74 * - Disable interrupts
75 * - Clean and turn off caches.
76 */
77ENTRY(cpu_sa1100_proc_fin)
78 stmfd sp!, {lr}
79 mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
80 msr cpsr_c, ip
81 flush_1100_dcache r0, r1, r2 @ clean caches
82 mov r0, #0
83 mcr p15, 0, r0, c15, c2, 2 @ Disable clock switching
84 mrc p15, 0, r0, c1, c0, 0 @ ctrl register
85 bic r0, r0, #0x1000 @ ...i............
86 bic r0, r0, #0x000e @ ............wca.
87 mcr p15, 0, r0, c1, c0, 0 @ disable caches
88 ldmfd sp!, {pc}
89
90/*
91 * cpu_sa1100_reset(loc)
92 *
93 * Perform a soft reset of the system. Put the CPU into the
94 * same state as it would be if it had been reset, and branch
95 * to what would be the reset vector.
96 *
97 * loc: location to jump to for soft reset
98 */
99 .align 5
100ENTRY(cpu_sa1100_reset)
101 mov ip, #0
102 mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
103 mcr p15, 0, ip, c7, c10, 4 @ drain WB
104 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
105 mrc p15, 0, ip, c1, c0, 0 @ ctrl register
106 bic ip, ip, #0x000f @ ............wcam
107 bic ip, ip, #0x1100 @ ...i...s........
108 mcr p15, 0, ip, c1, c0, 0 @ ctrl register
109 mov pc, r0
110
111/*
112 * cpu_sa1100_do_idle(type)
113 *
114 * Cause the processor to idle
115 *
116 * type: call type:
117 * 0 = slow idle
118 * 1 = fast idle
119 * 2 = switch to slow processor clock
120 * 3 = switch to fast processor clock
121 */
122 .align 5
123ENTRY(cpu_sa1100_do_idle)
124 mov r0, r0 @ 4 nop padding
125 mov r0, r0
126 mov r0, r0
127 mov r0, r0 @ 4 nop padding
128 mov r0, r0
129 mov r0, r0
130 mov r0, #0
131 ldr r1, =UNCACHEABLE_ADDR @ ptr to uncacheable address
132 @ --- aligned to a cache line
133 mcr p15, 0, r0, c15, c2, 2 @ disable clock switching
134 ldr r1, [r1, #0] @ force switch to MCLK
135 mcr p15, 0, r0, c15, c8, 2 @ wait for interrupt
136 mov r0, r0 @ safety
137 mcr p15, 0, r0, c15, c1, 2 @ enable clock switching
138 mov pc, lr
139
140/* ================================= CACHE ================================ */
141
142/*
143 * cpu_sa1100_dcache_clean_area(addr,sz)
144 *
145 * Clean the specified entry of any caches such that the MMU
146 * translation fetches will obtain correct data.
147 *
148 * addr: cache-unaligned virtual address
149 */
150 .align 5
151ENTRY(cpu_sa1100_dcache_clean_area)
1521: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
153 add r0, r0, #DCACHELINESIZE
154 subs r1, r1, #DCACHELINESIZE
155 bhi 1b
156 mov pc, lr
157
158/* =============================== PageTable ============================== */
159
160/*
161 * cpu_sa1100_switch_mm(pgd)
162 *
163 * Set the translation base pointer to be as described by pgd.
164 *
165 * pgd: new page tables
166 */
167 .align 5
168ENTRY(cpu_sa1100_switch_mm)
169 flush_1100_dcache r3, ip, r1
170 mov ip, #0
171 mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache
172 mcr p15, 0, ip, c9, c0, 0 @ invalidate RB
173 mcr p15, 0, ip, c7, c10, 4 @ drain WB
174 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
175 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
176 mov pc, lr
177
178/*
179 * cpu_sa1100_set_pte(ptep, pte)
180 *
181 * Set a PTE and flush it out
182 */
183 .align 5
184ENTRY(cpu_sa1100_set_pte)
185 str r1, [r0], #-2048 @ linux version
186
187 eor r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
188
189 bic r2, r1, #PTE_SMALL_AP_MASK
190 bic r2, r2, #PTE_TYPE_MASK
191 orr r2, r2, #PTE_TYPE_SMALL
192
193 tst r1, #L_PTE_USER @ User?
194 orrne r2, r2, #PTE_SMALL_AP_URO_SRW
195
196 tst r1, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty?
197 orreq r2, r2, #PTE_SMALL_AP_UNO_SRW
198
199 tst r1, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young?
200 movne r2, #0
201
202 str r2, [r0] @ hardware version
203 mov r0, r0
204 mcr p15, 0, r0, c7, c10, 1 @ clean D entry
205 mcr p15, 0, r0, c7, c10, 4 @ drain WB
206 mov pc, lr
207
208 __INIT
209
210 .type __sa1100_setup, #function
211__sa1100_setup:
212 mov r0, #0
213 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
214 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
215 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
216 mrc p15, 0, r0, c1, c0 @ get control register v4
217 ldr r5, sa1100_cr1_clear
218 bic r0, r0, r5
219 ldr r5, sa1100_cr1_set
220 orr r0, r0, r5
221 mov pc, lr
222 .size __sa1100_setup, . - __sa1100_setup
223
224 /*
225 * R
226 * .RVI ZFRS BLDP WCAM
227 * ..11 0001 ..11 1101
228 *
229 */
230 .type sa1100_cr1_clear, #object
231 .type sa1100_cr1_set, #object
232sa1100_cr1_clear:
233 .word 0x3f3f
234sa1100_cr1_set:
235 .word 0x313d
236
237 __INITDATA
238
239/*
240 * Purpose : Function pointers used to access above functions - all calls
241 * come through these
242 */
243
244/*
245 * SA1100 and SA1110 share the same function calls
246 */
247 .type sa1100_processor_functions, #object
248ENTRY(sa1100_processor_functions)
249 .word v4_early_abort
250 .word cpu_sa1100_proc_init
251 .word cpu_sa1100_proc_fin
252 .word cpu_sa1100_reset
253 .word cpu_sa1100_do_idle
254 .word cpu_sa1100_dcache_clean_area
255 .word cpu_sa1100_switch_mm
256 .word cpu_sa1100_set_pte
257 .size sa1100_processor_functions, . - sa1100_processor_functions
258
259 .section ".rodata"
260
261 .type cpu_arch_name, #object
262cpu_arch_name:
263 .asciz "armv4"
264 .size cpu_arch_name, . - cpu_arch_name
265
266 .type cpu_elf_name, #object
267cpu_elf_name:
268 .asciz "v4"
269 .size cpu_elf_name, . - cpu_elf_name
270
271 .type cpu_sa1100_name, #object
272cpu_sa1100_name:
273 .asciz "StrongARM-1100"
274 .size cpu_sa1100_name, . - cpu_sa1100_name
275
276 .type cpu_sa1110_name, #object
277cpu_sa1110_name:
278 .asciz "StrongARM-1110"
279 .size cpu_sa1110_name, . - cpu_sa1110_name
280
281 .align
282
283 .section ".proc.info", #alloc, #execinstr
284
285 .type __sa1100_proc_info,#object
286__sa1100_proc_info:
287 .long 0x4401a110
288 .long 0xfffffff0
289 .long PMD_TYPE_SECT | \
290 PMD_SECT_BUFFERABLE | \
291 PMD_SECT_CACHEABLE | \
292 PMD_SECT_AP_WRITE | \
293 PMD_SECT_AP_READ
294 b __sa1100_setup
295 .long cpu_arch_name
296 .long cpu_elf_name
297 .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT
298 .long cpu_sa1100_name
299 .long sa1100_processor_functions
300 .long v4wb_tlb_fns
301 .long v4_mc_user_fns
302 .long v4wb_cache_fns
303 .size __sa1100_proc_info, . - __sa1100_proc_info
304
305 .type __sa1110_proc_info,#object
306__sa1110_proc_info:
307 .long 0x6901b110
308 .long 0xfffffff0
309 .long PMD_TYPE_SECT | \
310 PMD_SECT_BUFFERABLE | \
311 PMD_SECT_CACHEABLE | \
312 PMD_SECT_AP_WRITE | \
313 PMD_SECT_AP_READ
314 b __sa1100_setup
315 .long cpu_arch_name
316 .long cpu_elf_name
317 .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT
318 .long cpu_sa1110_name
319 .long sa1100_processor_functions
320 .long v4wb_tlb_fns
321 .long v4_mc_user_fns
322 .long v4wb_cache_fns
323 .size __sa1110_proc_info, . - __sa1110_proc_info
diff --git a/arch/arm/mm/proc-syms.c b/arch/arm/mm/proc-syms.c
new file mode 100644
index 000000000000..6c5f0fe578a5
--- /dev/null
+++ b/arch/arm/mm/proc-syms.c
@@ -0,0 +1,40 @@
1/*
2 * linux/arch/arm/mm/proc-syms.c
3 *
4 * Copyright (C) 2000-2002 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/module.h>
11#include <linux/mm.h>
12
13#include <asm/cacheflush.h>
14#include <asm/proc-fns.h>
15#include <asm/tlbflush.h>
16
17#ifndef MULTI_CPU
18EXPORT_SYMBOL(cpu_dcache_clean_area);
19EXPORT_SYMBOL(cpu_set_pte);
20#else
21EXPORT_SYMBOL(processor);
22#endif
23
24#ifndef MULTI_CACHE
25EXPORT_SYMBOL(__cpuc_flush_kern_all);
26EXPORT_SYMBOL(__cpuc_flush_user_all);
27EXPORT_SYMBOL(__cpuc_flush_user_range);
28EXPORT_SYMBOL(__cpuc_coherent_kern_range);
29#else
30EXPORT_SYMBOL(cpu_cache);
31#endif
32
33/*
34 * No module should need to touch the TLB (and currently
35 * no modules do. We export this for "loadkernel" support
36 * (booting a new kernel from within a running kernel.)
37 */
38#ifdef MULTI_TLB
39EXPORT_SYMBOL(cpu_tlb);
40#endif
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
new file mode 100644
index 000000000000..0aa73d414783
--- /dev/null
+++ b/arch/arm/mm/proc-v6.S
@@ -0,0 +1,272 @@
1/*
2 * linux/arch/arm/mm/proc-v6.S
3 *
4 * Copyright (C) 2001 Deep Blue Solutions Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This is the "shell" of the ARMv6 processor support.
11 */
12#include <linux/linkage.h>
13#include <asm/assembler.h>
14#include <asm/constants.h>
15#include <asm/procinfo.h>
16#include <asm/pgtable.h>
17
18#include "proc-macros.S"
19
20#define D_CACHE_LINE_SIZE 32
21
22 .macro cpsie, flags
23 .ifc \flags, f
24 .long 0xf1080040
25 .exitm
26 .endif
27 .ifc \flags, i
28 .long 0xf1080080
29 .exitm
30 .endif
31 .ifc \flags, if
32 .long 0xf10800c0
33 .exitm
34 .endif
35 .err
36 .endm
37
38 .macro cpsid, flags
39 .ifc \flags, f
40 .long 0xf10c0040
41 .exitm
42 .endif
43 .ifc \flags, i
44 .long 0xf10c0080
45 .exitm
46 .endif
47 .ifc \flags, if
48 .long 0xf10c00c0
49 .exitm
50 .endif
51 .err
52 .endm
53
54ENTRY(cpu_v6_proc_init)
55 mov pc, lr
56
57ENTRY(cpu_v6_proc_fin)
58 mov pc, lr
59
60/*
61 * cpu_v6_reset(loc)
62 *
63 * Perform a soft reset of the system. Put the CPU into the
64 * same state as it would be if it had been reset, and branch
65 * to what would be the reset vector.
66 *
67 * - loc - location to jump to for soft reset
68 *
69 * It is assumed that:
70 */
71 .align 5
72ENTRY(cpu_v6_reset)
73 mov pc, r0
74
75/*
76 * cpu_v6_do_idle()
77 *
78 * Idle the processor (eg, wait for interrupt).
79 *
80 * IRQs are already disabled.
81 */
82ENTRY(cpu_v6_do_idle)
83 mcr p15, 0, r1, c7, c0, 4 @ wait for interrupt
84 mov pc, lr
85
86ENTRY(cpu_v6_dcache_clean_area)
87#ifndef TLB_CAN_READ_FROM_L1_CACHE
881: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
89 add r0, r0, #D_CACHE_LINE_SIZE
90 subs r1, r1, #D_CACHE_LINE_SIZE
91 bhi 1b
92#endif
93 mov pc, lr
94
95/*
96 * cpu_arm926_switch_mm(pgd_phys, tsk)
97 *
98 * Set the translation table base pointer to be pgd_phys
99 *
100 * - pgd_phys - physical address of new TTB
101 *
102 * It is assumed that:
103 * - we are not using split page tables
104 */
105ENTRY(cpu_v6_switch_mm)
106 mov r2, #0
107 ldr r1, [r1, #MM_CONTEXT_ID] @ get mm->context.id
108 mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB
109 mcr p15, 0, r2, c7, c10, 4 @ drain write buffer
110 mcr p15, 0, r0, c2, c0, 0 @ set TTB 0
111 mcr p15, 0, r1, c13, c0, 1 @ set context ID
112 mov pc, lr
113
114#define nG (1 << 11)
115#define APX (1 << 9)
116#define AP1 (1 << 5)
117#define AP0 (1 << 4)
118#define XN (1 << 0)
119
120/*
121 * cpu_v6_set_pte(ptep, pte)
122 *
123 * Set a level 2 translation table entry.
124 *
125 * - ptep - pointer to level 2 translation table entry
126 * (hardware version is stored at -1024 bytes)
127 * - pte - PTE value to store
128 *
129 * Permissions:
130 * YUWD APX AP1 AP0 SVC User
131 * 0xxx 0 0 0 no acc no acc
132 * 100x 1 0 1 r/o no acc
133 * 10x0 1 0 1 r/o no acc
134 * 1011 0 0 1 r/w no acc
135 * 110x 1 1 0 r/o r/o
136 * 11x0 1 1 0 r/o r/o
137 * 1111 0 1 1 r/w r/w
138 */
139ENTRY(cpu_v6_set_pte)
140 str r1, [r0], #-2048 @ linux version
141
142 bic r2, r1, #0x00000ff0
143 bic r2, r2, #0x00000003
144 orr r2, r2, #AP0 | 2
145
146 tst r1, #L_PTE_WRITE
147 tstne r1, #L_PTE_DIRTY
148 orreq r2, r2, #APX
149
150 tst r1, #L_PTE_USER
151 orrne r2, r2, #AP1 | nG
152 tstne r2, #APX
153 eorne r2, r2, #AP0
154
155 tst r1, #L_PTE_YOUNG
156 biceq r2, r2, #APX | AP1 | AP0
157
158@ tst r1, #L_PTE_EXEC
159@ orreq r2, r2, #XN
160
161 tst r1, #L_PTE_PRESENT
162 moveq r2, #0
163
164 str r2, [r0]
165 mcr p15, 0, r0, c7, c10, 1 @ flush_pte
166 mov pc, lr
167
168
169
170
171cpu_v6_name:
172 .asciz "Some Random V6 Processor"
173 .align
174
175 .section ".text.init", #alloc, #execinstr
176
177/*
178 * __v6_setup
179 *
180 * Initialise TLB, Caches, and MMU state ready to switch the MMU
181 * on. Return in r0 the new CP15 C1 control register setting.
182 *
183 * We automatically detect if we have a Harvard cache, and use the
184 * Harvard cache control instructions insead of the unified cache
185 * control instructions.
186 *
187 * This should be able to cover all ARMv6 cores.
188 *
189 * It is assumed that:
190 * - cache type register is implemented
191 */
192__v6_setup:
193 mov r0, #0
194 mcr p15, 0, r0, c7, c14, 0 @ clean+invalidate D cache
195 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
196 mcr p15, 0, r0, c7, c15, 0 @ clean+invalidate cache
197 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
198 mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs
199 mcr p15, 0, r0, c2, c0, 2 @ TTB control register
200 mcr p15, 0, r4, c2, c0, 1 @ load TTB1
201#ifdef CONFIG_VFP
202 mrc p15, 0, r0, c1, c0, 2
203 orr r0, r0, #(3 << 20)
204 mcr p15, 0, r0, c1, c0, 2 @ Enable full access to VFP
205#endif
206 mrc p15, 0, r0, c1, c0, 0 @ read control register
207 ldr r5, v6_cr1_clear @ get mask for bits to clear
208 bic r0, r0, r5 @ clear bits them
209 ldr r5, v6_cr1_set @ get mask for bits to set
210 orr r0, r0, r5 @ set them
211 mov pc, lr @ return to head.S:__ret
212
213 /*
214 * V X F I D LR
215 * .... ...E PUI. .T.T 4RVI ZFRS BLDP WCAM
216 * rrrr rrrx xxx0 0101 xxxx xxxx x111 xxxx < forced
217 * 0 110 0011 1.00 .111 1101 < we want
218 */
219 .type v6_cr1_clear, #object
220 .type v6_cr1_set, #object
221v6_cr1_clear:
222 .word 0x01e0fb7f
223v6_cr1_set:
224 .word 0x00c0387d
225
226 .type v6_processor_functions, #object
227ENTRY(v6_processor_functions)
228 .word v6_early_abort
229 .word cpu_v6_proc_init
230 .word cpu_v6_proc_fin
231 .word cpu_v6_reset
232 .word cpu_v6_do_idle
233 .word cpu_v6_dcache_clean_area
234 .word cpu_v6_switch_mm
235 .word cpu_v6_set_pte
236 .size v6_processor_functions, . - v6_processor_functions
237
238 .type cpu_arch_name, #object
239cpu_arch_name:
240 .asciz "armv6"
241 .size cpu_arch_name, . - cpu_arch_name
242
243 .type cpu_elf_name, #object
244cpu_elf_name:
245 .asciz "v6"
246 .size cpu_elf_name, . - cpu_elf_name
247 .align
248
249 .section ".proc.info", #alloc, #execinstr
250
251 /*
252 * Match any ARMv6 processor core.
253 */
254 .type __v6_proc_info, #object
255__v6_proc_info:
256 .long 0x0007b000
257 .long 0x0007f000
258 .long PMD_TYPE_SECT | \
259 PMD_SECT_BUFFERABLE | \
260 PMD_SECT_CACHEABLE | \
261 PMD_SECT_AP_WRITE | \
262 PMD_SECT_AP_READ
263 b __v6_setup
264 .long cpu_arch_name
265 .long cpu_elf_name
266 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_VFP|HWCAP_EDSP|HWCAP_JAVA
267 .long cpu_v6_name
268 .long v6_processor_functions
269 .long v6wbi_tlb_fns
270 .long v6_user_fns
271 .long v6_cache_fns
272 .size __v6_proc_info, . - __v6_proc_info
diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S
new file mode 100644
index 000000000000..2d977b4eeeab
--- /dev/null
+++ b/arch/arm/mm/proc-xscale.S
@@ -0,0 +1,934 @@
1/*
2 * linux/arch/arm/mm/proc-xscale.S
3 *
4 * Author: Nicolas Pitre
5 * Created: November 2000
6 * Copyright: (C) 2000, 2001 MontaVista Software Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * MMU functions for the Intel XScale CPUs
13 *
14 * 2001 Aug 21:
15 * some contributions by Brett Gaines <brett.w.gaines@intel.com>
16 * Copyright 2001 by Intel Corp.
17 *
18 * 2001 Sep 08:
19 * Completely revisited, many important fixes
20 * Nicolas Pitre <nico@cam.org>
21 */
22
23#include <linux/linkage.h>
24#include <linux/init.h>
25#include <asm/assembler.h>
26#include <asm/procinfo.h>
27#include <asm/hardware.h>
28#include <asm/pgtable.h>
29#include <asm/page.h>
30#include <asm/ptrace.h>
31#include "proc-macros.S"
32
33/*
34 * This is the maximum size of an area which will be flushed. If the area
35 * is larger than this, then we flush the whole cache
36 */
37#define MAX_AREA_SIZE 32768
38
39/*
40 * the cache line size of the I and D cache
41 */
42#define CACHELINESIZE 32
43
44/*
45 * the size of the data cache
46 */
47#define CACHESIZE 32768
48
49/*
50 * Virtual address used to allocate the cache when flushed
51 *
52 * This must be an address range which is _never_ used. It should
53 * apparently have a mapping in the corresponding page table for
54 * compatibility with future CPUs that _could_ require it. For instance we
55 * don't care.
56 *
57 * This must be aligned on a 2*CACHESIZE boundary. The code selects one of
58 * the 2 areas in alternance each time the clean_d_cache macro is used.
59 * Without this the XScale core exhibits cache eviction problems and no one
60 * knows why.
61 *
62 * Reminder: the vector table is located at 0xffff0000-0xffff0fff.
63 */
64#define CLEAN_ADDR 0xfffe0000
65
66/*
67 * This macro is used to wait for a CP15 write and is needed
68 * when we have to ensure that the last operation to the co-pro
69 * was completed before continuing with operation.
70 */
71 .macro cpwait, rd
72 mrc p15, 0, \rd, c2, c0, 0 @ arbitrary read of cp15
73 mov \rd, \rd @ wait for completion
74 sub pc, pc, #4 @ flush instruction pipeline
75 .endm
76
77 .macro cpwait_ret, lr, rd
78 mrc p15, 0, \rd, c2, c0, 0 @ arbitrary read of cp15
79 sub pc, \lr, \rd, LSR #32 @ wait for completion and
80 @ flush instruction pipeline
81 .endm
82
83/*
84 * This macro cleans the entire dcache using line allocate.
85 * The main loop has been unrolled to reduce loop overhead.
86 * rd and rs are two scratch registers.
87 */
88 .macro clean_d_cache, rd, rs
89 ldr \rs, =clean_addr
90 ldr \rd, [\rs]
91 eor \rd, \rd, #CACHESIZE
92 str \rd, [\rs]
93 add \rs, \rd, #CACHESIZE
941: mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line
95 add \rd, \rd, #CACHELINESIZE
96 mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line
97 add \rd, \rd, #CACHELINESIZE
98 mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line
99 add \rd, \rd, #CACHELINESIZE
100 mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line
101 add \rd, \rd, #CACHELINESIZE
102 teq \rd, \rs
103 bne 1b
104 .endm
105
106 .data
107clean_addr: .word CLEAN_ADDR
108
109 .text
110
111/*
112 * cpu_xscale_proc_init()
113 *
114 * Nothing too exciting at the moment
115 */
116ENTRY(cpu_xscale_proc_init)
117 mov pc, lr
118
119/*
120 * cpu_xscale_proc_fin()
121 */
122ENTRY(cpu_xscale_proc_fin)
123 str lr, [sp, #-4]!
124 mov r0, #PSR_F_BIT|PSR_I_BIT|SVC_MODE
125 msr cpsr_c, r0
126 bl xscale_flush_kern_cache_all @ clean caches
127 mrc p15, 0, r0, c1, c0, 0 @ ctrl register
128 bic r0, r0, #0x1800 @ ...IZ...........
129 bic r0, r0, #0x0006 @ .............CA.
130 mcr p15, 0, r0, c1, c0, 0 @ disable caches
131 ldr pc, [sp], #4
132
133/*
134 * cpu_xscale_reset(loc)
135 *
136 * Perform a soft reset of the system. Put the CPU into the
137 * same state as it would be if it had been reset, and branch
138 * to what would be the reset vector.
139 *
140 * loc: location to jump to for soft reset
141 */
142 .align 5
143ENTRY(cpu_xscale_reset)
144 mov r1, #PSR_F_BIT|PSR_I_BIT|SVC_MODE
145 msr cpsr_c, r1 @ reset CPSR
146 mrc p15, 0, r1, c1, c0, 0 @ ctrl register
147 bic r1, r1, #0x0086 @ ........B....CA.
148 bic r1, r1, #0x3900 @ ..VIZ..S........
149 mcr p15, 0, r1, c1, c0, 0 @ ctrl register
150 mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches & BTB
151 bic r1, r1, #0x0001 @ ...............M
152 mcr p15, 0, r1, c1, c0, 0 @ ctrl register
153 @ CAUTION: MMU turned off from this point. We count on the pipeline
154 @ already containing those two last instructions to survive.
155 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
156 mov pc, r0
157
158/*
159 * cpu_xscale_do_idle()
160 *
161 * Cause the processor to idle
162 *
163 * For now we do nothing but go to idle mode for every case
164 *
165 * XScale supports clock switching, but using idle mode support
166 * allows external hardware to react to system state changes.
167 */
168 .align 5
169
170ENTRY(cpu_xscale_do_idle)
171 mov r0, #1
172 mcr p14, 0, r0, c7, c0, 0 @ Go to IDLE
173 mov pc, lr
174
175/* ================================= CACHE ================================ */
176
177/*
178 * flush_user_cache_all()
179 *
180 * Invalidate all cache entries in a particular address
181 * space.
182 */
183ENTRY(xscale_flush_user_cache_all)
184 /* FALLTHROUGH */
185
186/*
187 * flush_kern_cache_all()
188 *
189 * Clean and invalidate the entire cache.
190 */
191ENTRY(xscale_flush_kern_cache_all)
192 mov r2, #VM_EXEC
193 mov ip, #0
194__flush_whole_cache:
195 clean_d_cache r0, r1
196 tst r2, #VM_EXEC
197 mcrne p15, 0, ip, c7, c5, 0 @ Invalidate I cache & BTB
198 mcrne p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
199 mov pc, lr
200
201/*
202 * flush_user_cache_range(start, end, vm_flags)
203 *
204 * Invalidate a range of cache entries in the specified
205 * address space.
206 *
207 * - start - start address (may not be aligned)
208 * - end - end address (exclusive, may not be aligned)
209 * - vma - vma_area_struct describing address space
210 */
211 .align 5
212ENTRY(xscale_flush_user_cache_range)
213 mov ip, #0
214 sub r3, r1, r0 @ calculate total size
215 cmp r3, #MAX_AREA_SIZE
216 bhs __flush_whole_cache
217
2181: tst r2, #VM_EXEC
219 mcrne p15, 0, r0, c7, c5, 1 @ Invalidate I cache line
220 mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
221 mcr p15, 0, r0, c7, c6, 1 @ Invalidate D cache line
222 add r0, r0, #CACHELINESIZE
223 cmp r0, r1
224 blo 1b
225 tst r2, #VM_EXEC
226 mcrne p15, 0, ip, c7, c5, 6 @ Invalidate BTB
227 mcrne p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
228 mov pc, lr
229
230/*
231 * coherent_kern_range(start, end)
232 *
233 * Ensure coherency between the Icache and the Dcache in the
234 * region described by start. If you have non-snooping
235 * Harvard caches, you need to implement this function.
236 *
237 * - start - virtual start address
238 * - end - virtual end address
239 *
240 * Note: single I-cache line invalidation isn't used here since
241 * it also trashes the mini I-cache used by JTAG debuggers.
242 */
243ENTRY(xscale_coherent_kern_range)
244 /* FALLTHROUGH */
245
246/*
247 * coherent_user_range(start, end)
248 *
249 * Ensure coherency between the Icache and the Dcache in the
250 * region described by start. If you have non-snooping
251 * Harvard caches, you need to implement this function.
252 *
253 * - start - virtual start address
254 * - end - virtual end address
255 *
256 * Note: single I-cache line invalidation isn't used here since
257 * it also trashes the mini I-cache used by JTAG debuggers.
258 */
259ENTRY(xscale_coherent_user_range)
260 bic r0, r0, #CACHELINESIZE - 1
2611: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
262 add r0, r0, #CACHELINESIZE
263 cmp r0, r1
264 blo 1b
265 mov r0, #0
266 mcr p15, 0, r0, c7, c5, 0 @ Invalidate I cache & BTB
267 mcr p15, 0, r0, c7, c10, 4 @ Drain Write (& Fill) Buffer
268 mov pc, lr
269
270/*
271 * flush_kern_dcache_page(void *page)
272 *
273 * Ensure no D cache aliasing occurs, either with itself or
274 * the I cache
275 *
276 * - addr - page aligned address
277 */
278ENTRY(xscale_flush_kern_dcache_page)
279 add r1, r0, #PAGE_SZ
2801: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
281 mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
282 add r0, r0, #CACHELINESIZE
283 cmp r0, r1
284 blo 1b
285 mov r0, #0
286 mcr p15, 0, r0, c7, c5, 0 @ Invalidate I cache & BTB
287 mcr p15, 0, r0, c7, c10, 4 @ Drain Write (& Fill) Buffer
288 mov pc, lr
289
290/*
291 * dma_inv_range(start, end)
292 *
293 * Invalidate (discard) the specified virtual address range.
294 * May not write back any entries. If 'start' or 'end'
295 * are not cache line aligned, those lines must be written
296 * back.
297 *
298 * - start - virtual start address
299 * - end - virtual end address
300 */
301ENTRY(xscale_dma_inv_range)
302 mrc p15, 0, r2, c0, c0, 0 @ read ID
303 eor r2, r2, #0x69000000
304 eor r2, r2, #0x00052000
305 bics r2, r2, #1
306 beq xscale_dma_flush_range
307
308 tst r0, #CACHELINESIZE - 1
309 bic r0, r0, #CACHELINESIZE - 1
310 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
311 tst r1, #CACHELINESIZE - 1
312 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry
3131: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
314 add r0, r0, #CACHELINESIZE
315 cmp r0, r1
316 blo 1b
317 mcr p15, 0, r0, c7, c10, 4 @ Drain Write (& Fill) Buffer
318 mov pc, lr
319
320/*
321 * dma_clean_range(start, end)
322 *
323 * Clean the specified virtual address range.
324 *
325 * - start - virtual start address
326 * - end - virtual end address
327 */
328ENTRY(xscale_dma_clean_range)
329 bic r0, r0, #CACHELINESIZE - 1
3301: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
331 add r0, r0, #CACHELINESIZE
332 cmp r0, r1
333 blo 1b
334 mcr p15, 0, r0, c7, c10, 4 @ Drain Write (& Fill) Buffer
335 mov pc, lr
336
337/*
338 * dma_flush_range(start, end)
339 *
340 * Clean and invalidate the specified virtual address range.
341 *
342 * - start - virtual start address
343 * - end - virtual end address
344 */
345ENTRY(xscale_dma_flush_range)
346 bic r0, r0, #CACHELINESIZE - 1
3471: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
348 mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
349 add r0, r0, #CACHELINESIZE
350 cmp r0, r1
351 blo 1b
352 mcr p15, 0, r0, c7, c10, 4 @ Drain Write (& Fill) Buffer
353 mov pc, lr
354
355ENTRY(xscale_cache_fns)
356 .long xscale_flush_kern_cache_all
357 .long xscale_flush_user_cache_all
358 .long xscale_flush_user_cache_range
359 .long xscale_coherent_kern_range
360 .long xscale_coherent_user_range
361 .long xscale_flush_kern_dcache_page
362 .long xscale_dma_inv_range
363 .long xscale_dma_clean_range
364 .long xscale_dma_flush_range
365
366ENTRY(cpu_xscale_dcache_clean_area)
3671: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
368 add r0, r0, #CACHELINESIZE
369 subs r1, r1, #CACHELINESIZE
370 bhi 1b
371 mov pc, lr
372
373/* ================================ CACHE LOCKING============================
374 *
375 * The XScale MicroArchitecture implements support for locking entries into
376 * the data and instruction cache. The following functions implement the core
377 * low level instructions needed to accomplish the locking. The developer's
378 * manual states that the code that performs the locking must be in non-cached
379 * memory. To accomplish this, the code in xscale-cache-lock.c copies the
380 * following functions from the cache into a non-cached memory region that
381 * is allocated through consistent_alloc().
382 *
383 */
384 .align 5
385/*
386 * xscale_icache_lock
387 *
388 * r0: starting address to lock
389 * r1: end address to lock
390 */
391ENTRY(xscale_icache_lock)
392
393iLockLoop:
394 bic r0, r0, #CACHELINESIZE - 1
395 mcr p15, 0, r0, c9, c1, 0 @ lock into cache
396 cmp r0, r1 @ are we done?
397 add r0, r0, #CACHELINESIZE @ advance to next cache line
398 bls iLockLoop
399 mov pc, lr
400
401/*
402 * xscale_icache_unlock
403 */
404ENTRY(xscale_icache_unlock)
405 mcr p15, 0, r0, c9, c1, 1 @ Unlock icache
406 mov pc, lr
407
408/*
409 * xscale_dcache_lock
410 *
411 * r0: starting address to lock
412 * r1: end address to lock
413 */
414ENTRY(xscale_dcache_lock)
415 mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
416 mov r2, #1
417 mcr p15, 0, r2, c9, c2, 0 @ Put dcache in lock mode
418 cpwait ip @ Wait for completion
419
420 mrs r2, cpsr
421 orr r3, r2, #PSR_F_BIT | PSR_I_BIT
422dLockLoop:
423 msr cpsr_c, r3
424 mcr p15, 0, r0, c7, c10, 1 @ Write back line if it is dirty
425 mcr p15, 0, r0, c7, c6, 1 @ Flush/invalidate line
426 msr cpsr_c, r2
427 ldr ip, [r0], #CACHELINESIZE @ Preload 32 bytes into cache from
428 @ location [r0]. Post-increment
429 @ r3 to next cache line
430 cmp r0, r1 @ Are we done?
431 bls dLockLoop
432
433 mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
434 mov r2, #0
435 mcr p15, 0, r2, c9, c2, 0 @ Get out of lock mode
436 cpwait_ret lr, ip
437
438/*
439 * xscale_dcache_unlock
440 */
441ENTRY(xscale_dcache_unlock)
442 mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
443 mcr p15, 0, ip, c9, c2, 1 @ Unlock cache
444 mov pc, lr
445
446/*
447 * Needed to determine the length of the code that needs to be copied.
448 */
449 .align 5
450ENTRY(xscale_cache_dummy)
451 mov pc, lr
452
453/* ================================ TLB LOCKING==============================
454 *
455 * The XScale MicroArchitecture implements support for locking entries into
456 * the Instruction and Data TLBs. The following functions provide the
457 * low level support for supporting these under Linux. xscale-lock.c
458 * implements some higher level management code. Most of the following
459 * is taken straight out of the Developer's Manual.
460 */
461
462/*
463 * Lock I-TLB entry
464 *
465 * r0: Virtual address to translate and lock
466 */
467 .align 5
468ENTRY(xscale_itlb_lock)
469 mrs r2, cpsr
470 orr r3, r2, #PSR_F_BIT | PSR_I_BIT
471 msr cpsr_c, r3 @ Disable interrupts
472 mcr p15, 0, r0, c8, c5, 1 @ Invalidate I-TLB entry
473 mcr p15, 0, r0, c10, c4, 0 @ Translate and lock
474 msr cpsr_c, r2 @ Restore interrupts
475 cpwait_ret lr, ip
476
477/*
478 * Lock D-TLB entry
479 *
480 * r0: Virtual address to translate and lock
481 */
482 .align 5
483ENTRY(xscale_dtlb_lock)
484 mrs r2, cpsr
485 orr r3, r2, #PSR_F_BIT | PSR_I_BIT
486 msr cpsr_c, r3 @ Disable interrupts
487 mcr p15, 0, r0, c8, c6, 1 @ Invalidate D-TLB entry
488 mcr p15, 0, r0, c10, c8, 0 @ Translate and lock
489 msr cpsr_c, r2 @ Restore interrupts
490 cpwait_ret lr, ip
491
492/*
493 * Unlock all I-TLB entries
494 */
495 .align 5
496ENTRY(xscale_itlb_unlock)
497 mcr p15, 0, ip, c10, c4, 1 @ Unlock I-TLB
498 mcr p15, 0, ip, c8, c5, 0 @ Invalidate I-TLB
499 cpwait_ret lr, ip
500
501/*
502 * Unlock all D-TLB entries
503 */
504ENTRY(xscale_dtlb_unlock)
505 mcr p15, 0, ip, c10, c8, 1 @ Unlock D-TBL
506 mcr p15, 0, ip, c8, c6, 0 @ Invalidate D-TLB
507 cpwait_ret lr, ip
508
509/* =============================== PageTable ============================== */
510
511#define PTE_CACHE_WRITE_ALLOCATE 0
512
513/*
514 * cpu_xscale_switch_mm(pgd)
515 *
516 * Set the translation base pointer to be as described by pgd.
517 *
518 * pgd: new page tables
519 */
520 .align 5
521ENTRY(cpu_xscale_switch_mm)
522 clean_d_cache r1, r2
523 mcr p15, 0, ip, c7, c5, 0 @ Invalidate I cache & BTB
524 mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
525 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
526 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
527 cpwait_ret lr, ip
528
529/*
530 * cpu_xscale_set_pte(ptep, pte)
531 *
532 * Set a PTE and flush it out
533 *
534 * Errata 40: must set memory to write-through for user read-only pages.
535 */
536 .align 5
537ENTRY(cpu_xscale_set_pte)
538 str r1, [r0], #-2048 @ linux version
539
540 bic r2, r1, #0xff0
541 orr r2, r2, #PTE_TYPE_EXT @ extended page
542
543 eor r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
544
545 tst r3, #L_PTE_USER @ User?
546 orrne r2, r2, #PTE_EXT_AP_URO_SRW @ yes -> user r/o, system r/w
547
548 tst r3, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty?
549 orreq r2, r2, #PTE_EXT_AP_UNO_SRW @ yes -> user n/a, system r/w
550 @ combined with user -> user r/w
551
552 @
553 @ Handle the X bit. We want to set this bit for the minicache
554 @ (U = E = B = W = 0, C = 1) or when write allocate is enabled,
555 @ and we have a writeable, cacheable region. If we ignore the
556 @ U and E bits, we can allow user space to use the minicache as
557 @ well.
558 @
559 @ X = (C & ~W & ~B) | (C & W & B & write_allocate)
560 @
561 eor ip, r1, #L_PTE_CACHEABLE
562 tst ip, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE
563#if PTE_CACHE_WRITE_ALLOCATE
564 eorne ip, r1, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE
565 tstne ip, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE
566#endif
567 orreq r2, r2, #PTE_EXT_TEX(1)
568
569 @
570 @ Erratum 40: The B bit must be cleared for a user read-only
571 @ cacheable page.
572 @
573 @ B = B & ~(U & C & ~W)
574 @
575 and ip, r1, #L_PTE_USER | L_PTE_WRITE | L_PTE_CACHEABLE
576 teq ip, #L_PTE_USER | L_PTE_CACHEABLE
577 biceq r2, r2, #PTE_BUFFERABLE
578
579 tst r3, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young?
580 movne r2, #0 @ no -> fault
581
582 str r2, [r0] @ hardware version
583 mov ip, #0
584 mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
585 mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
586 mov pc, lr
587
588
589 .ltorg
590
591 .align
592
593 __INIT
594
595 .type __xscale_setup, #function
596__xscale_setup:
597 mcr p15, 0, ip, c7, c7, 0 @ invalidate I, D caches & BTB
598 mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
599 mcr p15, 0, ip, c8, c7, 0 @ invalidate I, D TLBs
600#ifdef CONFIG_IWMMXT
601 mov r0, #0 @ initially disallow access to CP0/CP1
602#else
603 mov r0, #1 @ Allow access to CP0
604#endif
605 orr r0, r0, #1 << 6 @ cp6 for IOP3xx and Bulverde
606 orr r0, r0, #1 << 13 @ Its undefined whether this
607 mcr p15, 0, r0, c15, c1, 0 @ affects USR or SVC modes
608 mrc p15, 0, r0, c1, c0, 0 @ get control register
609 ldr r5, xscale_cr1_clear
610 bic r0, r0, r5
611 ldr r5, xscale_cr1_set
612 orr r0, r0, r5
613 mov pc, lr
614 .size __xscale_setup, . - __xscale_setup
615
616 /*
617 * R
618 * .RVI ZFRS BLDP WCAM
619 * ..11 1.01 .... .101
620 *
621 */
622 .type xscale_cr1_clear, #object
623 .type xscale_cr1_set, #object
624xscale_cr1_clear:
625 .word 0x3b07
626xscale_cr1_set:
627 .word 0x3905
628
629 __INITDATA
630
631/*
632 * Purpose : Function pointers used to access above functions - all calls
633 * come through these
634 */
635
636 .type xscale_processor_functions, #object
637ENTRY(xscale_processor_functions)
638 .word v5t_early_abort
639 .word cpu_xscale_proc_init
640 .word cpu_xscale_proc_fin
641 .word cpu_xscale_reset
642 .word cpu_xscale_do_idle
643 .word cpu_xscale_dcache_clean_area
644 .word cpu_xscale_switch_mm
645 .word cpu_xscale_set_pte
646 .size xscale_processor_functions, . - xscale_processor_functions
647
648 .section ".rodata"
649
650 .type cpu_arch_name, #object
651cpu_arch_name:
652 .asciz "armv5te"
653 .size cpu_arch_name, . - cpu_arch_name
654
655 .type cpu_elf_name, #object
656cpu_elf_name:
657 .asciz "v5"
658 .size cpu_elf_name, . - cpu_elf_name
659
660 .type cpu_80200_name, #object
661cpu_80200_name:
662 .asciz "XScale-80200"
663 .size cpu_80200_name, . - cpu_80200_name
664
665 .type cpu_8032x_name, #object
666cpu_8032x_name:
667 .asciz "XScale-IOP8032x Family"
668 .size cpu_8032x_name, . - cpu_8032x_name
669
670 .type cpu_8033x_name, #object
671cpu_8033x_name:
672 .asciz "XScale-IOP8033x Family"
673 .size cpu_8033x_name, . - cpu_8033x_name
674
675 .type cpu_pxa250_name, #object
676cpu_pxa250_name:
677 .asciz "XScale-PXA250"
678 .size cpu_pxa250_name, . - cpu_pxa250_name
679
680 .type cpu_pxa210_name, #object
681cpu_pxa210_name:
682 .asciz "XScale-PXA210"
683 .size cpu_pxa210_name, . - cpu_pxa210_name
684
685 .type cpu_ixp42x_name, #object
686cpu_ixp42x_name:
687 .asciz "XScale-IXP42x Family"
688 .size cpu_ixp42x_name, . - cpu_ixp42x_name
689
690 .type cpu_ixp46x_name, #object
691cpu_ixp46x_name:
692 .asciz "XScale-IXP46x Family"
693 .size cpu_ixp46x_name, . - cpu_ixp46x_name
694
695 .type cpu_ixp2400_name, #object
696cpu_ixp2400_name:
697 .asciz "XScale-IXP2400"
698 .size cpu_ixp2400_name, . - cpu_ixp2400_name
699
700 .type cpu_ixp2800_name, #object
701cpu_ixp2800_name:
702 .asciz "XScale-IXP2800"
703 .size cpu_ixp2800_name, . - cpu_ixp2800_name
704
705 .type cpu_pxa255_name, #object
706cpu_pxa255_name:
707 .asciz "XScale-PXA255"
708 .size cpu_pxa255_name, . - cpu_pxa255_name
709
710 .type cpu_pxa270_name, #object
711cpu_pxa270_name:
712 .asciz "XScale-PXA270"
713 .size cpu_pxa270_name, . - cpu_pxa270_name
714
715 .align
716
717 .section ".proc.info", #alloc, #execinstr
718
719 .type __80200_proc_info,#object
720__80200_proc_info:
721 .long 0x69052000
722 .long 0xfffffff0
723 .long PMD_TYPE_SECT | \
724 PMD_SECT_BUFFERABLE | \
725 PMD_SECT_CACHEABLE | \
726 PMD_SECT_AP_WRITE | \
727 PMD_SECT_AP_READ
728 b __xscale_setup
729 .long cpu_arch_name
730 .long cpu_elf_name
731 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
732 .long cpu_80200_name
733 .long xscale_processor_functions
734 .long v4wbi_tlb_fns
735 .long xscale_mc_user_fns
736 .long xscale_cache_fns
737 .size __80200_proc_info, . - __80200_proc_info
738
739 .type __8032x_proc_info,#object
740__8032x_proc_info:
741 .long 0x69052420
742 .long 0xfffff5e0 @ mask should accomodate IOP80219 also
743 .long PMD_TYPE_SECT | \
744 PMD_SECT_BUFFERABLE | \
745 PMD_SECT_CACHEABLE | \
746 PMD_SECT_AP_WRITE | \
747 PMD_SECT_AP_READ
748 b __xscale_setup
749 .long cpu_arch_name
750 .long cpu_elf_name
751 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
752 .long cpu_8032x_name
753 .long xscale_processor_functions
754 .long v4wbi_tlb_fns
755 .long xscale_mc_user_fns
756 .long xscale_cache_fns
757 .size __8032x_proc_info, . - __8032x_proc_info
758
759 .type __8033x_proc_info,#object
760__8033x_proc_info:
761 .long 0x69054010
762 .long 0xffffff30
763 .long PMD_TYPE_SECT | \
764 PMD_SECT_BUFFERABLE | \
765 PMD_SECT_CACHEABLE | \
766 PMD_SECT_AP_WRITE | \
767 PMD_SECT_AP_READ
768 b __xscale_setup
769 .long cpu_arch_name
770 .long cpu_elf_name
771 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
772 .long cpu_8033x_name
773 .long xscale_processor_functions
774 .long v4wbi_tlb_fns
775 .long xscale_mc_user_fns
776 .long xscale_cache_fns
777 .size __8033x_proc_info, . - __8033x_proc_info
778
779 .type __pxa250_proc_info,#object
780__pxa250_proc_info:
781 .long 0x69052100
782 .long 0xfffff7f0
783 .long PMD_TYPE_SECT | \
784 PMD_SECT_BUFFERABLE | \
785 PMD_SECT_CACHEABLE | \
786 PMD_SECT_AP_WRITE | \
787 PMD_SECT_AP_READ
788 b __xscale_setup
789 .long cpu_arch_name
790 .long cpu_elf_name
791 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
792 .long cpu_pxa250_name
793 .long xscale_processor_functions
794 .long v4wbi_tlb_fns
795 .long xscale_mc_user_fns
796 .long xscale_cache_fns
797 .size __pxa250_proc_info, . - __pxa250_proc_info
798
799 .type __pxa210_proc_info,#object
800__pxa210_proc_info:
801 .long 0x69052120
802 .long 0xfffff3f0
803 .long PMD_TYPE_SECT | \
804 PMD_SECT_BUFFERABLE | \
805 PMD_SECT_CACHEABLE | \
806 PMD_SECT_AP_WRITE | \
807 PMD_SECT_AP_READ
808 b __xscale_setup
809 .long cpu_arch_name
810 .long cpu_elf_name
811 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
812 .long cpu_pxa210_name
813 .long xscale_processor_functions
814 .long v4wbi_tlb_fns
815 .long xscale_mc_user_fns
816 .long xscale_cache_fns
817 .size __pxa210_proc_info, . - __pxa210_proc_info
818
819 .type __ixp2400_proc_info, #object
820__ixp2400_proc_info:
821 .long 0x69054190
822 .long 0xfffffff0
823 .long PMD_TYPE_SECT | \
824 PMD_SECT_BUFFERABLE | \
825 PMD_SECT_CACHEABLE | \
826 PMD_SECT_AP_WRITE | \
827 PMD_SECT_AP_READ
828 b __xscale_setup
829 .long cpu_arch_name
830 .long cpu_elf_name
831 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
832 .long cpu_ixp2400_name
833 .long xscale_processor_functions
834 .long v4wbi_tlb_fns
835 .long xscale_mc_user_fns
836 .long xscale_cache_fns
837 .size __ixp2400_proc_info, . - __ixp2400_proc_info
838
839 .type __ixp2800_proc_info, #object
840__ixp2800_proc_info:
841 .long 0x690541a0
842 .long 0xfffffff0
843 .long PMD_TYPE_SECT | \
844 PMD_SECT_BUFFERABLE | \
845 PMD_SECT_CACHEABLE | \
846 PMD_SECT_AP_WRITE | \
847 PMD_SECT_AP_READ
848 b __xscale_setup
849 .long cpu_arch_name
850 .long cpu_elf_name
851 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
852 .long cpu_ixp2800_name
853 .long xscale_processor_functions
854 .long v4wbi_tlb_fns
855 .long xscale_mc_user_fns
856 .long xscale_cache_fns
857 .size __ixp2800_proc_info, . - __ixp2800_proc_info
858
859 .type __ixp42x_proc_info, #object
860__ixp42x_proc_info:
861 .long 0x690541c0
862 .long 0xffffffc0
863 .long PMD_TYPE_SECT | \
864 PMD_SECT_BUFFERABLE | \
865 PMD_SECT_CACHEABLE | \
866 PMD_SECT_AP_WRITE | \
867 PMD_SECT_AP_READ
868 b __xscale_setup
869 .long cpu_arch_name
870 .long cpu_elf_name
871 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
872 .long cpu_ixp42x_name
873 .long xscale_processor_functions
874 .long v4wbi_tlb_fns
875 .long xscale_mc_user_fns
876 .long xscale_cache_fns
877 .size __ixp42x_proc_info, . - __ixp42x_proc_info
878
879 .type __ixp46x_proc_info, #object
880__ixp46x_proc_info:
881 .long 0x69054200
882 .long 0xffffff00
883 .long 0x00000c0e
884 b __xscale_setup
885 .long cpu_arch_name
886 .long cpu_elf_name
887 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
888 .long cpu_ixp46x_name
889 .long xscale_processor_functions
890 .long v4wbi_tlb_fns
891 .long xscale_mc_user_fns
892 .long xscale_cache_fns
893 .size __ixp46x_proc_info, . - __ixp46x_proc_info
894
895 .type __pxa255_proc_info,#object
896__pxa255_proc_info:
897 .long 0x69052d00
898 .long 0xfffffff0
899 .long PMD_TYPE_SECT | \
900 PMD_SECT_BUFFERABLE | \
901 PMD_SECT_CACHEABLE | \
902 PMD_SECT_AP_WRITE | \
903 PMD_SECT_AP_READ
904 b __xscale_setup
905 .long cpu_arch_name
906 .long cpu_elf_name
907 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
908 .long cpu_pxa255_name
909 .long xscale_processor_functions
910 .long v4wbi_tlb_fns
911 .long xscale_mc_user_fns
912 .long xscale_cache_fns
913 .size __pxa255_proc_info, . - __pxa255_proc_info
914
915 .type __pxa270_proc_info,#object
916__pxa270_proc_info:
917 .long 0x69054110
918 .long 0xfffffff0
919 .long PMD_TYPE_SECT | \
920 PMD_SECT_BUFFERABLE | \
921 PMD_SECT_CACHEABLE | \
922 PMD_SECT_AP_WRITE | \
923 PMD_SECT_AP_READ
924 b __xscale_setup
925 .long cpu_arch_name
926 .long cpu_elf_name
927 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
928 .long cpu_pxa270_name
929 .long xscale_processor_functions
930 .long v4wbi_tlb_fns
931 .long xscale_mc_user_fns
932 .long xscale_cache_fns
933 .size __pxa270_proc_info, . - __pxa270_proc_info
934
diff --git a/arch/arm/mm/tlb-v3.S b/arch/arm/mm/tlb-v3.S
new file mode 100644
index 000000000000..44b0daeaff9b
--- /dev/null
+++ b/arch/arm/mm/tlb-v3.S
@@ -0,0 +1,52 @@
1/*
2 * linux/arch/arm/mm/tlbv3.S
3 *
4 * Copyright (C) 1997-2002 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ARM architecture version 3 TLB handling functions.
11 *
12 * Processors: ARM610, ARM710.
13 */
14#include <linux/linkage.h>
15#include <linux/init.h>
16#include <asm/constants.h>
17#include <asm/tlbflush.h>
18#include "proc-macros.S"
19
20 .align 5
21/*
22 * v3_flush_user_tlb_range(start, end, mm)
23 *
24 * Invalidate a range of TLB entries in the specified address space.
25 *
26 * - start - range start address
27 * - end - range end address
28 * - mm - mm_struct describing address space
29 */
30 .align 5
31ENTRY(v3_flush_user_tlb_range)
32 vma_vm_mm r2, r2
33 act_mm r3 @ get current->active_mm
34 teq r2, r3 @ == mm ?
35 movne pc, lr @ no, we dont do anything
36ENTRY(v3_flush_kern_tlb_range)
37 bic r0, r0, #0x0ff
38 bic r0, r0, #0xf00
391: mcr p15, 0, r0, c6, c0, 0 @ invalidate TLB entry
40 add r0, r0, #PAGE_SZ
41 cmp r0, r1
42 blo 1b
43 mov pc, lr
44
45 __INITDATA
46
47 .type v3_tlb_fns, #object
48ENTRY(v3_tlb_fns)
49 .long v3_flush_user_tlb_range
50 .long v3_flush_kern_tlb_range
51 .long v3_tlb_flags
52 .size v3_tlb_fns, . - v3_tlb_fns
diff --git a/arch/arm/mm/tlb-v4.S b/arch/arm/mm/tlb-v4.S
new file mode 100644
index 000000000000..db82ee468248
--- /dev/null
+++ b/arch/arm/mm/tlb-v4.S
@@ -0,0 +1,65 @@
1/*
2 * linux/arch/arm/mm/tlbv4.S
3 *
4 * Copyright (C) 1997-2002 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ARM architecture version 4 TLB handling functions.
11 * These assume a split I/D TLBs, and no write buffer.
12 *
13 * Processors: ARM720T
14 */
15#include <linux/linkage.h>
16#include <linux/init.h>
17#include <asm/constants.h>
18#include <asm/tlbflush.h>
19#include "proc-macros.S"
20
21 .align 5
22/*
23 * v4_flush_user_tlb_range(start, end, mm)
24 *
25 * Invalidate a range of TLB entries in the specified user address space.
26 *
27 * - start - range start address
28 * - end - range end address
29 * - mm - mm_struct describing address space
30 */
31 .align 5
32ENTRY(v4_flush_user_tlb_range)
33 vma_vm_mm ip, r2
34 act_mm r3 @ get current->active_mm
35 eors r3, ip, r3 @ == mm ?
36 movne pc, lr @ no, we dont do anything
37.v4_flush_kern_tlb_range:
38 bic r0, r0, #0x0ff
39 bic r0, r0, #0xf00
401: mcr p15, 0, r0, c8, c7, 1 @ invalidate TLB entry
41 add r0, r0, #PAGE_SZ
42 cmp r0, r1
43 blo 1b
44 mov pc, lr
45
46/*
47 * v4_flush_kern_tlb_range(start, end)
48 *
49 * Invalidate a range of TLB entries in the specified kernel
50 * address range.
51 *
52 * - start - virtual address (may not be aligned)
53 * - end - virtual address (may not be aligned)
54 */
55.globl v4_flush_kern_tlb_range
56.equ v4_flush_kern_tlb_range, .v4_flush_kern_tlb_range
57
58 __INITDATA
59
60 .type v4_tlb_fns, #object
61ENTRY(v4_tlb_fns)
62 .long v4_flush_user_tlb_range
63 .long v4_flush_kern_tlb_range
64 .long v4_tlb_flags
65 .size v4_tlb_fns, . - v4_tlb_fns
diff --git a/arch/arm/mm/tlb-v4wb.S b/arch/arm/mm/tlb-v4wb.S
new file mode 100644
index 000000000000..7908d5f1f130
--- /dev/null
+++ b/arch/arm/mm/tlb-v4wb.S
@@ -0,0 +1,77 @@
1/*
2 * linux/arch/arm/mm/tlbv4wb.S
3 *
4 * Copyright (C) 1997-2002 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ARM architecture version 4 TLB handling functions.
11 * These assume a split I/D TLBs w/o I TLB entry, with a write buffer.
12 *
13 * Processors: SA110 SA1100 SA1110
14 */
15#include <linux/linkage.h>
16#include <linux/init.h>
17#include <asm/constants.h>
18#include <asm/tlbflush.h>
19#include "proc-macros.S"
20
21 .align 5
22/*
23 * v4wb_flush_user_tlb_range(start, end, mm)
24 *
25 * Invalidate a range of TLB entries in the specified address space.
26 *
27 * - start - range start address
28 * - end - range end address
29 * - mm - mm_struct describing address space
30 */
31 .align 5
32ENTRY(v4wb_flush_user_tlb_range)
33 vma_vm_mm ip, r2
34 act_mm r3 @ get current->active_mm
35 eors r3, ip, r3 @ == mm ?
36 movne pc, lr @ no, we dont do anything
37 vma_vm_flags r2, r2
38 mcr p15, 0, r3, c7, c10, 4 @ drain WB
39 tst r2, #VM_EXEC
40 mcrne p15, 0, r3, c8, c5, 0 @ invalidate I TLB
41 bic r0, r0, #0x0ff
42 bic r0, r0, #0xf00
431: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry
44 add r0, r0, #PAGE_SZ
45 cmp r0, r1
46 blo 1b
47 mov pc, lr
48
49/*
50 * v4_flush_kern_tlb_range(start, end)
51 *
52 * Invalidate a range of TLB entries in the specified kernel
53 * address range.
54 *
55 * - start - virtual address (may not be aligned)
56 * - end - virtual address (may not be aligned)
57 */
58ENTRY(v4wb_flush_kern_tlb_range)
59 mov r3, #0
60 mcr p15, 0, r3, c7, c10, 4 @ drain WB
61 bic r0, r0, #0x0ff
62 bic r0, r0, #0xf00
63 mcr p15, 0, r3, c8, c5, 0 @ invalidate I TLB
641: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry
65 add r0, r0, #PAGE_SZ
66 cmp r0, r1
67 blo 1b
68 mov pc, lr
69
70 __INITDATA
71
72 .type v4wb_tlb_fns, #object
73ENTRY(v4wb_tlb_fns)
74 .long v4wb_flush_user_tlb_range
75 .long v4wb_flush_kern_tlb_range
76 .long v4wb_tlb_flags
77 .size v4wb_tlb_fns, . - v4wb_tlb_fns
diff --git a/arch/arm/mm/tlb-v4wbi.S b/arch/arm/mm/tlb-v4wbi.S
new file mode 100644
index 000000000000..efbe94bbe1a7
--- /dev/null
+++ b/arch/arm/mm/tlb-v4wbi.S
@@ -0,0 +1,68 @@
1/*
2 * linux/arch/arm/mm/tlbv4wbi.S
3 *
4 * Copyright (C) 1997-2002 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ARM architecture version 4 and version 5 TLB handling functions.
11 * These assume a split I/D TLBs, with a write buffer.
12 *
13 * Processors: ARM920 ARM922 ARM925 ARM926 XScale
14 */
15#include <linux/linkage.h>
16#include <linux/init.h>
17#include <asm/constants.h>
18#include <asm/tlbflush.h>
19#include "proc-macros.S"
20
21/*
22 * v4wb_flush_user_tlb_range(start, end, mm)
23 *
24 * Invalidate a range of TLB entries in the specified address space.
25 *
26 * - start - range start address
27 * - end - range end address
28 * - mm - mm_struct describing address space
29 */
30 .align 5
31ENTRY(v4wbi_flush_user_tlb_range)
32 vma_vm_mm ip, r2
33 act_mm r3 @ get current->active_mm
34 eors r3, ip, r3 @ == mm ?
35 movne pc, lr @ no, we dont do anything
36 mov r3, #0
37 mcr p15, 0, r3, c7, c10, 4 @ drain WB
38 vma_vm_flags r2, r2
39 bic r0, r0, #0x0ff
40 bic r0, r0, #0xf00
411: tst r2, #VM_EXEC
42 mcrne p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry
43 mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry
44 add r0, r0, #PAGE_SZ
45 cmp r0, r1
46 blo 1b
47 mov pc, lr
48
49ENTRY(v4wbi_flush_kern_tlb_range)
50 mov r3, #0
51 mcr p15, 0, r3, c7, c10, 4 @ drain WB
52 bic r0, r0, #0x0ff
53 bic r0, r0, #0xf00
541: mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry
55 mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry
56 add r0, r0, #PAGE_SZ
57 cmp r0, r1
58 blo 1b
59 mov pc, lr
60
61 __INITDATA
62
63 .type v4wbi_tlb_fns, #object
64ENTRY(v4wbi_tlb_fns)
65 .long v4wbi_flush_user_tlb_range
66 .long v4wbi_flush_kern_tlb_range
67 .long v4wbi_tlb_flags
68 .size v4wbi_tlb_fns, . - v4wbi_tlb_fns
diff --git a/arch/arm/mm/tlb-v6.S b/arch/arm/mm/tlb-v6.S
new file mode 100644
index 000000000000..99ed26e78adf
--- /dev/null
+++ b/arch/arm/mm/tlb-v6.S
@@ -0,0 +1,92 @@
1/*
2 * linux/arch/arm/mm/tlb-v6.S
3 *
4 * Copyright (C) 1997-2002 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ARM architecture version 6 TLB handling functions.
11 * These assume a split I/D TLB.
12 */
13#include <linux/linkage.h>
14#include <asm/constants.h>
15#include <asm/page.h>
16#include <asm/tlbflush.h>
17#include "proc-macros.S"
18
19#define HARVARD_TLB
20
21/*
22 * v6wbi_flush_user_tlb_range(start, end, vma)
23 *
24 * Invalidate a range of TLB entries in the specified address space.
25 *
26 * - start - start address (may not be aligned)
27 * - end - end address (exclusive, may not be aligned)
28 * - vma - vma_struct describing address range
29 *
30 * It is assumed that:
31 * - the "Invalidate single entry" instruction will invalidate
32 * both the I and the D TLBs on Harvard-style TLBs
33 */
34ENTRY(v6wbi_flush_user_tlb_range)
35 vma_vm_mm r3, r2 @ get vma->vm_mm
36 mov ip, #0
37 mmid r3, r3 @ get vm_mm->context.id
38 mcr p15, 0, ip, c7, c10, 4 @ drain write buffer
39 mov r0, r0, lsr #PAGE_SHIFT @ align address
40 mov r1, r1, lsr #PAGE_SHIFT
41 asid r3, r3 @ mask ASID
42 orr r0, r3, r0, lsl #PAGE_SHIFT @ Create initial MVA
43 mov r1, r1, lsl #PAGE_SHIFT
44 vma_vm_flags r2, r2 @ get vma->vm_flags
451:
46#ifdef HARVARD_TLB
47 mcr p15, 0, r0, c8, c6, 1 @ TLB invalidate D MVA (was 1)
48 tst r2, #VM_EXEC @ Executable area ?
49 mcrne p15, 0, r0, c8, c5, 1 @ TLB invalidate I MVA (was 1)
50#else
51 mcr p15, 0, r0, c8, c7, 1 @ TLB invalidate MVA (was 1)
52#endif
53 add r0, r0, #PAGE_SZ
54 cmp r0, r1
55 blo 1b
56 mov pc, lr
57
58/*
59 * v6wbi_flush_kern_tlb_range(start,end)
60 *
61 * Invalidate a range of kernel TLB entries
62 *
63 * - start - start address (may not be aligned)
64 * - end - end address (exclusive, may not be aligned)
65 */
66ENTRY(v6wbi_flush_kern_tlb_range)
67 mov r2, #0
68 mcr p15, 0, r2, c7, c10, 4 @ drain write buffer
69 mov r0, r0, lsr #PAGE_SHIFT @ align address
70 mov r1, r1, lsr #PAGE_SHIFT
71 mov r0, r0, lsl #PAGE_SHIFT
72 mov r1, r1, lsl #PAGE_SHIFT
731:
74#ifdef HARVARD_TLB
75 mcr p15, 0, r0, c8, c6, 1 @ TLB invalidate D MVA
76 mcr p15, 0, r0, c8, c5, 1 @ TLB invalidate I MVA
77#else
78 mcr p15, 0, r0, c8, c7, 1 @ TLB invalidate MVA
79#endif
80 add r0, r0, #PAGE_SZ
81 cmp r0, r1
82 blo 1b
83 mov pc, lr
84
85 .section ".text.init", #alloc, #execinstr
86
87 .type v6wbi_tlb_fns, #object
88ENTRY(v6wbi_tlb_fns)
89 .long v6wbi_flush_user_tlb_range
90 .long v6wbi_flush_kern_tlb_range
91 .long v6wbi_tlb_flags
92 .size v6wbi_tlb_fns, . - v6wbi_tlb_fns