diff options
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/kernel/entry-armv.S | 19 | ||||
-rw-r--r-- | arch/arm/kernel/entry-header.S | 14 | ||||
-rw-r--r-- | arch/arm/kernel/kprobes.c | 19 | ||||
-rw-r--r-- | arch/arm/kernel/setup.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/tcm.c | 246 | ||||
-rw-r--r-- | arch/arm/kernel/tcm.h | 17 | ||||
-rw-r--r-- | arch/arm/kernel/vmlinux.lds.S | 57 |
8 files changed, 365 insertions, 10 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index c446aeff7b89..79087dd6d869 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile | |||
@@ -35,6 +35,7 @@ obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o | |||
35 | obj-$(CONFIG_ARM_THUMBEE) += thumbee.o | 35 | obj-$(CONFIG_ARM_THUMBEE) += thumbee.o |
36 | obj-$(CONFIG_KGDB) += kgdb.o | 36 | obj-$(CONFIG_KGDB) += kgdb.o |
37 | obj-$(CONFIG_ARM_UNWIND) += unwind.o | 37 | obj-$(CONFIG_ARM_UNWIND) += unwind.o |
38 | obj-$(CONFIG_HAVE_TCM) += tcm.o | ||
38 | 39 | ||
39 | obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o | 40 | obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o |
40 | AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312 | 41 | AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312 |
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 3d727a8a23bc..0a2ba51cf35d 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S | |||
@@ -272,7 +272,15 @@ __und_svc: | |||
272 | @ | 272 | @ |
273 | @ r0 - instruction | 273 | @ r0 - instruction |
274 | @ | 274 | @ |
275 | #ifndef CONFIG_THUMB2_KERNEL | ||
275 | ldr r0, [r2, #-4] | 276 | ldr r0, [r2, #-4] |
277 | #else | ||
278 | ldrh r0, [r2, #-2] @ Thumb instruction at LR - 2 | ||
279 | and r9, r0, #0xf800 | ||
280 | cmp r9, #0xe800 @ 32-bit instruction if xx >= 0 | ||
281 | ldrhhs r9, [r2] @ bottom 16 bits | ||
282 | orrhs r0, r9, r0, lsl #16 | ||
283 | #endif | ||
276 | adr r9, BSYM(1f) | 284 | adr r9, BSYM(1f) |
277 | bl call_fpe | 285 | bl call_fpe |
278 | 286 | ||
@@ -678,7 +686,9 @@ ENTRY(fp_enter) | |||
678 | .word no_fp | 686 | .word no_fp |
679 | .previous | 687 | .previous |
680 | 688 | ||
681 | no_fp: mov pc, lr | 689 | ENTRY(no_fp) |
690 | mov pc, lr | ||
691 | ENDPROC(no_fp) | ||
682 | 692 | ||
683 | __und_usr_unknown: | 693 | __und_usr_unknown: |
684 | enable_irq | 694 | enable_irq |
@@ -734,13 +744,6 @@ ENTRY(__switch_to) | |||
734 | #ifdef CONFIG_MMU | 744 | #ifdef CONFIG_MMU |
735 | ldr r6, [r2, #TI_CPU_DOMAIN] | 745 | ldr r6, [r2, #TI_CPU_DOMAIN] |
736 | #endif | 746 | #endif |
737 | #if __LINUX_ARM_ARCH__ >= 6 | ||
738 | #ifdef CONFIG_CPU_32v6K | ||
739 | clrex | ||
740 | #else | ||
741 | strex r5, r4, [ip] @ Clear exclusive monitor | ||
742 | #endif | ||
743 | #endif | ||
744 | #if defined(CONFIG_HAS_TLS_REG) | 747 | #if defined(CONFIG_HAS_TLS_REG) |
745 | mcr p15, 0, r3, c13, c0, 3 @ set TLS register | 748 | mcr p15, 0, r3, c13, c0, 3 @ set TLS register |
746 | #elif !defined(CONFIG_TLS_REG_EMUL) | 749 | #elif !defined(CONFIG_TLS_REG_EMUL) |
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index a4eaf4f920c5..e17e3c30d957 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S | |||
@@ -76,13 +76,25 @@ | |||
76 | #ifndef CONFIG_THUMB2_KERNEL | 76 | #ifndef CONFIG_THUMB2_KERNEL |
77 | .macro svc_exit, rpsr | 77 | .macro svc_exit, rpsr |
78 | msr spsr_cxsf, \rpsr | 78 | msr spsr_cxsf, \rpsr |
79 | #if defined(CONFIG_CPU_32v6K) | ||
80 | clrex @ clear the exclusive monitor | ||
79 | ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr | 81 | ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr |
82 | #elif defined (CONFIG_CPU_V6) | ||
83 | ldr r0, [sp] | ||
84 | strex r1, r2, [sp] @ clear the exclusive monitor | ||
85 | ldmib sp, {r1 - pc}^ @ load r1 - pc, cpsr | ||
86 | #endif | ||
80 | .endm | 87 | .endm |
81 | 88 | ||
82 | .macro restore_user_regs, fast = 0, offset = 0 | 89 | .macro restore_user_regs, fast = 0, offset = 0 |
83 | ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr | 90 | ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr |
84 | ldr lr, [sp, #\offset + S_PC]! @ get pc | 91 | ldr lr, [sp, #\offset + S_PC]! @ get pc |
85 | msr spsr_cxsf, r1 @ save in spsr_svc | 92 | msr spsr_cxsf, r1 @ save in spsr_svc |
93 | #if defined(CONFIG_CPU_32v6K) | ||
94 | clrex @ clear the exclusive monitor | ||
95 | #elif defined (CONFIG_CPU_V6) | ||
96 | strex r1, r2, [sp] @ clear the exclusive monitor | ||
97 | #endif | ||
86 | .if \fast | 98 | .if \fast |
87 | ldmdb sp, {r1 - lr}^ @ get calling r1 - lr | 99 | ldmdb sp, {r1 - lr}^ @ get calling r1 - lr |
88 | .else | 100 | .else |
@@ -98,6 +110,7 @@ | |||
98 | .endm | 110 | .endm |
99 | #else /* CONFIG_THUMB2_KERNEL */ | 111 | #else /* CONFIG_THUMB2_KERNEL */ |
100 | .macro svc_exit, rpsr | 112 | .macro svc_exit, rpsr |
113 | clrex @ clear the exclusive monitor | ||
101 | ldr r0, [sp, #S_SP] @ top of the stack | 114 | ldr r0, [sp, #S_SP] @ top of the stack |
102 | ldr r1, [sp, #S_PC] @ return address | 115 | ldr r1, [sp, #S_PC] @ return address |
103 | tst r0, #4 @ orig stack 8-byte aligned? | 116 | tst r0, #4 @ orig stack 8-byte aligned? |
@@ -110,6 +123,7 @@ | |||
110 | .endm | 123 | .endm |
111 | 124 | ||
112 | .macro restore_user_regs, fast = 0, offset = 0 | 125 | .macro restore_user_regs, fast = 0, offset = 0 |
126 | clrex @ clear the exclusive monitor | ||
113 | mov r2, sp | 127 | mov r2, sp |
114 | load_user_sp_lr r2, r3, \offset + S_SP @ calling sp, lr | 128 | load_user_sp_lr r2, r3, \offset + S_SP @ calling sp, lr |
115 | ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr | 129 | ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr |
diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index f692efddd449..60c62c377fa9 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
23 | #include <linux/kprobes.h> | 23 | #include <linux/kprobes.h> |
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/stop_machine.h> | ||
25 | #include <linux/stringify.h> | 26 | #include <linux/stringify.h> |
26 | #include <asm/traps.h> | 27 | #include <asm/traps.h> |
27 | #include <asm/cacheflush.h> | 28 | #include <asm/cacheflush.h> |
@@ -83,10 +84,24 @@ void __kprobes arch_arm_kprobe(struct kprobe *p) | |||
83 | flush_insns(p->addr, 1); | 84 | flush_insns(p->addr, 1); |
84 | } | 85 | } |
85 | 86 | ||
87 | /* | ||
88 | * The actual disarming is done here on each CPU and synchronized using | ||
89 | * stop_machine. This synchronization is necessary on SMP to avoid removing | ||
90 | * a probe between the moment the 'Undefined Instruction' exception is raised | ||
91 | * and the moment the exception handler reads the faulting instruction from | ||
92 | * memory. | ||
93 | */ | ||
94 | int __kprobes __arch_disarm_kprobe(void *p) | ||
95 | { | ||
96 | struct kprobe *kp = p; | ||
97 | *kp->addr = kp->opcode; | ||
98 | flush_insns(kp->addr, 1); | ||
99 | return 0; | ||
100 | } | ||
101 | |||
86 | void __kprobes arch_disarm_kprobe(struct kprobe *p) | 102 | void __kprobes arch_disarm_kprobe(struct kprobe *p) |
87 | { | 103 | { |
88 | *p->addr = p->opcode; | 104 | stop_machine(__arch_disarm_kprobe, p, &cpu_online_map); |
89 | flush_insns(p->addr, 1); | ||
90 | } | 105 | } |
91 | 106 | ||
92 | void __kprobes arch_remove_kprobe(struct kprobe *p) | 107 | void __kprobes arch_remove_kprobe(struct kprobe *p) |
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index d4d4f77c91b2..c6c57b640b6b 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c | |||
@@ -45,6 +45,7 @@ | |||
45 | 45 | ||
46 | #include "compat.h" | 46 | #include "compat.h" |
47 | #include "atags.h" | 47 | #include "atags.h" |
48 | #include "tcm.h" | ||
48 | 49 | ||
49 | #ifndef MEM_SIZE | 50 | #ifndef MEM_SIZE |
50 | #define MEM_SIZE (16*1024*1024) | 51 | #define MEM_SIZE (16*1024*1024) |
@@ -749,6 +750,7 @@ void __init setup_arch(char **cmdline_p) | |||
749 | #endif | 750 | #endif |
750 | 751 | ||
751 | cpu_init(); | 752 | cpu_init(); |
753 | tcm_init(); | ||
752 | 754 | ||
753 | /* | 755 | /* |
754 | * Set up various architecture-specific pointers | 756 | * Set up various architecture-specific pointers |
diff --git a/arch/arm/kernel/tcm.c b/arch/arm/kernel/tcm.c new file mode 100644 index 000000000000..e50303868f1b --- /dev/null +++ b/arch/arm/kernel/tcm.c | |||
@@ -0,0 +1,246 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008-2009 ST-Ericsson AB | ||
3 | * License terms: GNU General Public License (GPL) version 2 | ||
4 | * TCM memory handling for ARM systems | ||
5 | * | ||
6 | * Author: Linus Walleij <linus.walleij@stericsson.com> | ||
7 | * Author: Rickard Andersson <rickard.andersson@stericsson.com> | ||
8 | */ | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/stddef.h> | ||
13 | #include <linux/ioport.h> | ||
14 | #include <linux/genalloc.h> | ||
15 | #include <linux/string.h> /* memcpy */ | ||
16 | #include <asm/page.h> /* PAGE_SHIFT */ | ||
17 | #include <asm/cputype.h> | ||
18 | #include <asm/mach/map.h> | ||
19 | #include <mach/memory.h> | ||
20 | #include "tcm.h" | ||
21 | |||
22 | /* Scream and warn about misuse */ | ||
23 | #if !defined(ITCM_OFFSET) || !defined(ITCM_END) || \ | ||
24 | !defined(DTCM_OFFSET) || !defined(DTCM_END) | ||
25 | #error "TCM support selected but offsets not defined!" | ||
26 | #endif | ||
27 | |||
28 | static struct gen_pool *tcm_pool; | ||
29 | |||
30 | /* TCM section definitions from the linker */ | ||
31 | extern char __itcm_start, __sitcm_text, __eitcm_text; | ||
32 | extern char __dtcm_start, __sdtcm_data, __edtcm_data; | ||
33 | |||
34 | /* | ||
35 | * TCM memory resources | ||
36 | */ | ||
37 | static struct resource dtcm_res = { | ||
38 | .name = "DTCM RAM", | ||
39 | .start = DTCM_OFFSET, | ||
40 | .end = DTCM_END, | ||
41 | .flags = IORESOURCE_MEM | ||
42 | }; | ||
43 | |||
44 | static struct resource itcm_res = { | ||
45 | .name = "ITCM RAM", | ||
46 | .start = ITCM_OFFSET, | ||
47 | .end = ITCM_END, | ||
48 | .flags = IORESOURCE_MEM | ||
49 | }; | ||
50 | |||
51 | static struct map_desc dtcm_iomap[] __initdata = { | ||
52 | { | ||
53 | .virtual = DTCM_OFFSET, | ||
54 | .pfn = __phys_to_pfn(DTCM_OFFSET), | ||
55 | .length = (DTCM_END - DTCM_OFFSET + 1), | ||
56 | .type = MT_UNCACHED | ||
57 | } | ||
58 | }; | ||
59 | |||
60 | static struct map_desc itcm_iomap[] __initdata = { | ||
61 | { | ||
62 | .virtual = ITCM_OFFSET, | ||
63 | .pfn = __phys_to_pfn(ITCM_OFFSET), | ||
64 | .length = (ITCM_END - ITCM_OFFSET + 1), | ||
65 | .type = MT_UNCACHED | ||
66 | } | ||
67 | }; | ||
68 | |||
69 | /* | ||
70 | * Allocate a chunk of TCM memory | ||
71 | */ | ||
72 | void *tcm_alloc(size_t len) | ||
73 | { | ||
74 | unsigned long vaddr; | ||
75 | |||
76 | if (!tcm_pool) | ||
77 | return NULL; | ||
78 | |||
79 | vaddr = gen_pool_alloc(tcm_pool, len); | ||
80 | if (!vaddr) | ||
81 | return NULL; | ||
82 | |||
83 | return (void *) vaddr; | ||
84 | } | ||
85 | EXPORT_SYMBOL(tcm_alloc); | ||
86 | |||
87 | /* | ||
88 | * Free a chunk of TCM memory | ||
89 | */ | ||
90 | void tcm_free(void *addr, size_t len) | ||
91 | { | ||
92 | gen_pool_free(tcm_pool, (unsigned long) addr, len); | ||
93 | } | ||
94 | EXPORT_SYMBOL(tcm_free); | ||
95 | |||
96 | |||
97 | static void __init setup_tcm_bank(u8 type, u32 offset, u32 expected_size) | ||
98 | { | ||
99 | const int tcm_sizes[16] = { 0, -1, -1, 4, 8, 16, 32, 64, 128, | ||
100 | 256, 512, 1024, -1, -1, -1, -1 }; | ||
101 | u32 tcm_region; | ||
102 | int tcm_size; | ||
103 | |||
104 | /* Read the special TCM region register c9, 0 */ | ||
105 | if (!type) | ||
106 | asm("mrc p15, 0, %0, c9, c1, 0" | ||
107 | : "=r" (tcm_region)); | ||
108 | else | ||
109 | asm("mrc p15, 0, %0, c9, c1, 1" | ||
110 | : "=r" (tcm_region)); | ||
111 | |||
112 | tcm_size = tcm_sizes[(tcm_region >> 2) & 0x0f]; | ||
113 | if (tcm_size < 0) { | ||
114 | pr_err("CPU: %sTCM of unknown size!\n", | ||
115 | type ? "I" : "D"); | ||
116 | } else { | ||
117 | pr_info("CPU: found %sTCM %dk @ %08x, %senabled\n", | ||
118 | type ? "I" : "D", | ||
119 | tcm_size, | ||
120 | (tcm_region & 0xfffff000U), | ||
121 | (tcm_region & 1) ? "" : "not "); | ||
122 | } | ||
123 | |||
124 | if (tcm_size != expected_size) { | ||
125 | pr_crit("CPU: %sTCM was detected %dk but expected %dk!\n", | ||
126 | type ? "I" : "D", | ||
127 | tcm_size, | ||
128 | expected_size); | ||
129 | /* Adjust to the expected size? what can we do... */ | ||
130 | } | ||
131 | |||
132 | /* Force move the TCM bank to where we want it, enable */ | ||
133 | tcm_region = offset | (tcm_region & 0x00000ffeU) | 1; | ||
134 | |||
135 | if (!type) | ||
136 | asm("mcr p15, 0, %0, c9, c1, 0" | ||
137 | : /* No output operands */ | ||
138 | : "r" (tcm_region)); | ||
139 | else | ||
140 | asm("mcr p15, 0, %0, c9, c1, 1" | ||
141 | : /* No output operands */ | ||
142 | : "r" (tcm_region)); | ||
143 | |||
144 | pr_debug("CPU: moved %sTCM %dk to %08x, enabled\n", | ||
145 | type ? "I" : "D", | ||
146 | tcm_size, | ||
147 | (tcm_region & 0xfffff000U)); | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | * This initializes the TCM memory | ||
152 | */ | ||
153 | void __init tcm_init(void) | ||
154 | { | ||
155 | u32 tcm_status = read_cpuid_tcmstatus(); | ||
156 | char *start; | ||
157 | char *end; | ||
158 | char *ram; | ||
159 | |||
160 | /* Setup DTCM if present */ | ||
161 | if (tcm_status & (1 << 16)) { | ||
162 | setup_tcm_bank(0, DTCM_OFFSET, | ||
163 | (DTCM_END - DTCM_OFFSET + 1) >> 10); | ||
164 | request_resource(&iomem_resource, &dtcm_res); | ||
165 | iotable_init(dtcm_iomap, 1); | ||
166 | /* Copy data from RAM to DTCM */ | ||
167 | start = &__sdtcm_data; | ||
168 | end = &__edtcm_data; | ||
169 | ram = &__dtcm_start; | ||
170 | memcpy(start, ram, (end-start)); | ||
171 | pr_debug("CPU DTCM: copied data from %p - %p\n", start, end); | ||
172 | } | ||
173 | |||
174 | /* Setup ITCM if present */ | ||
175 | if (tcm_status & 1) { | ||
176 | setup_tcm_bank(1, ITCM_OFFSET, | ||
177 | (ITCM_END - ITCM_OFFSET + 1) >> 10); | ||
178 | request_resource(&iomem_resource, &itcm_res); | ||
179 | iotable_init(itcm_iomap, 1); | ||
180 | /* Copy code from RAM to ITCM */ | ||
181 | start = &__sitcm_text; | ||
182 | end = &__eitcm_text; | ||
183 | ram = &__itcm_start; | ||
184 | memcpy(start, ram, (end-start)); | ||
185 | pr_debug("CPU ITCM: copied code from %p - %p\n", start, end); | ||
186 | } | ||
187 | } | ||
188 | |||
189 | /* | ||
190 | * This creates the TCM memory pool and has to be done later, | ||
191 | * during the core_initicalls, since the allocator is not yet | ||
192 | * up and running when the first initialization runs. | ||
193 | */ | ||
194 | static int __init setup_tcm_pool(void) | ||
195 | { | ||
196 | u32 tcm_status = read_cpuid_tcmstatus(); | ||
197 | u32 dtcm_pool_start = (u32) &__edtcm_data; | ||
198 | u32 itcm_pool_start = (u32) &__eitcm_text; | ||
199 | int ret; | ||
200 | |||
201 | /* | ||
202 | * Set up malloc pool, 2^2 = 4 bytes granularity since | ||
203 | * the TCM is sometimes just 4 KiB. NB: pages and cache | ||
204 | * line alignments does not matter in TCM! | ||
205 | */ | ||
206 | tcm_pool = gen_pool_create(2, -1); | ||
207 | |||
208 | pr_debug("Setting up TCM memory pool\n"); | ||
209 | |||
210 | /* Add the rest of DTCM to the TCM pool */ | ||
211 | if (tcm_status & (1 << 16)) { | ||
212 | if (dtcm_pool_start < DTCM_END) { | ||
213 | ret = gen_pool_add(tcm_pool, dtcm_pool_start, | ||
214 | DTCM_END - dtcm_pool_start + 1, -1); | ||
215 | if (ret) { | ||
216 | pr_err("CPU DTCM: could not add DTCM " \ | ||
217 | "remainder to pool!\n"); | ||
218 | return ret; | ||
219 | } | ||
220 | pr_debug("CPU DTCM: Added %08x bytes @ %08x to " \ | ||
221 | "the TCM memory pool\n", | ||
222 | DTCM_END - dtcm_pool_start + 1, | ||
223 | dtcm_pool_start); | ||
224 | } | ||
225 | } | ||
226 | |||
227 | /* Add the rest of ITCM to the TCM pool */ | ||
228 | if (tcm_status & 1) { | ||
229 | if (itcm_pool_start < ITCM_END) { | ||
230 | ret = gen_pool_add(tcm_pool, itcm_pool_start, | ||
231 | ITCM_END - itcm_pool_start + 1, -1); | ||
232 | if (ret) { | ||
233 | pr_err("CPU ITCM: could not add ITCM " \ | ||
234 | "remainder to pool!\n"); | ||
235 | return ret; | ||
236 | } | ||
237 | pr_debug("CPU ITCM: Added %08x bytes @ %08x to " \ | ||
238 | "the TCM memory pool\n", | ||
239 | ITCM_END - itcm_pool_start + 1, | ||
240 | itcm_pool_start); | ||
241 | } | ||
242 | } | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | core_initcall(setup_tcm_pool); | ||
diff --git a/arch/arm/kernel/tcm.h b/arch/arm/kernel/tcm.h new file mode 100644 index 000000000000..8015ad434a40 --- /dev/null +++ b/arch/arm/kernel/tcm.h | |||
@@ -0,0 +1,17 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008-2009 ST-Ericsson AB | ||
3 | * License terms: GNU General Public License (GPL) version 2 | ||
4 | * TCM memory handling for ARM systems | ||
5 | * | ||
6 | * Author: Linus Walleij <linus.walleij@stericsson.com> | ||
7 | * Author: Rickard Andersson <rickard.andersson@stericsson.com> | ||
8 | */ | ||
9 | |||
10 | #ifdef CONFIG_HAVE_TCM | ||
11 | void __init tcm_init(void); | ||
12 | #else | ||
13 | /* No TCM support, just blank inlines to be optimized out */ | ||
14 | inline void tcm_init(void) | ||
15 | { | ||
16 | } | ||
17 | #endif | ||
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index 5cc4812c9763..aecf87dfbaec 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S | |||
@@ -199,6 +199,63 @@ SECTIONS | |||
199 | } | 199 | } |
200 | _edata_loc = __data_loc + SIZEOF(.data); | 200 | _edata_loc = __data_loc + SIZEOF(.data); |
201 | 201 | ||
202 | #ifdef CONFIG_HAVE_TCM | ||
203 | /* | ||
204 | * We align everything to a page boundary so we can | ||
205 | * free it after init has commenced and TCM contents have | ||
206 | * been copied to its destination. | ||
207 | */ | ||
208 | .tcm_start : { | ||
209 | . = ALIGN(PAGE_SIZE); | ||
210 | __tcm_start = .; | ||
211 | __itcm_start = .; | ||
212 | } | ||
213 | |||
214 | /* | ||
215 | * Link these to the ITCM RAM | ||
216 | * Put VMA to the TCM address and LMA to the common RAM | ||
217 | * and we'll upload the contents from RAM to TCM and free | ||
218 | * the used RAM after that. | ||
219 | */ | ||
220 | .text_itcm ITCM_OFFSET : AT(__itcm_start) | ||
221 | { | ||
222 | __sitcm_text = .; | ||
223 | *(.tcm.text) | ||
224 | *(.tcm.rodata) | ||
225 | . = ALIGN(4); | ||
226 | __eitcm_text = .; | ||
227 | } | ||
228 | |||
229 | /* | ||
230 | * Reset the dot pointer, this is needed to create the | ||
231 | * relative __dtcm_start below (to be used as extern in code). | ||
232 | */ | ||
233 | . = ADDR(.tcm_start) + SIZEOF(.tcm_start) + SIZEOF(.text_itcm); | ||
234 | |||
235 | .dtcm_start : { | ||
236 | __dtcm_start = .; | ||
237 | } | ||
238 | |||
239 | /* TODO: add remainder of ITCM as well, that can be used for data! */ | ||
240 | .data_dtcm DTCM_OFFSET : AT(__dtcm_start) | ||
241 | { | ||
242 | . = ALIGN(4); | ||
243 | __sdtcm_data = .; | ||
244 | *(.tcm.data) | ||
245 | . = ALIGN(4); | ||
246 | __edtcm_data = .; | ||
247 | } | ||
248 | |||
249 | /* Reset the dot pointer or the linker gets confused */ | ||
250 | . = ADDR(.dtcm_start) + SIZEOF(.data_dtcm); | ||
251 | |||
252 | /* End marker for freeing TCM copy in linked object */ | ||
253 | .tcm_end : AT(ADDR(.dtcm_start) + SIZEOF(.data_dtcm)){ | ||
254 | . = ALIGN(PAGE_SIZE); | ||
255 | __tcm_end = .; | ||
256 | } | ||
257 | #endif | ||
258 | |||
202 | .bss : { | 259 | .bss : { |
203 | __bss_start = .; /* BSS */ | 260 | __bss_start = .; /* BSS */ |
204 | *(.bss) | 261 | *(.bss) |