aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mm')
-rw-r--r--arch/arm/mm/Kconfig51
-rw-r--r--arch/arm/mm/Makefile6
-rw-r--r--arch/arm/mm/cache-fa.S220
-rw-r--r--arch/arm/mm/cache-feroceon-l2.c54
-rw-r--r--arch/arm/mm/cache-xsc3l2.c107
-rw-r--r--arch/arm/mm/copypage-fa.c86
-rw-r--r--arch/arm/mm/dma-mapping.c72
-rw-r--r--arch/arm/mm/flush.c2
-rw-r--r--arch/arm/mm/highmem.c116
-rw-r--r--arch/arm/mm/init.c21
-rw-r--r--arch/arm/mm/mm.h3
-rw-r--r--arch/arm/mm/mmu.c43
-rw-r--r--arch/arm/mm/proc-fa526.S248
-rw-r--r--arch/arm/mm/proc-mohawk.S416
-rw-r--r--arch/arm/mm/tlb-fa.S75
15 files changed, 1464 insertions, 56 deletions
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index d490f3773c01..20979564e7ee 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -186,6 +186,24 @@ config CPU_ARM926T
186 Say Y if you want support for the ARM926T processor. 186 Say Y if you want support for the ARM926T processor.
187 Otherwise, say N. 187 Otherwise, say N.
188 188
189# FA526
190config CPU_FA526
191 bool
192 select CPU_32v4
193 select CPU_ABRT_EV4
194 select CPU_PABRT_NOIFAR
195 select CPU_CACHE_VIVT
196 select CPU_CP15_MMU
197 select CPU_CACHE_FA
198 select CPU_COPY_FA if MMU
199 select CPU_TLB_FA if MMU
200 help
201 The FA526 is a version of the ARMv4 compatible processor with
202 Branch Target Buffer, Unified TLB and cache line size 16.
203
204 Say Y if you want support for the FA526 processor.
205 Otherwise, say N.
206
189# ARM940T 207# ARM940T
190config CPU_ARM940T 208config CPU_ARM940T
191 bool "Support ARM940T processor" if ARCH_INTEGRATOR 209 bool "Support ARM940T processor" if ARCH_INTEGRATOR
@@ -340,6 +358,17 @@ config CPU_XSC3
340 select CPU_TLB_V4WBI if MMU 358 select CPU_TLB_V4WBI if MMU
341 select IO_36 359 select IO_36
342 360
361# Marvell PJ1 (Mohawk)
362config CPU_MOHAWK
363 bool
364 select CPU_32v5
365 select CPU_ABRT_EV5T
366 select CPU_PABRT_NOIFAR
367 select CPU_CACHE_VIVT
368 select CPU_CP15_MMU
369 select CPU_TLB_V4WBI if MMU
370 select CPU_COPY_V4WB if MMU
371
343# Feroceon 372# Feroceon
344config CPU_FEROCEON 373config CPU_FEROCEON
345 bool 374 bool
@@ -484,6 +513,9 @@ config CPU_CACHE_VIVT
484config CPU_CACHE_VIPT 513config CPU_CACHE_VIPT
485 bool 514 bool
486 515
516config CPU_CACHE_FA
517 bool
518
487if MMU 519if MMU
488# The copy-page model 520# The copy-page model
489config CPU_COPY_V3 521config CPU_COPY_V3
@@ -498,6 +530,9 @@ config CPU_COPY_V4WB
498config CPU_COPY_FEROCEON 530config CPU_COPY_FEROCEON
499 bool 531 bool
500 532
533config CPU_COPY_FA
534 bool
535
501config CPU_COPY_V6 536config CPU_COPY_V6
502 bool 537 bool
503 538
@@ -528,6 +563,13 @@ config CPU_TLB_FEROCEON
528 help 563 help
529 Feroceon TLB (v4wbi with non-outer-cachable page table walks). 564 Feroceon TLB (v4wbi with non-outer-cachable page table walks).
530 565
566config CPU_TLB_FA
567 bool
568 help
569 Faraday ARM FA526 architecture, unified TLB with writeback cache
570 and invalidate instruction cache entry. Branch target buffer is
571 also supported.
572
531config CPU_TLB_V6 573config CPU_TLB_V6
532 bool 574 bool
533 575
@@ -569,7 +611,7 @@ comment "Processor Features"
569 611
570config ARM_THUMB 612config ARM_THUMB
571 bool "Support Thumb user binaries" 613 bool "Support Thumb user binaries"
572 depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_V6 || CPU_V7 || CPU_FEROCEON 614 depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_V6 || CPU_V7 || CPU_FEROCEON
573 default y 615 default y
574 help 616 help
575 Say Y if you want to include kernel support for running user space 617 Say Y if you want to include kernel support for running user space
@@ -638,7 +680,7 @@ config CPU_DCACHE_SIZE
638 680
639config CPU_DCACHE_WRITETHROUGH 681config CPU_DCACHE_WRITETHROUGH
640 bool "Force write through D-cache" 682 bool "Force write through D-cache"
641 depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020) && !CPU_DCACHE_DISABLE 683 depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_FA526) && !CPU_DCACHE_DISABLE
642 default y if CPU_ARM925T 684 default y if CPU_ARM925T
643 help 685 help
644 Say Y here to use the data cache in writethrough mode. Unless you 686 Say Y here to use the data cache in writethrough mode. Unless you
@@ -653,7 +695,7 @@ config CPU_CACHE_ROUND_ROBIN
653 695
654config CPU_BPREDICT_DISABLE 696config CPU_BPREDICT_DISABLE
655 bool "Disable branch prediction" 697 bool "Disable branch prediction"
656 depends on CPU_ARM1020 || CPU_V6 || CPU_XSC3 || CPU_V7 698 depends on CPU_ARM1020 || CPU_V6 || CPU_MOHAWK || CPU_XSC3 || CPU_V7 || CPU_FA526
657 help 699 help
658 Say Y here to disable branch prediction. If unsure, say N. 700 Say Y here to disable branch prediction. If unsure, say N.
659 701
@@ -704,7 +746,8 @@ config CACHE_FEROCEON_L2_WRITETHROUGH
704 746
705config CACHE_L2X0 747config CACHE_L2X0
706 bool "Enable the L2x0 outer cache controller" 748 bool "Enable the L2x0 outer cache controller"
707 depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || REALVIEW_EB_A9MP 749 depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || \
750 REALVIEW_EB_A9MP || ARCH_MX35 || ARCH_MX31
708 default y 751 default y
709 select OUTER_CACHE 752 select OUTER_CACHE
710 help 753 help
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 480f78a3611a..63e3f6dd0e21 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_MODULES) += proc-syms.o
16 16
17obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o 17obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o
18obj-$(CONFIG_DISCONTIGMEM) += discontig.o 18obj-$(CONFIG_DISCONTIGMEM) += discontig.o
19obj-$(CONFIG_HIGHMEM) += highmem.o
19 20
20obj-$(CONFIG_CPU_ABRT_NOMMU) += abort-nommu.o 21obj-$(CONFIG_CPU_ABRT_NOMMU) += abort-nommu.o
21obj-$(CONFIG_CPU_ABRT_EV4) += abort-ev4.o 22obj-$(CONFIG_CPU_ABRT_EV4) += abort-ev4.o
@@ -32,6 +33,7 @@ obj-$(CONFIG_CPU_CACHE_V4WT) += cache-v4wt.o
32obj-$(CONFIG_CPU_CACHE_V4WB) += cache-v4wb.o 33obj-$(CONFIG_CPU_CACHE_V4WB) += cache-v4wb.o
33obj-$(CONFIG_CPU_CACHE_V6) += cache-v6.o 34obj-$(CONFIG_CPU_CACHE_V6) += cache-v6.o
34obj-$(CONFIG_CPU_CACHE_V7) += cache-v7.o 35obj-$(CONFIG_CPU_CACHE_V7) += cache-v7.o
36obj-$(CONFIG_CPU_CACHE_FA) += cache-fa.o
35 37
36obj-$(CONFIG_CPU_COPY_V3) += copypage-v3.o 38obj-$(CONFIG_CPU_COPY_V3) += copypage-v3.o
37obj-$(CONFIG_CPU_COPY_V4WT) += copypage-v4wt.o 39obj-$(CONFIG_CPU_COPY_V4WT) += copypage-v4wt.o
@@ -41,6 +43,7 @@ obj-$(CONFIG_CPU_COPY_V6) += copypage-v6.o context.o
41obj-$(CONFIG_CPU_SA1100) += copypage-v4mc.o 43obj-$(CONFIG_CPU_SA1100) += copypage-v4mc.o
42obj-$(CONFIG_CPU_XSCALE) += copypage-xscale.o 44obj-$(CONFIG_CPU_XSCALE) += copypage-xscale.o
43obj-$(CONFIG_CPU_XSC3) += copypage-xsc3.o 45obj-$(CONFIG_CPU_XSC3) += copypage-xsc3.o
46obj-$(CONFIG_CPU_COPY_FA) += copypage-fa.o
44 47
45obj-$(CONFIG_CPU_TLB_V3) += tlb-v3.o 48obj-$(CONFIG_CPU_TLB_V3) += tlb-v3.o
46obj-$(CONFIG_CPU_TLB_V4WT) += tlb-v4.o 49obj-$(CONFIG_CPU_TLB_V4WT) += tlb-v4.o
@@ -49,6 +52,7 @@ obj-$(CONFIG_CPU_TLB_V4WBI) += tlb-v4wbi.o
49obj-$(CONFIG_CPU_TLB_FEROCEON) += tlb-v4wbi.o # reuse v4wbi TLB functions 52obj-$(CONFIG_CPU_TLB_FEROCEON) += tlb-v4wbi.o # reuse v4wbi TLB functions
50obj-$(CONFIG_CPU_TLB_V6) += tlb-v6.o 53obj-$(CONFIG_CPU_TLB_V6) += tlb-v6.o
51obj-$(CONFIG_CPU_TLB_V7) += tlb-v7.o 54obj-$(CONFIG_CPU_TLB_V7) += tlb-v7.o
55obj-$(CONFIG_CPU_TLB_FA) += tlb-fa.o
52 56
53obj-$(CONFIG_CPU_ARM610) += proc-arm6_7.o 57obj-$(CONFIG_CPU_ARM610) += proc-arm6_7.o
54obj-$(CONFIG_CPU_ARM710) += proc-arm6_7.o 58obj-$(CONFIG_CPU_ARM710) += proc-arm6_7.o
@@ -62,6 +66,7 @@ obj-$(CONFIG_CPU_ARM925T) += proc-arm925.o
62obj-$(CONFIG_CPU_ARM926T) += proc-arm926.o 66obj-$(CONFIG_CPU_ARM926T) += proc-arm926.o
63obj-$(CONFIG_CPU_ARM940T) += proc-arm940.o 67obj-$(CONFIG_CPU_ARM940T) += proc-arm940.o
64obj-$(CONFIG_CPU_ARM946E) += proc-arm946.o 68obj-$(CONFIG_CPU_ARM946E) += proc-arm946.o
69obj-$(CONFIG_CPU_FA526) += proc-fa526.o
65obj-$(CONFIG_CPU_ARM1020) += proc-arm1020.o 70obj-$(CONFIG_CPU_ARM1020) += proc-arm1020.o
66obj-$(CONFIG_CPU_ARM1020E) += proc-arm1020e.o 71obj-$(CONFIG_CPU_ARM1020E) += proc-arm1020e.o
67obj-$(CONFIG_CPU_ARM1022) += proc-arm1022.o 72obj-$(CONFIG_CPU_ARM1022) += proc-arm1022.o
@@ -70,6 +75,7 @@ obj-$(CONFIG_CPU_SA110) += proc-sa110.o
70obj-$(CONFIG_CPU_SA1100) += proc-sa1100.o 75obj-$(CONFIG_CPU_SA1100) += proc-sa1100.o
71obj-$(CONFIG_CPU_XSCALE) += proc-xscale.o 76obj-$(CONFIG_CPU_XSCALE) += proc-xscale.o
72obj-$(CONFIG_CPU_XSC3) += proc-xsc3.o 77obj-$(CONFIG_CPU_XSC3) += proc-xsc3.o
78obj-$(CONFIG_CPU_MOHAWK) += proc-mohawk.o
73obj-$(CONFIG_CPU_FEROCEON) += proc-feroceon.o 79obj-$(CONFIG_CPU_FEROCEON) += proc-feroceon.o
74obj-$(CONFIG_CPU_V6) += proc-v6.o 80obj-$(CONFIG_CPU_V6) += proc-v6.o
75obj-$(CONFIG_CPU_V7) += proc-v7.o 81obj-$(CONFIG_CPU_V7) += proc-v7.o
diff --git a/arch/arm/mm/cache-fa.S b/arch/arm/mm/cache-fa.S
new file mode 100644
index 000000000000..b63a8f7b95cf
--- /dev/null
+++ b/arch/arm/mm/cache-fa.S
@@ -0,0 +1,220 @@
1/*
2 * linux/arch/arm/mm/cache-fa.S
3 *
4 * Copyright (C) 2005 Faraday Corp.
5 * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
6 *
7 * Based on cache-v4wb.S:
8 * Copyright (C) 1997-2002 Russell king
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 * Processors: FA520 FA526 FA626
15 */
16#include <linux/linkage.h>
17#include <linux/init.h>
18#include <asm/memory.h>
19#include <asm/page.h>
20
21#include "proc-macros.S"
22
23/*
24 * The size of one data cache line.
25 */
26#define CACHE_DLINESIZE 16
27
28/*
29 * The total size of the data cache.
30 */
31#ifdef CONFIG_ARCH_GEMINI
32#define CACHE_DSIZE 8192
33#else
34#define CACHE_DSIZE 16384
35#endif
36
37/* FIXME: put optimal value here. Current one is just estimation */
38#define CACHE_DLIMIT (CACHE_DSIZE * 2)
39
40/*
41 * flush_user_cache_all()
42 *
43 * Clean and invalidate all cache entries in a particular address
44 * space.
45 */
46ENTRY(fa_flush_user_cache_all)
47 /* FALLTHROUGH */
48/*
49 * flush_kern_cache_all()
50 *
51 * Clean and invalidate the entire cache.
52 */
53ENTRY(fa_flush_kern_cache_all)
54 mov ip, #0
55 mov r2, #VM_EXEC
56__flush_whole_cache:
57 mcr p15, 0, ip, c7, c14, 0 @ clean/invalidate D cache
58 tst r2, #VM_EXEC
59 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
60 mcrne p15, 0, ip, c7, c5, 6 @ invalidate BTB
61 mcrne p15, 0, ip, c7, c10, 4 @ drain write buffer
62 mcrne p15, 0, ip, c7, c5, 4 @ prefetch flush
63 mov pc, lr
64
65/*
66 * flush_user_cache_range(start, end, flags)
67 *
68 * Invalidate a range of cache entries in the specified
69 * address space.
70 *
71 * - start - start address (inclusive, page aligned)
72 * - end - end address (exclusive, page aligned)
73 * - flags - vma_area_struct flags describing address space
74 */
75ENTRY(fa_flush_user_cache_range)
76 mov ip, #0
77 sub r3, r1, r0 @ calculate total size
78 cmp r3, #CACHE_DLIMIT @ total size >= limit?
79 bhs __flush_whole_cache @ flush whole D cache
80
811: tst r2, #VM_EXEC
82 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I line
83 mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry
84 add r0, r0, #CACHE_DLINESIZE
85 cmp r0, r1
86 blo 1b
87 tst r2, #VM_EXEC
88 mcrne p15, 0, ip, c7, c5, 6 @ invalidate BTB
89 mcrne p15, 0, ip, c7, c10, 4 @ data write barrier
90 mcrne p15, 0, ip, c7, c5, 4 @ prefetch flush
91 mov pc, lr
92
93/*
94 * coherent_kern_range(start, end)
95 *
96 * Ensure coherency between the Icache and the Dcache in the
97 * region described by start. If you have non-snooping
98 * Harvard caches, you need to implement this function.
99 *
100 * - start - virtual start address
101 * - end - virtual end address
102 */
103ENTRY(fa_coherent_kern_range)
104 /* fall through */
105
106/*
107 * coherent_user_range(start, end)
108 *
109 * Ensure coherency between the Icache and the Dcache in the
110 * region described by start. If you have non-snooping
111 * Harvard caches, you need to implement this function.
112 *
113 * - start - virtual start address
114 * - end - virtual end address
115 */
116ENTRY(fa_coherent_user_range)
117 bic r0, r0, #CACHE_DLINESIZE - 1
1181: mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry
119 mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry
120 add r0, r0, #CACHE_DLINESIZE
121 cmp r0, r1
122 blo 1b
123 mov r0, #0
124 mcr p15, 0, r0, c7, c5, 6 @ invalidate BTB
125 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
126 mcr p15, 0, r0, c7, c5, 4 @ prefetch flush
127 mov pc, lr
128
129/*
130 * flush_kern_dcache_page(kaddr)
131 *
132 * Ensure that the data held in the page kaddr is written back
133 * to the page in question.
134 *
135 * - kaddr - kernel address (guaranteed to be page aligned)
136 */
137ENTRY(fa_flush_kern_dcache_page)
138 add r1, r0, #PAGE_SZ
1391: mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D line
140 add r0, r0, #CACHE_DLINESIZE
141 cmp r0, r1
142 blo 1b
143 mov r0, #0
144 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
145 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
146 mov pc, lr
147
148/*
149 * dma_inv_range(start, end)
150 *
151 * Invalidate (discard) the specified virtual address range.
152 * May not write back any entries. If 'start' or 'end'
153 * are not cache line aligned, those lines must be written
154 * back.
155 *
156 * - start - virtual start address
157 * - end - virtual end address
158 */
159ENTRY(fa_dma_inv_range)
160 tst r0, #CACHE_DLINESIZE - 1
161 bic r0, r0, #CACHE_DLINESIZE - 1
162 mcrne p15, 0, r0, c7, c14, 1 @ clean & invalidate D entry
163 tst r1, #CACHE_DLINESIZE - 1
164 bic r1, r1, #CACHE_DLINESIZE - 1
165 mcrne p15, 0, r1, c7, c14, 1 @ clean & invalidate 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 mov r0, #0
171 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
172 mov pc, lr
173
174/*
175 * dma_clean_range(start, end)
176 *
177 * Clean (write back) the specified virtual address range.
178 *
179 * - start - virtual start address
180 * - end - virtual end address
181 */
182ENTRY(fa_dma_clean_range)
183 bic r0, r0, #CACHE_DLINESIZE - 1
1841: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
185 add r0, r0, #CACHE_DLINESIZE
186 cmp r0, r1
187 blo 1b
188 mov r0, #0
189 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
190 mov pc, lr
191
192/*
193 * dma_flush_range(start,end)
194 * - start - virtual start address of region
195 * - end - virtual end address of region
196 */
197ENTRY(fa_dma_flush_range)
198 bic r0, r0, #CACHE_DLINESIZE - 1
1991: mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D entry
200 add r0, r0, #CACHE_DLINESIZE
201 cmp r0, r1
202 blo 1b
203 mov r0, #0
204 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
205 mov pc, lr
206
207 __INITDATA
208
209 .type fa_cache_fns, #object
210ENTRY(fa_cache_fns)
211 .long fa_flush_kern_cache_all
212 .long fa_flush_user_cache_all
213 .long fa_flush_user_cache_range
214 .long fa_coherent_kern_range
215 .long fa_coherent_user_range
216 .long fa_flush_kern_dcache_page
217 .long fa_dma_inv_range
218 .long fa_dma_clean_range
219 .long fa_dma_flush_range
220 .size fa_cache_fns, . - fa_cache_fns
diff --git a/arch/arm/mm/cache-feroceon-l2.c b/arch/arm/mm/cache-feroceon-l2.c
index 80cd207cbaea..d6dd83826f8a 100644
--- a/arch/arm/mm/cache-feroceon-l2.c
+++ b/arch/arm/mm/cache-feroceon-l2.c
@@ -14,8 +14,12 @@
14 14
15#include <linux/init.h> 15#include <linux/init.h>
16#include <asm/cacheflush.h> 16#include <asm/cacheflush.h>
17#include <asm/kmap_types.h>
18#include <asm/fixmap.h>
19#include <asm/pgtable.h>
20#include <asm/tlbflush.h>
17#include <plat/cache-feroceon-l2.h> 21#include <plat/cache-feroceon-l2.h>
18 22#include "mm.h"
19 23
20/* 24/*
21 * Low-level cache maintenance operations. 25 * Low-level cache maintenance operations.
@@ -34,14 +38,36 @@
34 * The range operations require two successive cp15 writes, in 38 * The range operations require two successive cp15 writes, in
35 * between which we don't want to be preempted. 39 * between which we don't want to be preempted.
36 */ 40 */
41
42static inline unsigned long l2_start_va(unsigned long paddr)
43{
44#ifdef CONFIG_HIGHMEM
45 /*
46 * Let's do our own fixmap stuff in a minimal way here.
47 * Because range ops can't be done on physical addresses,
48 * we simply install a virtual mapping for it only for the
49 * TLB lookup to occur, hence no need to flush the untouched
50 * memory mapping. This is protected with the disabling of
51 * interrupts by the caller.
52 */
53 unsigned long idx = KM_L2_CACHE + KM_TYPE_NR * smp_processor_id();
54 unsigned long vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
55 set_pte_ext(TOP_PTE(vaddr), pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL), 0);
56 local_flush_tlb_kernel_page(vaddr);
57 return vaddr + (paddr & ~PAGE_MASK);
58#else
59 return __phys_to_virt(paddr);
60#endif
61}
62
37static inline void l2_clean_pa(unsigned long addr) 63static inline void l2_clean_pa(unsigned long addr)
38{ 64{
39 __asm__("mcr p15, 1, %0, c15, c9, 3" : : "r" (addr)); 65 __asm__("mcr p15, 1, %0, c15, c9, 3" : : "r" (addr));
40} 66}
41 67
42static inline void l2_clean_mva_range(unsigned long start, unsigned long end) 68static inline void l2_clean_pa_range(unsigned long start, unsigned long end)
43{ 69{
44 unsigned long flags; 70 unsigned long va_start, va_end, flags;
45 71
46 /* 72 /*
47 * Make sure 'start' and 'end' reference the same page, as 73 * Make sure 'start' and 'end' reference the same page, as
@@ -51,17 +77,14 @@ static inline void l2_clean_mva_range(unsigned long start, unsigned long end)
51 BUG_ON((start ^ end) >> PAGE_SHIFT); 77 BUG_ON((start ^ end) >> PAGE_SHIFT);
52 78
53 raw_local_irq_save(flags); 79 raw_local_irq_save(flags);
80 va_start = l2_start_va(start);
81 va_end = va_start + (end - start);
54 __asm__("mcr p15, 1, %0, c15, c9, 4\n\t" 82 __asm__("mcr p15, 1, %0, c15, c9, 4\n\t"
55 "mcr p15, 1, %1, c15, c9, 5" 83 "mcr p15, 1, %1, c15, c9, 5"
56 : : "r" (start), "r" (end)); 84 : : "r" (va_start), "r" (va_end));
57 raw_local_irq_restore(flags); 85 raw_local_irq_restore(flags);
58} 86}
59 87
60static inline void l2_clean_pa_range(unsigned long start, unsigned long end)
61{
62 l2_clean_mva_range(__phys_to_virt(start), __phys_to_virt(end));
63}
64
65static inline void l2_clean_inv_pa(unsigned long addr) 88static inline void l2_clean_inv_pa(unsigned long addr)
66{ 89{
67 __asm__("mcr p15, 1, %0, c15, c10, 3" : : "r" (addr)); 90 __asm__("mcr p15, 1, %0, c15, c10, 3" : : "r" (addr));
@@ -72,9 +95,9 @@ static inline void l2_inv_pa(unsigned long addr)
72 __asm__("mcr p15, 1, %0, c15, c11, 3" : : "r" (addr)); 95 __asm__("mcr p15, 1, %0, c15, c11, 3" : : "r" (addr));
73} 96}
74 97
75static inline void l2_inv_mva_range(unsigned long start, unsigned long end) 98static inline void l2_inv_pa_range(unsigned long start, unsigned long end)
76{ 99{
77 unsigned long flags; 100 unsigned long va_start, va_end, flags;
78 101
79 /* 102 /*
80 * Make sure 'start' and 'end' reference the same page, as 103 * Make sure 'start' and 'end' reference the same page, as
@@ -84,17 +107,14 @@ static inline void l2_inv_mva_range(unsigned long start, unsigned long end)
84 BUG_ON((start ^ end) >> PAGE_SHIFT); 107 BUG_ON((start ^ end) >> PAGE_SHIFT);
85 108
86 raw_local_irq_save(flags); 109 raw_local_irq_save(flags);
110 va_start = l2_start_va(start);
111 va_end = va_start + (end - start);
87 __asm__("mcr p15, 1, %0, c15, c11, 4\n\t" 112 __asm__("mcr p15, 1, %0, c15, c11, 4\n\t"
88 "mcr p15, 1, %1, c15, c11, 5" 113 "mcr p15, 1, %1, c15, c11, 5"
89 : : "r" (start), "r" (end)); 114 : : "r" (va_start), "r" (va_end));
90 raw_local_irq_restore(flags); 115 raw_local_irq_restore(flags);
91} 116}
92 117
93static inline void l2_inv_pa_range(unsigned long start, unsigned long end)
94{
95 l2_inv_mva_range(__phys_to_virt(start), __phys_to_virt(end));
96}
97
98 118
99/* 119/*
100 * Linux primitives. 120 * Linux primitives.
diff --git a/arch/arm/mm/cache-xsc3l2.c b/arch/arm/mm/cache-xsc3l2.c
index 464de893a988..5d180cb0bd94 100644
--- a/arch/arm/mm/cache-xsc3l2.c
+++ b/arch/arm/mm/cache-xsc3l2.c
@@ -17,12 +17,14 @@
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */ 18 */
19#include <linux/init.h> 19#include <linux/init.h>
20#include <linux/spinlock.h>
21#include <linux/io.h>
22
23#include <asm/system.h> 20#include <asm/system.h>
24#include <asm/cputype.h> 21#include <asm/cputype.h>
25#include <asm/cacheflush.h> 22#include <asm/cacheflush.h>
23#include <asm/kmap_types.h>
24#include <asm/fixmap.h>
25#include <asm/pgtable.h>
26#include <asm/tlbflush.h>
27#include "mm.h"
26 28
27#define CR_L2 (1 << 26) 29#define CR_L2 (1 << 26)
28 30
@@ -47,21 +49,11 @@ static inline void xsc3_l2_clean_mva(unsigned long addr)
47 __asm__("mcr p15, 1, %0, c7, c11, 1" : : "r" (addr)); 49 __asm__("mcr p15, 1, %0, c7, c11, 1" : : "r" (addr));
48} 50}
49 51
50static inline void xsc3_l2_clean_pa(unsigned long addr)
51{
52 xsc3_l2_clean_mva(__phys_to_virt(addr));
53}
54
55static inline void xsc3_l2_inv_mva(unsigned long addr) 52static inline void xsc3_l2_inv_mva(unsigned long addr)
56{ 53{
57 __asm__("mcr p15, 1, %0, c7, c7, 1" : : "r" (addr)); 54 __asm__("mcr p15, 1, %0, c7, c7, 1" : : "r" (addr));
58} 55}
59 56
60static inline void xsc3_l2_inv_pa(unsigned long addr)
61{
62 xsc3_l2_inv_mva(__phys_to_virt(addr));
63}
64
65static inline void xsc3_l2_inv_all(void) 57static inline void xsc3_l2_inv_all(void)
66{ 58{
67 unsigned long l2ctype, set_way; 59 unsigned long l2ctype, set_way;
@@ -79,50 +71,103 @@ static inline void xsc3_l2_inv_all(void)
79 dsb(); 71 dsb();
80} 72}
81 73
74#ifdef CONFIG_HIGHMEM
75#define l2_map_save_flags(x) raw_local_save_flags(x)
76#define l2_map_restore_flags(x) raw_local_irq_restore(x)
77#else
78#define l2_map_save_flags(x) ((x) = 0)
79#define l2_map_restore_flags(x) ((void)(x))
80#endif
81
82static inline unsigned long l2_map_va(unsigned long pa, unsigned long prev_va,
83 unsigned long flags)
84{
85#ifdef CONFIG_HIGHMEM
86 unsigned long va = prev_va & PAGE_MASK;
87 unsigned long pa_offset = pa << (32 - PAGE_SHIFT);
88 if (unlikely(pa_offset < (prev_va << (32 - PAGE_SHIFT)))) {
89 /*
90 * Switching to a new page. Because cache ops are
91 * using virtual addresses only, we must put a mapping
92 * in place for it. We also enable interrupts for a
93 * short while and disable them again to protect this
94 * mapping.
95 */
96 unsigned long idx;
97 raw_local_irq_restore(flags);
98 idx = KM_L2_CACHE + KM_TYPE_NR * smp_processor_id();
99 va = __fix_to_virt(FIX_KMAP_BEGIN + idx);
100 raw_local_irq_restore(flags | PSR_I_BIT);
101 set_pte_ext(TOP_PTE(va), pfn_pte(pa >> PAGE_SHIFT, PAGE_KERNEL), 0);
102 local_flush_tlb_kernel_page(va);
103 }
104 return va + (pa_offset >> (32 - PAGE_SHIFT));
105#else
106 return __phys_to_virt(pa);
107#endif
108}
109
82static void xsc3_l2_inv_range(unsigned long start, unsigned long end) 110static void xsc3_l2_inv_range(unsigned long start, unsigned long end)
83{ 111{
112 unsigned long vaddr, flags;
113
84 if (start == 0 && end == -1ul) { 114 if (start == 0 && end == -1ul) {
85 xsc3_l2_inv_all(); 115 xsc3_l2_inv_all();
86 return; 116 return;
87 } 117 }
88 118
119 vaddr = -1; /* to force the first mapping */
120 l2_map_save_flags(flags);
121
89 /* 122 /*
90 * Clean and invalidate partial first cache line. 123 * Clean and invalidate partial first cache line.
91 */ 124 */
92 if (start & (CACHE_LINE_SIZE - 1)) { 125 if (start & (CACHE_LINE_SIZE - 1)) {
93 xsc3_l2_clean_pa(start & ~(CACHE_LINE_SIZE - 1)); 126 vaddr = l2_map_va(start & ~(CACHE_LINE_SIZE - 1), vaddr, flags);
94 xsc3_l2_inv_pa(start & ~(CACHE_LINE_SIZE - 1)); 127 xsc3_l2_clean_mva(vaddr);
128 xsc3_l2_inv_mva(vaddr);
95 start = (start | (CACHE_LINE_SIZE - 1)) + 1; 129 start = (start | (CACHE_LINE_SIZE - 1)) + 1;
96 } 130 }
97 131
98 /* 132 /*
99 * Clean and invalidate partial last cache line. 133 * Invalidate all full cache lines between 'start' and 'end'.
100 */ 134 */
101 if (start < end && (end & (CACHE_LINE_SIZE - 1))) { 135 while (start < (end & ~(CACHE_LINE_SIZE - 1))) {
102 xsc3_l2_clean_pa(end & ~(CACHE_LINE_SIZE - 1)); 136 vaddr = l2_map_va(start, vaddr, flags);
103 xsc3_l2_inv_pa(end & ~(CACHE_LINE_SIZE - 1)); 137 xsc3_l2_inv_mva(vaddr);
104 end &= ~(CACHE_LINE_SIZE - 1); 138 start += CACHE_LINE_SIZE;
105 } 139 }
106 140
107 /* 141 /*
108 * Invalidate all full cache lines between 'start' and 'end'. 142 * Clean and invalidate partial last cache line.
109 */ 143 */
110 while (start < end) { 144 if (start < end) {
111 xsc3_l2_inv_pa(start); 145 vaddr = l2_map_va(start, vaddr, flags);
112 start += CACHE_LINE_SIZE; 146 xsc3_l2_clean_mva(vaddr);
147 xsc3_l2_inv_mva(vaddr);
113 } 148 }
114 149
150 l2_map_restore_flags(flags);
151
115 dsb(); 152 dsb();
116} 153}
117 154
118static void xsc3_l2_clean_range(unsigned long start, unsigned long end) 155static void xsc3_l2_clean_range(unsigned long start, unsigned long end)
119{ 156{
157 unsigned long vaddr, flags;
158
159 vaddr = -1; /* to force the first mapping */
160 l2_map_save_flags(flags);
161
120 start &= ~(CACHE_LINE_SIZE - 1); 162 start &= ~(CACHE_LINE_SIZE - 1);
121 while (start < end) { 163 while (start < end) {
122 xsc3_l2_clean_pa(start); 164 vaddr = l2_map_va(start, vaddr, flags);
165 xsc3_l2_clean_mva(vaddr);
123 start += CACHE_LINE_SIZE; 166 start += CACHE_LINE_SIZE;
124 } 167 }
125 168
169 l2_map_restore_flags(flags);
170
126 dsb(); 171 dsb();
127} 172}
128 173
@@ -148,18 +193,26 @@ static inline void xsc3_l2_flush_all(void)
148 193
149static void xsc3_l2_flush_range(unsigned long start, unsigned long end) 194static void xsc3_l2_flush_range(unsigned long start, unsigned long end)
150{ 195{
196 unsigned long vaddr, flags;
197
151 if (start == 0 && end == -1ul) { 198 if (start == 0 && end == -1ul) {
152 xsc3_l2_flush_all(); 199 xsc3_l2_flush_all();
153 return; 200 return;
154 } 201 }
155 202
203 vaddr = -1; /* to force the first mapping */
204 l2_map_save_flags(flags);
205
156 start &= ~(CACHE_LINE_SIZE - 1); 206 start &= ~(CACHE_LINE_SIZE - 1);
157 while (start < end) { 207 while (start < end) {
158 xsc3_l2_clean_pa(start); 208 vaddr = l2_map_va(start, vaddr, flags);
159 xsc3_l2_inv_pa(start); 209 xsc3_l2_clean_mva(vaddr);
210 xsc3_l2_inv_mva(vaddr);
160 start += CACHE_LINE_SIZE; 211 start += CACHE_LINE_SIZE;
161 } 212 }
162 213
214 l2_map_restore_flags(flags);
215
163 dsb(); 216 dsb();
164} 217}
165 218
diff --git a/arch/arm/mm/copypage-fa.c b/arch/arm/mm/copypage-fa.c
new file mode 100644
index 000000000000..b2a6008b0111
--- /dev/null
+++ b/arch/arm/mm/copypage-fa.c
@@ -0,0 +1,86 @@
1/*
2 * linux/arch/arm/lib/copypage-fa.S
3 *
4 * Copyright (C) 2005 Faraday Corp.
5 * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
6 *
7 * Based on copypage-v4wb.S:
8 * Copyright (C) 1995-1999 Russell King
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/init.h>
15#include <linux/highmem.h>
16
17/*
18 * Faraday optimised copy_user_page
19 */
20static void __naked
21fa_copy_user_page(void *kto, const void *kfrom)
22{
23 asm("\
24 stmfd sp!, {r4, lr} @ 2\n\
25 mov r2, %0 @ 1\n\
261: ldmia r1!, {r3, r4, ip, lr} @ 4\n\
27 stmia r0, {r3, r4, ip, lr} @ 4\n\
28 mcr p15, 0, r0, c7, c14, 1 @ 1 clean and invalidate D line\n\
29 add r0, r0, #16 @ 1\n\
30 ldmia r1!, {r3, r4, ip, lr} @ 4\n\
31 stmia r0, {r3, r4, ip, lr} @ 4\n\
32 mcr p15, 0, r0, c7, c14, 1 @ 1 clean and invalidate D line\n\
33 add r0, r0, #16 @ 1\n\
34 subs r2, r2, #1 @ 1\n\
35 bne 1b @ 1\n\
36 mcr p15, 0, r2, c7, c10, 4 @ 1 drain WB\n\
37 ldmfd sp!, {r4, pc} @ 3"
38 :
39 : "I" (PAGE_SIZE / 32));
40}
41
42void fa_copy_user_highpage(struct page *to, struct page *from,
43 unsigned long vaddr)
44{
45 void *kto, *kfrom;
46
47 kto = kmap_atomic(to, KM_USER0);
48 kfrom = kmap_atomic(from, KM_USER1);
49 fa_copy_user_page(kto, kfrom);
50 kunmap_atomic(kfrom, KM_USER1);
51 kunmap_atomic(kto, KM_USER0);
52}
53
54/*
55 * Faraday optimised clear_user_page
56 *
57 * Same story as above.
58 */
59void fa_clear_user_highpage(struct page *page, unsigned long vaddr)
60{
61 void *ptr, *kaddr = kmap_atomic(page, KM_USER0);
62 asm volatile("\
63 mov r1, %2 @ 1\n\
64 mov r2, #0 @ 1\n\
65 mov r3, #0 @ 1\n\
66 mov ip, #0 @ 1\n\
67 mov lr, #0 @ 1\n\
681: stmia %0, {r2, r3, ip, lr} @ 4\n\
69 mcr p15, 0, %0, c7, c14, 1 @ 1 clean and invalidate D line\n\
70 add %0, %0, #16 @ 1\n\
71 stmia %0, {r2, r3, ip, lr} @ 4\n\
72 mcr p15, 0, %0, c7, c14, 1 @ 1 clean and invalidate D line\n\
73 add %0, %0, #16 @ 1\n\
74 subs r1, r1, #1 @ 1\n\
75 bne 1b @ 1\n\
76 mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB"
77 : "=r" (ptr)
78 : "0" (kaddr), "I" (PAGE_SIZE / 32)
79 : "r1", "r2", "r3", "ip", "lr");
80 kunmap_atomic(kaddr, KM_USER0);
81}
82
83struct cpu_user_fns fa_user_fns __initdata = {
84 .cpu_clear_user_highpage = fa_clear_user_highpage,
85 .cpu_copy_user_highpage = fa_copy_user_highpage,
86};
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index f1ef5613ccd4..510c179b0ac8 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -19,6 +19,7 @@
19#include <linux/dma-mapping.h> 19#include <linux/dma-mapping.h>
20 20
21#include <asm/memory.h> 21#include <asm/memory.h>
22#include <asm/highmem.h>
22#include <asm/cacheflush.h> 23#include <asm/cacheflush.h>
23#include <asm/tlbflush.h> 24#include <asm/tlbflush.h>
24#include <asm/sizes.h> 25#include <asm/sizes.h>
@@ -517,6 +518,74 @@ void dma_cache_maint(const void *start, size_t size, int direction)
517} 518}
518EXPORT_SYMBOL(dma_cache_maint); 519EXPORT_SYMBOL(dma_cache_maint);
519 520
521static void dma_cache_maint_contiguous(struct page *page, unsigned long offset,
522 size_t size, int direction)
523{
524 void *vaddr;
525 unsigned long paddr;
526 void (*inner_op)(const void *, const void *);
527 void (*outer_op)(unsigned long, unsigned long);
528
529 switch (direction) {
530 case DMA_FROM_DEVICE: /* invalidate only */
531 inner_op = dmac_inv_range;
532 outer_op = outer_inv_range;
533 break;
534 case DMA_TO_DEVICE: /* writeback only */
535 inner_op = dmac_clean_range;
536 outer_op = outer_clean_range;
537 break;
538 case DMA_BIDIRECTIONAL: /* writeback and invalidate */
539 inner_op = dmac_flush_range;
540 outer_op = outer_flush_range;
541 break;
542 default:
543 BUG();
544 }
545
546 if (!PageHighMem(page)) {
547 vaddr = page_address(page) + offset;
548 inner_op(vaddr, vaddr + size);
549 } else {
550 vaddr = kmap_high_get(page);
551 if (vaddr) {
552 vaddr += offset;
553 inner_op(vaddr, vaddr + size);
554 kunmap_high(page);
555 }
556 }
557
558 paddr = page_to_phys(page) + offset;
559 outer_op(paddr, paddr + size);
560}
561
562void dma_cache_maint_page(struct page *page, unsigned long offset,
563 size_t size, int dir)
564{
565 /*
566 * A single sg entry may refer to multiple physically contiguous
567 * pages. But we still need to process highmem pages individually.
568 * If highmem is not configured then the bulk of this loop gets
569 * optimized out.
570 */
571 size_t left = size;
572 do {
573 size_t len = left;
574 if (PageHighMem(page) && len + offset > PAGE_SIZE) {
575 if (offset >= PAGE_SIZE) {
576 page += offset / PAGE_SIZE;
577 offset %= PAGE_SIZE;
578 }
579 len = PAGE_SIZE - offset;
580 }
581 dma_cache_maint_contiguous(page, offset, len, dir);
582 offset = 0;
583 page++;
584 left -= len;
585 } while (left);
586}
587EXPORT_SYMBOL(dma_cache_maint_page);
588
520/** 589/**
521 * dma_map_sg - map a set of SG buffers for streaming mode DMA 590 * dma_map_sg - map a set of SG buffers for streaming mode DMA
522 * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices 591 * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
@@ -614,7 +683,8 @@ void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
614 continue; 683 continue;
615 684
616 if (!arch_is_coherent()) 685 if (!arch_is_coherent())
617 dma_cache_maint(sg_virt(s), s->length, dir); 686 dma_cache_maint_page(sg_page(s), s->offset,
687 s->length, dir);
618 } 688 }
619} 689}
620EXPORT_SYMBOL(dma_sync_sg_for_device); 690EXPORT_SYMBOL(dma_sync_sg_for_device);
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index 0fa9bf388f0b..4e283481cee1 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -192,7 +192,7 @@ void flush_dcache_page(struct page *page)
192 struct address_space *mapping = page_mapping(page); 192 struct address_space *mapping = page_mapping(page);
193 193
194#ifndef CONFIG_SMP 194#ifndef CONFIG_SMP
195 if (mapping && !mapping_mapped(mapping)) 195 if (!PageHighMem(page) && mapping && !mapping_mapped(mapping))
196 set_bit(PG_dcache_dirty, &page->flags); 196 set_bit(PG_dcache_dirty, &page->flags);
197 else 197 else
198#endif 198#endif
diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c
new file mode 100644
index 000000000000..a34954d9df7d
--- /dev/null
+++ b/arch/arm/mm/highmem.c
@@ -0,0 +1,116 @@
1/*
2 * arch/arm/mm/highmem.c -- ARM highmem support
3 *
4 * Author: Nicolas Pitre
5 * Created: september 8, 2008
6 * Copyright: Marvell Semiconductors 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
13#include <linux/module.h>
14#include <linux/highmem.h>
15#include <linux/interrupt.h>
16#include <asm/fixmap.h>
17#include <asm/cacheflush.h>
18#include <asm/tlbflush.h>
19#include "mm.h"
20
21void *kmap(struct page *page)
22{
23 might_sleep();
24 if (!PageHighMem(page))
25 return page_address(page);
26 return kmap_high(page);
27}
28EXPORT_SYMBOL(kmap);
29
30void kunmap(struct page *page)
31{
32 BUG_ON(in_interrupt());
33 if (!PageHighMem(page))
34 return;
35 kunmap_high(page);
36}
37EXPORT_SYMBOL(kunmap);
38
39void *kmap_atomic(struct page *page, enum km_type type)
40{
41 unsigned int idx;
42 unsigned long vaddr;
43
44 pagefault_disable();
45 if (!PageHighMem(page))
46 return page_address(page);
47
48 idx = type + KM_TYPE_NR * smp_processor_id();
49 vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
50#ifdef CONFIG_DEBUG_HIGHMEM
51 /*
52 * With debugging enabled, kunmap_atomic forces that entry to 0.
53 * Make sure it was indeed properly unmapped.
54 */
55 BUG_ON(!pte_none(*(TOP_PTE(vaddr))));
56#endif
57 set_pte_ext(TOP_PTE(vaddr), mk_pte(page, kmap_prot), 0);
58 /*
59 * When debugging is off, kunmap_atomic leaves the previous mapping
60 * in place, so this TLB flush ensures the TLB is updated with the
61 * new mapping.
62 */
63 local_flush_tlb_kernel_page(vaddr);
64
65 return (void *)vaddr;
66}
67EXPORT_SYMBOL(kmap_atomic);
68
69void kunmap_atomic(void *kvaddr, enum km_type type)
70{
71 unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
72 unsigned int idx = type + KM_TYPE_NR * smp_processor_id();
73
74 if (kvaddr >= (void *)FIXADDR_START) {
75 __cpuc_flush_dcache_page((void *)vaddr);
76#ifdef CONFIG_DEBUG_HIGHMEM
77 BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
78 set_pte_ext(TOP_PTE(vaddr), __pte(0), 0);
79 local_flush_tlb_kernel_page(vaddr);
80#else
81 (void) idx; /* to kill a warning */
82#endif
83 }
84 pagefault_enable();
85}
86EXPORT_SYMBOL(kunmap_atomic);
87
88void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
89{
90 unsigned int idx;
91 unsigned long vaddr;
92
93 pagefault_disable();
94
95 idx = type + KM_TYPE_NR * smp_processor_id();
96 vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
97#ifdef CONFIG_DEBUG_HIGHMEM
98 BUG_ON(!pte_none(*(TOP_PTE(vaddr))));
99#endif
100 set_pte_ext(TOP_PTE(vaddr), pfn_pte(pfn, kmap_prot), 0);
101 local_flush_tlb_kernel_page(vaddr);
102
103 return (void *)vaddr;
104}
105
106struct page *kmap_atomic_to_page(const void *ptr)
107{
108 unsigned long vaddr = (unsigned long)ptr;
109 pte_t *pte;
110
111 if (vaddr < FIXADDR_START)
112 return virt_to_page(ptr);
113
114 pte = TOP_PTE(vaddr);
115 return pte_page(*pte);
116}
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 80fd3b69ae1f..8277802ec859 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -15,6 +15,7 @@
15#include <linux/mman.h> 15#include <linux/mman.h>
16#include <linux/nodemask.h> 16#include <linux/nodemask.h>
17#include <linux/initrd.h> 17#include <linux/initrd.h>
18#include <linux/highmem.h>
18 19
19#include <asm/mach-types.h> 20#include <asm/mach-types.h>
20#include <asm/sections.h> 21#include <asm/sections.h>
@@ -485,7 +486,7 @@ void __init mem_init(void)
485 int i, node; 486 int i, node;
486 487
487#ifndef CONFIG_DISCONTIGMEM 488#ifndef CONFIG_DISCONTIGMEM
488 max_mapnr = virt_to_page(high_memory) - mem_map; 489 max_mapnr = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map;
489#endif 490#endif
490 491
491 /* this will put all unused low memory onto the freelists */ 492 /* this will put all unused low memory onto the freelists */
@@ -504,6 +505,19 @@ void __init mem_init(void)
504 __phys_to_pfn(__pa(swapper_pg_dir)), NULL); 505 __phys_to_pfn(__pa(swapper_pg_dir)), NULL);
505#endif 506#endif
506 507
508#ifdef CONFIG_HIGHMEM
509 /* set highmem page free */
510 for_each_online_node(node) {
511 for_each_nodebank (i, &meminfo, node) {
512 unsigned long start = bank_pfn_start(&meminfo.bank[i]);
513 unsigned long end = bank_pfn_end(&meminfo.bank[i]);
514 if (start >= max_low_pfn + PHYS_PFN_OFFSET)
515 totalhigh_pages += free_area(start, end, NULL);
516 }
517 }
518 totalram_pages += totalhigh_pages;
519#endif
520
507 /* 521 /*
508 * Since our memory may not be contiguous, calculate the 522 * Since our memory may not be contiguous, calculate the
509 * real number of pages we have in this system 523 * real number of pages we have in this system
@@ -521,9 +535,10 @@ void __init mem_init(void)
521 initsize = __init_end - __init_begin; 535 initsize = __init_end - __init_begin;
522 536
523 printk(KERN_NOTICE "Memory: %luKB available (%dK code, " 537 printk(KERN_NOTICE "Memory: %luKB available (%dK code, "
524 "%dK data, %dK init)\n", 538 "%dK data, %dK init, %luK highmem)\n",
525 (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), 539 (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
526 codesize >> 10, datasize >> 10, initsize >> 10); 540 codesize >> 10, datasize >> 10, initsize >> 10,
541 (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)));
527 542
528 if (PAGE_SIZE >= 16384 && num_physpages <= 128) { 543 if (PAGE_SIZE >= 16384 && num_physpages <= 128) {
529 extern int sysctl_overcommit_memory; 544 extern int sysctl_overcommit_memory;
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
index 95bbe112965e..c4f6f05198e0 100644
--- a/arch/arm/mm/mm.h
+++ b/arch/arm/mm/mm.h
@@ -1,7 +1,6 @@
1/* the upper-most page table pointer */
2
3#ifdef CONFIG_MMU 1#ifdef CONFIG_MMU
4 2
3/* the upper-most page table pointer */
5extern pmd_t *top_pmd; 4extern pmd_t *top_pmd;
6 5
7#define TOP_PTE(x) pte_offset_kernel(top_pmd, x) 6#define TOP_PTE(x) pte_offset_kernel(top_pmd, x)
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index d4d082c5c2d4..b438fc4fb77b 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -18,9 +18,11 @@
18#include <asm/cputype.h> 18#include <asm/cputype.h>
19#include <asm/mach-types.h> 19#include <asm/mach-types.h>
20#include <asm/sections.h> 20#include <asm/sections.h>
21#include <asm/cachetype.h>
21#include <asm/setup.h> 22#include <asm/setup.h>
22#include <asm/sizes.h> 23#include <asm/sizes.h>
23#include <asm/tlb.h> 24#include <asm/tlb.h>
25#include <asm/highmem.h>
24 26
25#include <asm/mach/arch.h> 27#include <asm/mach/arch.h>
26#include <asm/mach/map.h> 28#include <asm/mach/map.h>
@@ -243,6 +245,10 @@ static struct mem_type mem_types[] = {
243 .prot_sect = PMD_TYPE_SECT, 245 .prot_sect = PMD_TYPE_SECT,
244 .domain = DOMAIN_KERNEL, 246 .domain = DOMAIN_KERNEL,
245 }, 247 },
248 [MT_MEMORY_NONCACHED] = {
249 .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
250 .domain = DOMAIN_KERNEL,
251 },
246}; 252};
247 253
248const struct mem_type *get_mem_type(unsigned int type) 254const struct mem_type *get_mem_type(unsigned int type)
@@ -406,9 +412,28 @@ static void __init build_mem_type_table(void)
406 kern_pgprot |= L_PTE_SHARED; 412 kern_pgprot |= L_PTE_SHARED;
407 vecs_pgprot |= L_PTE_SHARED; 413 vecs_pgprot |= L_PTE_SHARED;
408 mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S; 414 mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S;
415 mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_S;
409#endif 416#endif
410 } 417 }
411 418
419 /*
420 * Non-cacheable Normal - intended for memory areas that must
421 * not cause dirty cache line writebacks when used
422 */
423 if (cpu_arch >= CPU_ARCH_ARMv6) {
424 if (cpu_arch >= CPU_ARCH_ARMv7 && (cr & CR_TRE)) {
425 /* Non-cacheable Normal is XCB = 001 */
426 mem_types[MT_MEMORY_NONCACHED].prot_sect |=
427 PMD_SECT_BUFFERED;
428 } else {
429 /* For both ARMv6 and non-TEX-remapping ARMv7 */
430 mem_types[MT_MEMORY_NONCACHED].prot_sect |=
431 PMD_SECT_TEX(1);
432 }
433 } else {
434 mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_BUFFERABLE;
435 }
436
412 for (i = 0; i < 16; i++) { 437 for (i = 0; i < 16; i++) {
413 unsigned long v = pgprot_val(protection_map[i]); 438 unsigned long v = pgprot_val(protection_map[i]);
414 protection_map[i] = __pgprot(v | user_pgprot); 439 protection_map[i] = __pgprot(v | user_pgprot);
@@ -677,6 +702,10 @@ static void __init sanity_check_meminfo(void)
677 if (meminfo.nr_banks >= NR_BANKS) { 702 if (meminfo.nr_banks >= NR_BANKS) {
678 printk(KERN_CRIT "NR_BANKS too low, " 703 printk(KERN_CRIT "NR_BANKS too low, "
679 "ignoring high memory\n"); 704 "ignoring high memory\n");
705 } else if (cache_is_vipt_aliasing()) {
706 printk(KERN_CRIT "HIGHMEM is not yet supported "
707 "with VIPT aliasing cache, "
708 "ignoring high memory\n");
680 } else { 709 } else {
681 memmove(bank + 1, bank, 710 memmove(bank + 1, bank,
682 (meminfo.nr_banks - i) * sizeof(*bank)); 711 (meminfo.nr_banks - i) * sizeof(*bank));
@@ -694,7 +723,7 @@ static void __init sanity_check_meminfo(void)
694 * the vmalloc area. 723 * the vmalloc area.
695 */ 724 */
696 if (__va(bank->start) >= VMALLOC_MIN || 725 if (__va(bank->start) >= VMALLOC_MIN ||
697 __va(bank->start) < PAGE_OFFSET) { 726 __va(bank->start) < (void *)PAGE_OFFSET) {
698 printk(KERN_NOTICE "Ignoring RAM at %.8lx-%.8lx " 727 printk(KERN_NOTICE "Ignoring RAM at %.8lx-%.8lx "
699 "(vmalloc region overlap).\n", 728 "(vmalloc region overlap).\n",
700 bank->start, bank->start + bank->size - 1); 729 bank->start, bank->start + bank->size - 1);
@@ -895,6 +924,17 @@ static void __init devicemaps_init(struct machine_desc *mdesc)
895 flush_cache_all(); 924 flush_cache_all();
896} 925}
897 926
927static void __init kmap_init(void)
928{
929#ifdef CONFIG_HIGHMEM
930 pmd_t *pmd = pmd_off_k(PKMAP_BASE);
931 pte_t *pte = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * sizeof(pte_t));
932 BUG_ON(!pmd_none(*pmd) || !pte);
933 __pmd_populate(pmd, __pa(pte) | _PAGE_KERNEL_TABLE);
934 pkmap_page_table = pte + PTRS_PER_PTE;
935#endif
936}
937
898/* 938/*
899 * paging_init() sets up the page tables, initialises the zone memory 939 * paging_init() sets up the page tables, initialises the zone memory
900 * maps, and sets up the zero page, bad page and bad page tables. 940 * maps, and sets up the zero page, bad page and bad page tables.
@@ -908,6 +948,7 @@ void __init paging_init(struct machine_desc *mdesc)
908 prepare_page_table(); 948 prepare_page_table();
909 bootmem_init(); 949 bootmem_init();
910 devicemaps_init(mdesc); 950 devicemaps_init(mdesc);
951 kmap_init();
911 952
912 top_pmd = pmd_off_k(0xffff0000); 953 top_pmd = pmd_off_k(0xffff0000);
913 954
diff --git a/arch/arm/mm/proc-fa526.S b/arch/arm/mm/proc-fa526.S
new file mode 100644
index 000000000000..08b8a955d5d7
--- /dev/null
+++ b/arch/arm/mm/proc-fa526.S
@@ -0,0 +1,248 @@
1/*
2 * linux/arch/arm/mm/proc-fa526.S: MMU functions for FA526
3 *
4 * Written by : Luke Lee
5 * Copyright (C) 2005 Faraday Corp.
6 * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
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 *
14 * These are the low level assembler for performing cache and TLB
15 * functions on the fa526.
16 */
17#include <linux/linkage.h>
18#include <linux/init.h>
19#include <asm/assembler.h>
20#include <asm/hwcap.h>
21#include <asm/pgtable-hwdef.h>
22#include <asm/pgtable.h>
23#include <asm/page.h>
24#include <asm/ptrace.h>
25#include <asm/system.h>
26
27#include "proc-macros.S"
28
29#define CACHE_DLINESIZE 16
30
31 .text
32/*
33 * cpu_fa526_proc_init()
34 */
35ENTRY(cpu_fa526_proc_init)
36 mov pc, lr
37
38/*
39 * cpu_fa526_proc_fin()
40 */
41ENTRY(cpu_fa526_proc_fin)
42 stmfd sp!, {lr}
43 mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
44 msr cpsr_c, ip
45 bl fa_flush_kern_cache_all
46 mrc p15, 0, r0, c1, c0, 0 @ ctrl register
47 bic r0, r0, #0x1000 @ ...i............
48 bic r0, r0, #0x000e @ ............wca.
49 mcr p15, 0, r0, c1, c0, 0 @ disable caches
50 nop
51 nop
52 ldmfd sp!, {pc}
53
54/*
55 * cpu_fa526_reset(loc)
56 *
57 * Perform a soft reset of the system. Put the CPU into the
58 * same state as it would be if it had been reset, and branch
59 * to what would be the reset vector.
60 *
61 * loc: location to jump to for soft reset
62 */
63 .align 4
64ENTRY(cpu_fa526_reset)
65/* TODO: Use CP8 if possible... */
66 mov ip, #0
67 mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
68 mcr p15, 0, ip, c7, c10, 4 @ drain WB
69#ifdef CONFIG_MMU
70 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
71#endif
72 mrc p15, 0, ip, c1, c0, 0 @ ctrl register
73 bic ip, ip, #0x000f @ ............wcam
74 bic ip, ip, #0x1100 @ ...i...s........
75 bic ip, ip, #0x0800 @ BTB off
76 mcr p15, 0, ip, c1, c0, 0 @ ctrl register
77 nop
78 nop
79 mov pc, r0
80
81/*
82 * cpu_fa526_do_idle()
83 */
84 .align 4
85ENTRY(cpu_fa526_do_idle)
86 mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt
87 mov pc, lr
88
89
90ENTRY(cpu_fa526_dcache_clean_area)
911: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
92 add r0, r0, #CACHE_DLINESIZE
93 subs r1, r1, #CACHE_DLINESIZE
94 bhi 1b
95 mcr p15, 0, r0, c7, c10, 4 @ drain WB
96 mov pc, lr
97
98/* =============================== PageTable ============================== */
99
100/*
101 * cpu_fa526_switch_mm(pgd)
102 *
103 * Set the translation base pointer to be as described by pgd.
104 *
105 * pgd: new page tables
106 */
107 .align 4
108ENTRY(cpu_fa526_switch_mm)
109#ifdef CONFIG_MMU
110 mov ip, #0
111#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
112 mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache
113#else
114 mcr p15, 0, ip, c7, c14, 0 @ clean and invalidate whole D cache
115#endif
116 mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache
117 mcr p15, 0, ip, c7, c5, 6 @ invalidate BTB since mm changed
118 mcr p15, 0, ip, c7, c10, 4 @ data write barrier
119 mcr p15, 0, ip, c7, c5, 4 @ prefetch flush
120 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
121 mcr p15, 0, ip, c8, c7, 0 @ invalidate UTLB
122#endif
123 mov pc, lr
124
125/*
126 * cpu_fa526_set_pte_ext(ptep, pte, ext)
127 *
128 * Set a PTE and flush it out
129 */
130 .align 4
131ENTRY(cpu_fa526_set_pte_ext)
132#ifdef CONFIG_MMU
133 armv3_set_pte_ext
134 mov r0, r0
135 mcr p15, 0, r0, c7, c10, 1 @ clean D entry
136 mov r0, #0
137 mcr p15, 0, r0, c7, c10, 4 @ drain WB
138#endif
139 mov pc, lr
140
141 __INIT
142
143 .type __fa526_setup, #function
144__fa526_setup:
145 /* On return of this routine, r0 must carry correct flags for CFG register */
146 mov r0, #0
147 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4
148 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
149#ifdef CONFIG_MMU
150 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
151#endif
152 mcr p15, 0, r0, c7, c5, 5 @ invalidate IScratchpad RAM
153
154 mov r0, #1
155 mcr p15, 0, r0, c1, c1, 0 @ turn-on ECR
156
157 mov r0, #0
158 mcr p15, 0, r0, c7, c5, 6 @ invalidate BTB All
159 mcr p15, 0, r0, c7, c10, 4 @ data write barrier
160 mcr p15, 0, r0, c7, c5, 4 @ prefetch flush
161
162 mov r0, #0x1f @ Domains 0, 1 = manager, 2 = client
163 mcr p15, 0, r0, c3, c0 @ load domain access register
164
165 mrc p15, 0, r0, c1, c0 @ get control register v4
166 ldr r5, fa526_cr1_clear
167 bic r0, r0, r5
168 ldr r5, fa526_cr1_set
169 orr r0, r0, r5
170 mov pc, lr
171 .size __fa526_setup, . - __fa526_setup
172
173 /*
174 * .RVI ZFRS BLDP WCAM
175 * ..11 1001 .111 1101
176 *
177 */
178 .type fa526_cr1_clear, #object
179 .type fa526_cr1_set, #object
180fa526_cr1_clear:
181 .word 0x3f3f
182fa526_cr1_set:
183 .word 0x397D
184
185 __INITDATA
186
187/*
188 * Purpose : Function pointers used to access above functions - all calls
189 * come through these
190 */
191 .type fa526_processor_functions, #object
192fa526_processor_functions:
193 .word v4_early_abort
194 .word pabort_noifar
195 .word cpu_fa526_proc_init
196 .word cpu_fa526_proc_fin
197 .word cpu_fa526_reset
198 .word cpu_fa526_do_idle
199 .word cpu_fa526_dcache_clean_area
200 .word cpu_fa526_switch_mm
201 .word cpu_fa526_set_pte_ext
202 .size fa526_processor_functions, . - fa526_processor_functions
203
204 .section ".rodata"
205
206 .type cpu_arch_name, #object
207cpu_arch_name:
208 .asciz "armv4"
209 .size cpu_arch_name, . - cpu_arch_name
210
211 .type cpu_elf_name, #object
212cpu_elf_name:
213 .asciz "v4"
214 .size cpu_elf_name, . - cpu_elf_name
215
216 .type cpu_fa526_name, #object
217cpu_fa526_name:
218 .asciz "FA526"
219 .size cpu_fa526_name, . - cpu_fa526_name
220
221 .align
222
223 .section ".proc.info.init", #alloc, #execinstr
224
225 .type __fa526_proc_info,#object
226__fa526_proc_info:
227 .long 0x66015261
228 .long 0xff01fff1
229 .long PMD_TYPE_SECT | \
230 PMD_SECT_BUFFERABLE | \
231 PMD_SECT_CACHEABLE | \
232 PMD_BIT4 | \
233 PMD_SECT_AP_WRITE | \
234 PMD_SECT_AP_READ
235 .long PMD_TYPE_SECT | \
236 PMD_BIT4 | \
237 PMD_SECT_AP_WRITE | \
238 PMD_SECT_AP_READ
239 b __fa526_setup
240 .long cpu_arch_name
241 .long cpu_elf_name
242 .long HWCAP_SWP | HWCAP_HALF
243 .long cpu_fa526_name
244 .long fa526_processor_functions
245 .long fa_tlb_fns
246 .long fa_user_fns
247 .long fa_cache_fns
248 .size __fa526_proc_info, . - __fa526_proc_info
diff --git a/arch/arm/mm/proc-mohawk.S b/arch/arm/mm/proc-mohawk.S
new file mode 100644
index 000000000000..540f5078496b
--- /dev/null
+++ b/arch/arm/mm/proc-mohawk.S
@@ -0,0 +1,416 @@
1/*
2 * linux/arch/arm/mm/proc-mohawk.S: MMU functions for Marvell PJ1 core
3 *
4 * PJ1 (codename Mohawk) is a hybrid of the xscale3 and Marvell's own core.
5 *
6 * Heavily based on proc-arm926.S and proc-xsc3.S
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#include <linux/linkage.h>
24#include <linux/init.h>
25#include <asm/assembler.h>
26#include <asm/hwcap.h>
27#include <asm/pgtable-hwdef.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
35 * area is larger than this, then we flush the whole cache.
36 */
37#define CACHE_DLIMIT 32768
38
39/*
40 * The cache line size of the L1 D cache.
41 */
42#define CACHE_DLINESIZE 32
43
44/*
45 * cpu_mohawk_proc_init()
46 */
47ENTRY(cpu_mohawk_proc_init)
48 mov pc, lr
49
50/*
51 * cpu_mohawk_proc_fin()
52 */
53ENTRY(cpu_mohawk_proc_fin)
54 stmfd sp!, {lr}
55 mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
56 msr cpsr_c, ip
57 bl mohawk_flush_kern_cache_all
58 mrc p15, 0, r0, c1, c0, 0 @ ctrl register
59 bic r0, r0, #0x1800 @ ...iz...........
60 bic r0, r0, #0x0006 @ .............ca.
61 mcr p15, 0, r0, c1, c0, 0 @ disable caches
62 ldmfd sp!, {pc}
63
64/*
65 * cpu_mohawk_reset(loc)
66 *
67 * Perform a soft reset of the system. Put the CPU into the
68 * same state as it would be if it had been reset, and branch
69 * to what would be the reset vector.
70 *
71 * loc: location to jump to for soft reset
72 *
73 * (same as arm926)
74 */
75 .align 5
76ENTRY(cpu_mohawk_reset)
77 mov ip, #0
78 mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
79 mcr p15, 0, ip, c7, c10, 4 @ drain WB
80 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
81 mrc p15, 0, ip, c1, c0, 0 @ ctrl register
82 bic ip, ip, #0x0007 @ .............cam
83 bic ip, ip, #0x1100 @ ...i...s........
84 mcr p15, 0, ip, c1, c0, 0 @ ctrl register
85 mov pc, r0
86
87/*
88 * cpu_mohawk_do_idle()
89 *
90 * Called with IRQs disabled
91 */
92 .align 5
93ENTRY(cpu_mohawk_do_idle)
94 mov r0, #0
95 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
96 mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt
97 mov pc, lr
98
99/*
100 * flush_user_cache_all()
101 *
102 * Clean and invalidate all cache entries in a particular
103 * address space.
104 */
105ENTRY(mohawk_flush_user_cache_all)
106 /* FALLTHROUGH */
107
108/*
109 * flush_kern_cache_all()
110 *
111 * Clean and invalidate the entire cache.
112 */
113ENTRY(mohawk_flush_kern_cache_all)
114 mov r2, #VM_EXEC
115 mov ip, #0
116__flush_whole_cache:
117 mcr p15, 0, ip, c7, c14, 0 @ clean & invalidate all D cache
118 tst r2, #VM_EXEC
119 mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
120 mcrne p15, 0, ip, c7, c10, 0 @ drain write buffer
121 mov pc, lr
122
123/*
124 * flush_user_cache_range(start, end, flags)
125 *
126 * Clean and invalidate a range of cache entries in the
127 * specified address range.
128 *
129 * - start - start address (inclusive)
130 * - end - end address (exclusive)
131 * - flags - vm_flags describing address space
132 *
133 * (same as arm926)
134 */
135ENTRY(mohawk_flush_user_cache_range)
136 mov ip, #0
137 sub r3, r1, r0 @ calculate total size
138 cmp r3, #CACHE_DLIMIT
139 bgt __flush_whole_cache
1401: tst r2, #VM_EXEC
141 mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry
142 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
143 add r0, r0, #CACHE_DLINESIZE
144 mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry
145 mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
146 add r0, r0, #CACHE_DLINESIZE
147 cmp r0, r1
148 blo 1b
149 tst r2, #VM_EXEC
150 mcrne p15, 0, ip, c7, c10, 4 @ drain WB
151 mov pc, lr
152
153/*
154 * coherent_kern_range(start, end)
155 *
156 * Ensure coherency between the Icache and the Dcache in the
157 * region described by start, end. If you have non-snooping
158 * Harvard caches, you need to implement this function.
159 *
160 * - start - virtual start address
161 * - end - virtual end address
162 */
163ENTRY(mohawk_coherent_kern_range)
164 /* FALLTHROUGH */
165
166/*
167 * coherent_user_range(start, end)
168 *
169 * Ensure coherency between the Icache and the Dcache in the
170 * region described by start, end. If you have non-snooping
171 * Harvard caches, you need to implement this function.
172 *
173 * - start - virtual start address
174 * - end - virtual end address
175 *
176 * (same as arm926)
177 */
178ENTRY(mohawk_coherent_user_range)
179 bic r0, r0, #CACHE_DLINESIZE - 1
1801: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
181 mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry
182 add r0, r0, #CACHE_DLINESIZE
183 cmp r0, r1
184 blo 1b
185 mcr p15, 0, r0, c7, c10, 4 @ drain WB
186 mov pc, lr
187
188/*
189 * flush_kern_dcache_page(void *page)
190 *
191 * Ensure no D cache aliasing occurs, either with itself or
192 * the I cache
193 *
194 * - addr - page aligned address
195 */
196ENTRY(mohawk_flush_kern_dcache_page)
197 add r1, r0, #PAGE_SZ
1981: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
199 add r0, r0, #CACHE_DLINESIZE
200 cmp r0, r1
201 blo 1b
202 mov r0, #0
203 mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
204 mcr p15, 0, r0, c7, c10, 4 @ drain WB
205 mov pc, lr
206
207/*
208 * dma_inv_range(start, end)
209 *
210 * Invalidate (discard) the specified virtual address range.
211 * May not write back any entries. If 'start' or 'end'
212 * are not cache line aligned, those lines must be written
213 * back.
214 *
215 * - start - virtual start address
216 * - end - virtual end address
217 *
218 * (same as v4wb)
219 */
220ENTRY(mohawk_dma_inv_range)
221 tst r0, #CACHE_DLINESIZE - 1
222 mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
223 tst r1, #CACHE_DLINESIZE - 1
224 mcrne p15, 0, r1, c7, c10, 1 @ clean D entry
225 bic r0, r0, #CACHE_DLINESIZE - 1
2261: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
227 add r0, r0, #CACHE_DLINESIZE
228 cmp r0, r1
229 blo 1b
230 mcr p15, 0, r0, c7, c10, 4 @ drain WB
231 mov pc, lr
232
233/*
234 * dma_clean_range(start, end)
235 *
236 * Clean the specified virtual address range.
237 *
238 * - start - virtual start address
239 * - end - virtual end address
240 *
241 * (same as v4wb)
242 */
243ENTRY(mohawk_dma_clean_range)
244 bic r0, r0, #CACHE_DLINESIZE - 1
2451: mcr p15, 0, r0, c7, c10, 1 @ clean 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_flush_range(start, end)
254 *
255 * Clean and invalidate the specified virtual address range.
256 *
257 * - start - virtual start address
258 * - end - virtual end address
259 */
260ENTRY(mohawk_dma_flush_range)
261 bic r0, r0, #CACHE_DLINESIZE - 1
2621:
263 mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
264 add r0, r0, #CACHE_DLINESIZE
265 cmp r0, r1
266 blo 1b
267 mcr p15, 0, r0, c7, c10, 4 @ drain WB
268 mov pc, lr
269
270ENTRY(mohawk_cache_fns)
271 .long mohawk_flush_kern_cache_all
272 .long mohawk_flush_user_cache_all
273 .long mohawk_flush_user_cache_range
274 .long mohawk_coherent_kern_range
275 .long mohawk_coherent_user_range
276 .long mohawk_flush_kern_dcache_page
277 .long mohawk_dma_inv_range
278 .long mohawk_dma_clean_range
279 .long mohawk_dma_flush_range
280
281ENTRY(cpu_mohawk_dcache_clean_area)
2821: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
283 add r0, r0, #CACHE_DLINESIZE
284 subs r1, r1, #CACHE_DLINESIZE
285 bhi 1b
286 mcr p15, 0, r0, c7, c10, 4 @ drain WB
287 mov pc, lr
288
289/*
290 * cpu_mohawk_switch_mm(pgd)
291 *
292 * Set the translation base pointer to be as described by pgd.
293 *
294 * pgd: new page tables
295 */
296 .align 5
297ENTRY(cpu_mohawk_switch_mm)
298 mov ip, #0
299 mcr p15, 0, ip, c7, c14, 0 @ clean & invalidate all D cache
300 mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache
301 mcr p15, 0, ip, c7, c10, 4 @ drain WB
302 orr r0, r0, #0x18 @ cache the page table in L2
303 mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
304 mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
305 mov pc, lr
306
307/*
308 * cpu_mohawk_set_pte_ext(ptep, pte, ext)
309 *
310 * Set a PTE and flush it out
311 */
312 .align 5
313ENTRY(cpu_mohawk_set_pte_ext)
314 armv3_set_pte_ext
315 mov r0, r0
316 mcr p15, 0, r0, c7, c10, 1 @ clean D entry
317 mcr p15, 0, r0, c7, c10, 4 @ drain WB
318 mov pc, lr
319
320 __INIT
321
322 .type __mohawk_setup, #function
323__mohawk_setup:
324 mov r0, #0
325 mcr p15, 0, r0, c7, c7 @ invalidate I,D caches
326 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
327 mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs
328 orr r4, r4, #0x18 @ cache the page table in L2
329 mcr p15, 0, r4, c2, c0, 0 @ load page table pointer
330
331 mov r0, #0 @ don't allow CP access
332 mcr p15, 0, r0, c15, c1, 0 @ write CP access register
333
334 adr r5, mohawk_crval
335 ldmia r5, {r5, r6}
336 mrc p15, 0, r0, c1, c0 @ get control register
337 bic r0, r0, r5
338 orr r0, r0, r6
339 mov pc, lr
340
341 .size __mohawk_setup, . - __mohawk_setup
342
343 /*
344 * R
345 * .RVI ZFRS BLDP WCAM
346 * .011 1001 ..00 0101
347 *
348 */
349 .type mohawk_crval, #object
350mohawk_crval:
351 crval clear=0x00007f3f, mmuset=0x00003905, ucset=0x00001134
352
353 __INITDATA
354
355/*
356 * Purpose : Function pointers used to access above functions - all calls
357 * come through these
358 */
359 .type mohawk_processor_functions, #object
360mohawk_processor_functions:
361 .word v5t_early_abort
362 .word pabort_noifar
363 .word cpu_mohawk_proc_init
364 .word cpu_mohawk_proc_fin
365 .word cpu_mohawk_reset
366 .word cpu_mohawk_do_idle
367 .word cpu_mohawk_dcache_clean_area
368 .word cpu_mohawk_switch_mm
369 .word cpu_mohawk_set_pte_ext
370 .size mohawk_processor_functions, . - mohawk_processor_functions
371
372 .section ".rodata"
373
374 .type cpu_arch_name, #object
375cpu_arch_name:
376 .asciz "armv5te"
377 .size cpu_arch_name, . - cpu_arch_name
378
379 .type cpu_elf_name, #object
380cpu_elf_name:
381 .asciz "v5"
382 .size cpu_elf_name, . - cpu_elf_name
383
384 .type cpu_mohawk_name, #object
385cpu_mohawk_name:
386 .asciz "Marvell 88SV331x"
387 .size cpu_mohawk_name, . - cpu_mohawk_name
388
389 .align
390
391 .section ".proc.info.init", #alloc, #execinstr
392
393 .type __88sv331x_proc_info,#object
394__88sv331x_proc_info:
395 .long 0x56158000 @ Marvell 88SV331x (MOHAWK)
396 .long 0xfffff000
397 .long PMD_TYPE_SECT | \
398 PMD_SECT_BUFFERABLE | \
399 PMD_SECT_CACHEABLE | \
400 PMD_BIT4 | \
401 PMD_SECT_AP_WRITE | \
402 PMD_SECT_AP_READ
403 .long PMD_TYPE_SECT | \
404 PMD_BIT4 | \
405 PMD_SECT_AP_WRITE | \
406 PMD_SECT_AP_READ
407 b __mohawk_setup
408 .long cpu_arch_name
409 .long cpu_elf_name
410 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
411 .long cpu_mohawk_name
412 .long mohawk_processor_functions
413 .long v4wbi_tlb_fns
414 .long v4wb_user_fns
415 .long mohawk_cache_fns
416 .size __88sv331x_proc_info, . - __88sv331x_proc_info
diff --git a/arch/arm/mm/tlb-fa.S b/arch/arm/mm/tlb-fa.S
new file mode 100644
index 000000000000..9694f1f6f485
--- /dev/null
+++ b/arch/arm/mm/tlb-fa.S
@@ -0,0 +1,75 @@
1/*
2 * linux/arch/arm/mm/tlb-fa.S
3 *
4 * Copyright (C) 2005 Faraday Corp.
5 * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
6 *
7 * Based on tlb-v4wbi.S:
8 * Copyright (C) 1997-2002 Russell King
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 * ARM architecture version 4, Faraday variation.
15 * This assume an unified TLBs, with a write buffer, and branch target buffer (BTB)
16 *
17 * Processors: FA520 FA526 FA626
18 */
19#include <linux/linkage.h>
20#include <linux/init.h>
21#include <asm/asm-offsets.h>
22#include <asm/tlbflush.h>
23#include "proc-macros.S"
24
25
26/*
27 * flush_user_tlb_range(start, end, mm)
28 *
29 * Invalidate a range of TLB entries in the specified address space.
30 *
31 * - start - range start address
32 * - end - range end address
33 * - mm - mm_struct describing address space
34 */
35 .align 4
36ENTRY(fa_flush_user_tlb_range)
37 vma_vm_mm ip, r2
38 act_mm r3 @ get current->active_mm
39 eors r3, ip, r3 @ == mm ?
40 movne pc, lr @ no, we dont do anything
41 mov r3, #0
42 mcr p15, 0, r3, c7, c10, 4 @ drain WB
43 bic r0, r0, #0x0ff
44 bic r0, r0, #0xf00
451: mcr p15, 0, r0, c8, c7, 1 @ invalidate UTLB entry
46 add r0, r0, #PAGE_SZ
47 cmp r0, r1
48 blo 1b
49 mcr p15, 0, r3, c7, c5, 6 @ invalidate BTB
50 mcr p15, 0, r3, c7, c10, 4 @ data write barrier
51 mov pc, lr
52
53
54ENTRY(fa_flush_kern_tlb_range)
55 mov r3, #0
56 mcr p15, 0, r3, c7, c10, 4 @ drain WB
57 bic r0, r0, #0x0ff
58 bic r0, r0, #0xf00
591: mcr p15, 0, r0, c8, c7, 1 @ invalidate UTLB entry
60 add r0, r0, #PAGE_SZ
61 cmp r0, r1
62 blo 1b
63 mcr p15, 0, r3, c7, c5, 6 @ invalidate BTB
64 mcr p15, 0, r3, c7, c10, 4 @ data write barrier
65 mcr p15, 0, r3, c7, c5, 4 @ prefetch flush
66 mov pc, lr
67
68 __INITDATA
69
70 .type fa_tlb_fns, #object
71ENTRY(fa_tlb_fns)
72 .long fa_flush_user_tlb_range
73 .long fa_flush_kern_tlb_range
74 .long fa_tlb_flags
75 .size fa_tlb_fns, . - fa_tlb_fns