diff options
Diffstat (limited to 'arch/microblaze/kernel')
28 files changed, 1251 insertions, 332 deletions
diff --git a/arch/microblaze/kernel/Makefile b/arch/microblaze/kernel/Makefile index d487729683de..b07594eccf9b 100644 --- a/arch/microblaze/kernel/Makefile +++ b/arch/microblaze/kernel/Makefile | |||
@@ -2,12 +2,22 @@ | |||
2 | # Makefile | 2 | # Makefile |
3 | # | 3 | # |
4 | 4 | ||
5 | ifdef CONFIG_FUNCTION_TRACER | ||
6 | # Do not trace early boot code and low level code | ||
7 | CFLAGS_REMOVE_timer.o = -pg | ||
8 | CFLAGS_REMOVE_intc.o = -pg | ||
9 | CFLAGS_REMOVE_early_printk.o = -pg | ||
10 | CFLAGS_REMOVE_selfmod.o = -pg | ||
11 | CFLAGS_REMOVE_heartbeat.o = -pg | ||
12 | CFLAGS_REMOVE_ftrace.o = -pg | ||
13 | endif | ||
14 | |||
5 | extra-y := head.o vmlinux.lds | 15 | extra-y := head.o vmlinux.lds |
6 | 16 | ||
7 | obj-y += exceptions.o \ | 17 | obj-y += exceptions.o \ |
8 | hw_exception_handler.o init_task.o intc.o irq.o of_device.o \ | 18 | hw_exception_handler.o init_task.o intc.o irq.o of_device.o \ |
9 | of_platform.o process.o prom.o prom_parse.o ptrace.o \ | 19 | of_platform.o process.o prom.o prom_parse.o ptrace.o \ |
10 | setup.o signal.o sys_microblaze.o timer.o traps.o | 20 | setup.o signal.o sys_microblaze.o timer.o traps.o reset.o |
11 | 21 | ||
12 | obj-y += cpu/ | 22 | obj-y += cpu/ |
13 | 23 | ||
@@ -16,5 +26,7 @@ obj-$(CONFIG_SELFMOD) += selfmod.o | |||
16 | obj-$(CONFIG_HEART_BEAT) += heartbeat.o | 26 | obj-$(CONFIG_HEART_BEAT) += heartbeat.o |
17 | obj-$(CONFIG_MODULES) += microblaze_ksyms.o module.o | 27 | obj-$(CONFIG_MODULES) += microblaze_ksyms.o module.o |
18 | obj-$(CONFIG_MMU) += misc.o | 28 | obj-$(CONFIG_MMU) += misc.o |
29 | obj-$(CONFIG_STACKTRACE) += stacktrace.o | ||
30 | obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o mcount.o | ||
19 | 31 | ||
20 | obj-y += entry$(MMU).o | 32 | obj-y += entry$(MMU).o |
diff --git a/arch/microblaze/kernel/cpu/Makefile b/arch/microblaze/kernel/cpu/Makefile index 20646e549271..59cc7bceaf8c 100644 --- a/arch/microblaze/kernel/cpu/Makefile +++ b/arch/microblaze/kernel/cpu/Makefile | |||
@@ -2,6 +2,10 @@ | |||
2 | # Build the appropriate CPU version support | 2 | # Build the appropriate CPU version support |
3 | # | 3 | # |
4 | 4 | ||
5 | ifdef CONFIG_FUNCTION_TRACER | ||
6 | CFLAGS_REMOVE_cache.o = -pg | ||
7 | endif | ||
8 | |||
5 | EXTRA_CFLAGS += -DCPU_MAJOR=$(CPU_MAJOR) -DCPU_MINOR=$(CPU_MINOR) \ | 9 | EXTRA_CFLAGS += -DCPU_MAJOR=$(CPU_MAJOR) -DCPU_MINOR=$(CPU_MINOR) \ |
6 | -DCPU_REV=$(CPU_REV) | 10 | -DCPU_REV=$(CPU_REV) |
7 | 11 | ||
diff --git a/arch/microblaze/kernel/cpu/cache.c b/arch/microblaze/kernel/cpu/cache.c index af866a450125..d9d63831cc2f 100644 --- a/arch/microblaze/kernel/cpu/cache.c +++ b/arch/microblaze/kernel/cpu/cache.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu> | 4 | * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu> |
5 | * Copyright (C) 2007-2009 PetaLogix | 5 | * Copyright (C) 2007-2009 PetaLogix |
6 | * Copyright (C) 2007 John Williams <john.williams@petalogix.com> | 6 | * Copyright (C) 2007-2009 John Williams <john.williams@petalogix.com> |
7 | * | 7 | * |
8 | * This file is subject to the terms and conditions of the GNU General | 8 | * This file is subject to the terms and conditions of the GNU General |
9 | * Public License. See the file COPYING in the main directory of this | 9 | * Public License. See the file COPYING in the main directory of this |
@@ -13,243 +13,534 @@ | |||
13 | #include <asm/cacheflush.h> | 13 | #include <asm/cacheflush.h> |
14 | #include <linux/cache.h> | 14 | #include <linux/cache.h> |
15 | #include <asm/cpuinfo.h> | 15 | #include <asm/cpuinfo.h> |
16 | #include <asm/pvr.h> | ||
16 | 17 | ||
17 | /* Exported functions */ | 18 | static inline void __invalidate_flush_icache(unsigned int addr) |
19 | { | ||
20 | __asm__ __volatile__ ("wic %0, r0;" \ | ||
21 | : : "r" (addr)); | ||
22 | } | ||
23 | |||
24 | static inline void __flush_dcache(unsigned int addr) | ||
25 | { | ||
26 | __asm__ __volatile__ ("wdc.flush %0, r0;" \ | ||
27 | : : "r" (addr)); | ||
28 | } | ||
29 | |||
30 | static inline void __invalidate_dcache(unsigned int baseaddr, | ||
31 | unsigned int offset) | ||
32 | { | ||
33 | __asm__ __volatile__ ("wdc.clear %0, %1;" \ | ||
34 | : : "r" (baseaddr), "r" (offset)); | ||
35 | } | ||
18 | 36 | ||
19 | void _enable_icache(void) | 37 | static inline void __enable_icache_msr(void) |
20 | { | 38 | { |
21 | if (cpuinfo.use_icache) { | 39 | __asm__ __volatile__ (" msrset r0, %0; \ |
22 | #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR | 40 | nop; " \ |
23 | __asm__ __volatile__ (" \ | 41 | : : "i" (MSR_ICE) : "memory"); |
24 | msrset r0, %0; \ | 42 | } |
25 | nop; " \ | 43 | |
26 | : \ | 44 | static inline void __disable_icache_msr(void) |
27 | : "i" (MSR_ICE) \ | 45 | { |
46 | __asm__ __volatile__ (" msrclr r0, %0; \ | ||
47 | nop; " \ | ||
48 | : : "i" (MSR_ICE) : "memory"); | ||
49 | } | ||
50 | |||
51 | static inline void __enable_dcache_msr(void) | ||
52 | { | ||
53 | __asm__ __volatile__ (" msrset r0, %0; \ | ||
54 | nop; " \ | ||
55 | : \ | ||
56 | : "i" (MSR_DCE) \ | ||
28 | : "memory"); | 57 | : "memory"); |
29 | #else | ||
30 | __asm__ __volatile__ (" \ | ||
31 | mfs r12, rmsr; \ | ||
32 | nop; \ | ||
33 | ori r12, r12, %0; \ | ||
34 | mts rmsr, r12; \ | ||
35 | nop; " \ | ||
36 | : \ | ||
37 | : "i" (MSR_ICE) \ | ||
38 | : "memory", "r12"); | ||
39 | #endif | ||
40 | } | ||
41 | } | 58 | } |
42 | 59 | ||
43 | void _disable_icache(void) | 60 | static inline void __disable_dcache_msr(void) |
44 | { | 61 | { |
45 | if (cpuinfo.use_icache) { | 62 | __asm__ __volatile__ (" msrclr r0, %0; \ |
46 | #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR | 63 | nop; " \ |
47 | __asm__ __volatile__ (" \ | 64 | : \ |
48 | msrclr r0, %0; \ | 65 | : "i" (MSR_DCE) \ |
49 | nop; " \ | ||
50 | : \ | ||
51 | : "i" (MSR_ICE) \ | ||
52 | : "memory"); | 66 | : "memory"); |
53 | #else | 67 | } |
54 | __asm__ __volatile__ (" \ | 68 | |
55 | mfs r12, rmsr; \ | 69 | static inline void __enable_icache_nomsr(void) |
56 | nop; \ | 70 | { |
57 | andi r12, r12, ~%0; \ | 71 | __asm__ __volatile__ (" mfs r12, rmsr; \ |
58 | mts rmsr, r12; \ | 72 | nop; \ |
59 | nop; " \ | 73 | ori r12, r12, %0; \ |
60 | : \ | 74 | mts rmsr, r12; \ |
61 | : "i" (MSR_ICE) \ | 75 | nop; " \ |
76 | : \ | ||
77 | : "i" (MSR_ICE) \ | ||
62 | : "memory", "r12"); | 78 | : "memory", "r12"); |
63 | #endif | ||
64 | } | ||
65 | } | 79 | } |
66 | 80 | ||
67 | void _invalidate_icache(unsigned int addr) | 81 | static inline void __disable_icache_nomsr(void) |
68 | { | 82 | { |
69 | if (cpuinfo.use_icache) { | 83 | __asm__ __volatile__ (" mfs r12, rmsr; \ |
70 | __asm__ __volatile__ (" \ | 84 | nop; \ |
71 | wic %0, r0" \ | 85 | andi r12, r12, ~%0; \ |
72 | : \ | 86 | mts rmsr, r12; \ |
73 | : "r" (addr)); | 87 | nop; " \ |
74 | } | 88 | : \ |
89 | : "i" (MSR_ICE) \ | ||
90 | : "memory", "r12"); | ||
75 | } | 91 | } |
76 | 92 | ||
77 | void _enable_dcache(void) | 93 | static inline void __enable_dcache_nomsr(void) |
78 | { | 94 | { |
79 | if (cpuinfo.use_dcache) { | 95 | __asm__ __volatile__ (" mfs r12, rmsr; \ |
80 | #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR | 96 | nop; \ |
81 | __asm__ __volatile__ (" \ | 97 | ori r12, r12, %0; \ |
82 | msrset r0, %0; \ | 98 | mts rmsr, r12; \ |
83 | nop; " \ | 99 | nop; " \ |
84 | : \ | 100 | : \ |
85 | : "i" (MSR_DCE) \ | 101 | : "i" (MSR_DCE) \ |
86 | : "memory"); | ||
87 | #else | ||
88 | __asm__ __volatile__ (" \ | ||
89 | mfs r12, rmsr; \ | ||
90 | nop; \ | ||
91 | ori r12, r12, %0; \ | ||
92 | mts rmsr, r12; \ | ||
93 | nop; " \ | ||
94 | : \ | ||
95 | : "i" (MSR_DCE) \ | ||
96 | : "memory", "r12"); | 102 | : "memory", "r12"); |
97 | #endif | ||
98 | } | ||
99 | } | 103 | } |
100 | 104 | ||
101 | void _disable_dcache(void) | 105 | static inline void __disable_dcache_nomsr(void) |
102 | { | 106 | { |
103 | #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR | 107 | __asm__ __volatile__ (" mfs r12, rmsr; \ |
104 | __asm__ __volatile__ (" \ | 108 | nop; \ |
105 | msrclr r0, %0; \ | 109 | andi r12, r12, ~%0; \ |
106 | nop; " \ | 110 | mts rmsr, r12; \ |
107 | : \ | 111 | nop; " \ |
108 | : "i" (MSR_DCE) \ | 112 | : \ |
109 | : "memory"); | 113 | : "i" (MSR_DCE) \ |
110 | #else | ||
111 | __asm__ __volatile__ (" \ | ||
112 | mfs r12, rmsr; \ | ||
113 | nop; \ | ||
114 | andi r12, r12, ~%0; \ | ||
115 | mts rmsr, r12; \ | ||
116 | nop; " \ | ||
117 | : \ | ||
118 | : "i" (MSR_DCE) \ | ||
119 | : "memory", "r12"); | 114 | : "memory", "r12"); |
120 | #endif | ||
121 | } | 115 | } |
122 | 116 | ||
123 | void _invalidate_dcache(unsigned int addr) | 117 | |
118 | /* Helper macro for computing the limits of cache range loops */ | ||
119 | #define CACHE_LOOP_LIMITS(start, end, cache_line_length, cache_size) \ | ||
120 | do { \ | ||
121 | int align = ~(cache_line_length - 1); \ | ||
122 | end = min(start + cache_size, end); \ | ||
123 | start &= align; \ | ||
124 | end = ((end & align) + cache_line_length); \ | ||
125 | } while (0); | ||
126 | |||
127 | /* | ||
128 | * Helper macro to loop over the specified cache_size/line_length and | ||
129 | * execute 'op' on that cacheline | ||
130 | */ | ||
131 | #define CACHE_ALL_LOOP(cache_size, line_length, op) \ | ||
132 | do { \ | ||
133 | unsigned int len = cache_size; \ | ||
134 | int step = -line_length; \ | ||
135 | BUG_ON(step >= 0); \ | ||
136 | \ | ||
137 | __asm__ __volatile__ (" 1: " #op " %0, r0; \ | ||
138 | bgtid %0, 1b; \ | ||
139 | addk %0, %0, %1; \ | ||
140 | " : : "r" (len), "r" (step) \ | ||
141 | : "memory"); \ | ||
142 | } while (0); | ||
143 | |||
144 | |||
145 | #define CACHE_ALL_LOOP2(cache_size, line_length, op) \ | ||
146 | do { \ | ||
147 | unsigned int len = cache_size; \ | ||
148 | int step = -line_length; \ | ||
149 | BUG_ON(step >= 0); \ | ||
150 | \ | ||
151 | __asm__ __volatile__ (" 1: " #op " r0, %0; \ | ||
152 | bgtid %0, 1b; \ | ||
153 | addk %0, %0, %1; \ | ||
154 | " : : "r" (len), "r" (step) \ | ||
155 | : "memory"); \ | ||
156 | } while (0); | ||
157 | |||
158 | /* for wdc.flush/clear */ | ||
159 | #define CACHE_RANGE_LOOP_2(start, end, line_length, op) \ | ||
160 | do { \ | ||
161 | int step = -line_length; \ | ||
162 | int count = end - start; \ | ||
163 | BUG_ON(count <= 0); \ | ||
164 | \ | ||
165 | __asm__ __volatile__ (" 1: " #op " %0, %1; \ | ||
166 | bgtid %1, 1b; \ | ||
167 | addk %1, %1, %2; \ | ||
168 | " : : "r" (start), "r" (count), \ | ||
169 | "r" (step) : "memory"); \ | ||
170 | } while (0); | ||
171 | |||
172 | /* It is used only first parameter for OP - for wic, wdc */ | ||
173 | #define CACHE_RANGE_LOOP_1(start, end, line_length, op) \ | ||
174 | do { \ | ||
175 | int step = -line_length; \ | ||
176 | int count = end - start; \ | ||
177 | BUG_ON(count <= 0); \ | ||
178 | \ | ||
179 | __asm__ __volatile__ (" 1: addk %0, %0, %1; \ | ||
180 | " #op " %0, r0; \ | ||
181 | bgtid %1, 1b; \ | ||
182 | addk %1, %1, %2; \ | ||
183 | " : : "r" (start), "r" (count), \ | ||
184 | "r" (step) : "memory"); \ | ||
185 | } while (0); | ||
186 | |||
187 | static void __flush_icache_range_msr_irq(unsigned long start, unsigned long end) | ||
124 | { | 188 | { |
125 | __asm__ __volatile__ (" \ | 189 | unsigned long flags; |
126 | wdc %0, r0" \ | 190 | |
127 | : \ | 191 | pr_debug("%s: start 0x%x, end 0x%x\n", __func__, |
128 | : "r" (addr)); | 192 | (unsigned int)start, (unsigned int) end); |
193 | |||
194 | CACHE_LOOP_LIMITS(start, end, | ||
195 | cpuinfo.icache_line_length, cpuinfo.icache_size); | ||
196 | |||
197 | local_irq_save(flags); | ||
198 | __disable_icache_msr(); | ||
199 | |||
200 | CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic); | ||
201 | |||
202 | __enable_icache_msr(); | ||
203 | local_irq_restore(flags); | ||
129 | } | 204 | } |
130 | 205 | ||
131 | void __invalidate_icache_all(void) | 206 | static void __flush_icache_range_nomsr_irq(unsigned long start, |
207 | unsigned long end) | ||
132 | { | 208 | { |
133 | unsigned int i; | 209 | unsigned long flags; |
134 | unsigned flags; | ||
135 | 210 | ||
136 | if (cpuinfo.use_icache) { | 211 | pr_debug("%s: start 0x%x, end 0x%x\n", __func__, |
137 | local_irq_save(flags); | 212 | (unsigned int)start, (unsigned int) end); |
138 | __disable_icache(); | ||
139 | 213 | ||
140 | /* Just loop through cache size and invalidate, no need to add | 214 | CACHE_LOOP_LIMITS(start, end, |
141 | CACHE_BASE address */ | 215 | cpuinfo.icache_line_length, cpuinfo.icache_size); |
142 | for (i = 0; i < cpuinfo.icache_size; | ||
143 | i += cpuinfo.icache_line) | ||
144 | __invalidate_icache(i); | ||
145 | 216 | ||
146 | __enable_icache(); | 217 | local_irq_save(flags); |
147 | local_irq_restore(flags); | 218 | __disable_icache_nomsr(); |
148 | } | 219 | |
220 | CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic); | ||
221 | |||
222 | __enable_icache_nomsr(); | ||
223 | local_irq_restore(flags); | ||
149 | } | 224 | } |
150 | 225 | ||
151 | void __invalidate_icache_range(unsigned long start, unsigned long end) | 226 | static void __flush_icache_range_noirq(unsigned long start, |
227 | unsigned long end) | ||
152 | { | 228 | { |
153 | unsigned int i; | 229 | pr_debug("%s: start 0x%x, end 0x%x\n", __func__, |
154 | unsigned flags; | 230 | (unsigned int)start, (unsigned int) end); |
155 | unsigned int align; | 231 | |
156 | 232 | CACHE_LOOP_LIMITS(start, end, | |
157 | if (cpuinfo.use_icache) { | 233 | cpuinfo.icache_line_length, cpuinfo.icache_size); |
158 | /* | 234 | CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic); |
159 | * No need to cover entire cache range, | 235 | } |
160 | * just cover cache footprint | 236 | |
161 | */ | 237 | static void __flush_icache_all_msr_irq(void) |
162 | end = min(start + cpuinfo.icache_size, end); | 238 | { |
163 | align = ~(cpuinfo.icache_line - 1); | 239 | unsigned long flags; |
164 | start &= align; /* Make sure we are aligned */ | 240 | |
165 | /* Push end up to the next cache line */ | 241 | pr_debug("%s\n", __func__); |
166 | end = ((end & align) + cpuinfo.icache_line); | 242 | |
167 | 243 | local_irq_save(flags); | |
168 | local_irq_save(flags); | 244 | __disable_icache_msr(); |
169 | __disable_icache(); | 245 | |
170 | 246 | CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic); | |
171 | for (i = start; i < end; i += cpuinfo.icache_line) | 247 | |
172 | __invalidate_icache(i); | 248 | __enable_icache_msr(); |
173 | 249 | local_irq_restore(flags); | |
174 | __enable_icache(); | 250 | } |
175 | local_irq_restore(flags); | 251 | |
176 | } | 252 | static void __flush_icache_all_nomsr_irq(void) |
253 | { | ||
254 | unsigned long flags; | ||
255 | |||
256 | pr_debug("%s\n", __func__); | ||
257 | |||
258 | local_irq_save(flags); | ||
259 | __disable_icache_nomsr(); | ||
260 | |||
261 | CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic); | ||
262 | |||
263 | __enable_icache_nomsr(); | ||
264 | local_irq_restore(flags); | ||
177 | } | 265 | } |
178 | 266 | ||
179 | void __invalidate_icache_page(struct vm_area_struct *vma, struct page *page) | 267 | static void __flush_icache_all_noirq(void) |
180 | { | 268 | { |
181 | __invalidate_icache_all(); | 269 | pr_debug("%s\n", __func__); |
270 | CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic); | ||
182 | } | 271 | } |
183 | 272 | ||
184 | void __invalidate_icache_user_range(struct vm_area_struct *vma, | 273 | static void __invalidate_dcache_all_msr_irq(void) |
185 | struct page *page, unsigned long adr, | ||
186 | int len) | ||
187 | { | 274 | { |
188 | __invalidate_icache_all(); | 275 | unsigned long flags; |
276 | |||
277 | pr_debug("%s\n", __func__); | ||
278 | |||
279 | local_irq_save(flags); | ||
280 | __disable_dcache_msr(); | ||
281 | |||
282 | CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc); | ||
283 | |||
284 | __enable_dcache_msr(); | ||
285 | local_irq_restore(flags); | ||
189 | } | 286 | } |
190 | 287 | ||
191 | void __invalidate_cache_sigtramp(unsigned long addr) | 288 | static void __invalidate_dcache_all_nomsr_irq(void) |
192 | { | 289 | { |
193 | __invalidate_icache_range(addr, addr + 8); | 290 | unsigned long flags; |
291 | |||
292 | pr_debug("%s\n", __func__); | ||
293 | |||
294 | local_irq_save(flags); | ||
295 | __disable_dcache_nomsr(); | ||
296 | |||
297 | CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc); | ||
298 | |||
299 | __enable_dcache_nomsr(); | ||
300 | local_irq_restore(flags); | ||
194 | } | 301 | } |
195 | 302 | ||
196 | void __invalidate_dcache_all(void) | 303 | static void __invalidate_dcache_all_noirq_wt(void) |
197 | { | 304 | { |
198 | unsigned int i; | 305 | pr_debug("%s\n", __func__); |
199 | unsigned flags; | 306 | CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc) |
200 | |||
201 | if (cpuinfo.use_dcache) { | ||
202 | local_irq_save(flags); | ||
203 | __disable_dcache(); | ||
204 | |||
205 | /* | ||
206 | * Just loop through cache size and invalidate, | ||
207 | * no need to add CACHE_BASE address | ||
208 | */ | ||
209 | for (i = 0; i < cpuinfo.dcache_size; | ||
210 | i += cpuinfo.dcache_line) | ||
211 | __invalidate_dcache(i); | ||
212 | |||
213 | __enable_dcache(); | ||
214 | local_irq_restore(flags); | ||
215 | } | ||
216 | } | 307 | } |
217 | 308 | ||
218 | void __invalidate_dcache_range(unsigned long start, unsigned long end) | 309 | /* FIXME this is weird - should be only wdc but not work |
310 | * MS: I am getting bus errors and other weird things */ | ||
311 | static void __invalidate_dcache_all_wb(void) | ||
219 | { | 312 | { |
313 | pr_debug("%s\n", __func__); | ||
314 | CACHE_ALL_LOOP2(cpuinfo.dcache_size, cpuinfo.dcache_line_length, | ||
315 | wdc.clear) | ||
316 | |||
317 | #if 0 | ||
220 | unsigned int i; | 318 | unsigned int i; |
221 | unsigned flags; | 319 | |
222 | unsigned int align; | 320 | pr_debug("%s\n", __func__); |
223 | 321 | ||
224 | if (cpuinfo.use_dcache) { | 322 | /* Just loop through cache size and invalidate it */ |
225 | /* | 323 | for (i = 0; i < cpuinfo.dcache_size; i += cpuinfo.dcache_line_length) |
226 | * No need to cover entire cache range, | 324 | __invalidate_dcache(0, i); |
227 | * just cover cache footprint | 325 | #endif |
228 | */ | 326 | } |
229 | end = min(start + cpuinfo.dcache_size, end); | 327 | |
230 | align = ~(cpuinfo.dcache_line - 1); | 328 | static void __invalidate_dcache_range_wb(unsigned long start, |
231 | start &= align; /* Make sure we are aligned */ | 329 | unsigned long end) |
232 | /* Push end up to the next cache line */ | 330 | { |
233 | end = ((end & align) + cpuinfo.dcache_line); | 331 | pr_debug("%s: start 0x%x, end 0x%x\n", __func__, |
234 | local_irq_save(flags); | 332 | (unsigned int)start, (unsigned int) end); |
235 | __disable_dcache(); | 333 | |
236 | 334 | CACHE_LOOP_LIMITS(start, end, | |
237 | for (i = start; i < end; i += cpuinfo.dcache_line) | 335 | cpuinfo.dcache_line_length, cpuinfo.dcache_size); |
238 | __invalidate_dcache(i); | 336 | CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.clear); |
239 | 337 | } | |
240 | __enable_dcache(); | 338 | |
241 | local_irq_restore(flags); | 339 | static void __invalidate_dcache_range_nomsr_wt(unsigned long start, |
242 | } | 340 | unsigned long end) |
341 | { | ||
342 | pr_debug("%s: start 0x%x, end 0x%x\n", __func__, | ||
343 | (unsigned int)start, (unsigned int) end); | ||
344 | CACHE_LOOP_LIMITS(start, end, | ||
345 | cpuinfo.dcache_line_length, cpuinfo.dcache_size); | ||
346 | |||
347 | CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc); | ||
243 | } | 348 | } |
244 | 349 | ||
245 | void __invalidate_dcache_page(struct vm_area_struct *vma, struct page *page) | 350 | static void __invalidate_dcache_range_msr_irq_wt(unsigned long start, |
351 | unsigned long end) | ||
246 | { | 352 | { |
247 | __invalidate_dcache_all(); | 353 | unsigned long flags; |
354 | |||
355 | pr_debug("%s: start 0x%x, end 0x%x\n", __func__, | ||
356 | (unsigned int)start, (unsigned int) end); | ||
357 | CACHE_LOOP_LIMITS(start, end, | ||
358 | cpuinfo.dcache_line_length, cpuinfo.dcache_size); | ||
359 | |||
360 | local_irq_save(flags); | ||
361 | __disable_dcache_msr(); | ||
362 | |||
363 | CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc); | ||
364 | |||
365 | __enable_dcache_msr(); | ||
366 | local_irq_restore(flags); | ||
367 | } | ||
368 | |||
369 | static void __invalidate_dcache_range_nomsr_irq(unsigned long start, | ||
370 | unsigned long end) | ||
371 | { | ||
372 | unsigned long flags; | ||
373 | |||
374 | pr_debug("%s: start 0x%x, end 0x%x\n", __func__, | ||
375 | (unsigned int)start, (unsigned int) end); | ||
376 | |||
377 | CACHE_LOOP_LIMITS(start, end, | ||
378 | cpuinfo.dcache_line_length, cpuinfo.dcache_size); | ||
379 | |||
380 | local_irq_save(flags); | ||
381 | __disable_dcache_nomsr(); | ||
382 | |||
383 | CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc); | ||
384 | |||
385 | __enable_dcache_nomsr(); | ||
386 | local_irq_restore(flags); | ||
387 | } | ||
388 | |||
389 | static void __flush_dcache_all_wb(void) | ||
390 | { | ||
391 | pr_debug("%s\n", __func__); | ||
392 | CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, | ||
393 | wdc.flush); | ||
248 | } | 394 | } |
249 | 395 | ||
250 | void __invalidate_dcache_user_range(struct vm_area_struct *vma, | 396 | static void __flush_dcache_range_wb(unsigned long start, unsigned long end) |
251 | struct page *page, unsigned long adr, | ||
252 | int len) | ||
253 | { | 397 | { |
254 | __invalidate_dcache_all(); | 398 | pr_debug("%s: start 0x%x, end 0x%x\n", __func__, |
399 | (unsigned int)start, (unsigned int) end); | ||
400 | |||
401 | CACHE_LOOP_LIMITS(start, end, | ||
402 | cpuinfo.dcache_line_length, cpuinfo.dcache_size); | ||
403 | CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.flush); | ||
404 | } | ||
405 | |||
406 | /* struct for wb caches and for wt caches */ | ||
407 | struct scache *mbc; | ||
408 | |||
409 | /* new wb cache model */ | ||
410 | const struct scache wb_msr = { | ||
411 | .ie = __enable_icache_msr, | ||
412 | .id = __disable_icache_msr, | ||
413 | .ifl = __flush_icache_all_noirq, | ||
414 | .iflr = __flush_icache_range_noirq, | ||
415 | .iin = __flush_icache_all_noirq, | ||
416 | .iinr = __flush_icache_range_noirq, | ||
417 | .de = __enable_dcache_msr, | ||
418 | .dd = __disable_dcache_msr, | ||
419 | .dfl = __flush_dcache_all_wb, | ||
420 | .dflr = __flush_dcache_range_wb, | ||
421 | .din = __invalidate_dcache_all_wb, | ||
422 | .dinr = __invalidate_dcache_range_wb, | ||
423 | }; | ||
424 | |||
425 | /* There is only difference in ie, id, de, dd functions */ | ||
426 | const struct scache wb_nomsr = { | ||
427 | .ie = __enable_icache_nomsr, | ||
428 | .id = __disable_icache_nomsr, | ||
429 | .ifl = __flush_icache_all_noirq, | ||
430 | .iflr = __flush_icache_range_noirq, | ||
431 | .iin = __flush_icache_all_noirq, | ||
432 | .iinr = __flush_icache_range_noirq, | ||
433 | .de = __enable_dcache_nomsr, | ||
434 | .dd = __disable_dcache_nomsr, | ||
435 | .dfl = __flush_dcache_all_wb, | ||
436 | .dflr = __flush_dcache_range_wb, | ||
437 | .din = __invalidate_dcache_all_wb, | ||
438 | .dinr = __invalidate_dcache_range_wb, | ||
439 | }; | ||
440 | |||
441 | /* Old wt cache model with disabling irq and turn off cache */ | ||
442 | const struct scache wt_msr = { | ||
443 | .ie = __enable_icache_msr, | ||
444 | .id = __disable_icache_msr, | ||
445 | .ifl = __flush_icache_all_msr_irq, | ||
446 | .iflr = __flush_icache_range_msr_irq, | ||
447 | .iin = __flush_icache_all_msr_irq, | ||
448 | .iinr = __flush_icache_range_msr_irq, | ||
449 | .de = __enable_dcache_msr, | ||
450 | .dd = __disable_dcache_msr, | ||
451 | .dfl = __invalidate_dcache_all_msr_irq, | ||
452 | .dflr = __invalidate_dcache_range_msr_irq_wt, | ||
453 | .din = __invalidate_dcache_all_msr_irq, | ||
454 | .dinr = __invalidate_dcache_range_msr_irq_wt, | ||
455 | }; | ||
456 | |||
457 | const struct scache wt_nomsr = { | ||
458 | .ie = __enable_icache_nomsr, | ||
459 | .id = __disable_icache_nomsr, | ||
460 | .ifl = __flush_icache_all_nomsr_irq, | ||
461 | .iflr = __flush_icache_range_nomsr_irq, | ||
462 | .iin = __flush_icache_all_nomsr_irq, | ||
463 | .iinr = __flush_icache_range_nomsr_irq, | ||
464 | .de = __enable_dcache_nomsr, | ||
465 | .dd = __disable_dcache_nomsr, | ||
466 | .dfl = __invalidate_dcache_all_nomsr_irq, | ||
467 | .dflr = __invalidate_dcache_range_nomsr_irq, | ||
468 | .din = __invalidate_dcache_all_nomsr_irq, | ||
469 | .dinr = __invalidate_dcache_range_nomsr_irq, | ||
470 | }; | ||
471 | |||
472 | /* New wt cache model for newer Microblaze versions */ | ||
473 | const struct scache wt_msr_noirq = { | ||
474 | .ie = __enable_icache_msr, | ||
475 | .id = __disable_icache_msr, | ||
476 | .ifl = __flush_icache_all_noirq, | ||
477 | .iflr = __flush_icache_range_noirq, | ||
478 | .iin = __flush_icache_all_noirq, | ||
479 | .iinr = __flush_icache_range_noirq, | ||
480 | .de = __enable_dcache_msr, | ||
481 | .dd = __disable_dcache_msr, | ||
482 | .dfl = __invalidate_dcache_all_noirq_wt, | ||
483 | .dflr = __invalidate_dcache_range_nomsr_wt, | ||
484 | .din = __invalidate_dcache_all_noirq_wt, | ||
485 | .dinr = __invalidate_dcache_range_nomsr_wt, | ||
486 | }; | ||
487 | |||
488 | const struct scache wt_nomsr_noirq = { | ||
489 | .ie = __enable_icache_nomsr, | ||
490 | .id = __disable_icache_nomsr, | ||
491 | .ifl = __flush_icache_all_noirq, | ||
492 | .iflr = __flush_icache_range_noirq, | ||
493 | .iin = __flush_icache_all_noirq, | ||
494 | .iinr = __flush_icache_range_noirq, | ||
495 | .de = __enable_dcache_nomsr, | ||
496 | .dd = __disable_dcache_nomsr, | ||
497 | .dfl = __invalidate_dcache_all_noirq_wt, | ||
498 | .dflr = __invalidate_dcache_range_nomsr_wt, | ||
499 | .din = __invalidate_dcache_all_noirq_wt, | ||
500 | .dinr = __invalidate_dcache_range_nomsr_wt, | ||
501 | }; | ||
502 | |||
503 | /* CPU version code for 7.20.c - see arch/microblaze/kernel/cpu/cpuinfo.c */ | ||
504 | #define CPUVER_7_20_A 0x0c | ||
505 | #define CPUVER_7_20_D 0x0f | ||
506 | |||
507 | #define INFO(s) printk(KERN_INFO "cache: " s " \n"); | ||
508 | |||
509 | void microblaze_cache_init(void) | ||
510 | { | ||
511 | if (cpuinfo.use_instr & PVR2_USE_MSR_INSTR) { | ||
512 | if (cpuinfo.dcache_wb) { | ||
513 | INFO("wb_msr"); | ||
514 | mbc = (struct scache *)&wb_msr; | ||
515 | if (cpuinfo.ver_code < CPUVER_7_20_D) { | ||
516 | /* MS: problem with signal handling - hw bug */ | ||
517 | INFO("WB won't work properly"); | ||
518 | } | ||
519 | } else { | ||
520 | if (cpuinfo.ver_code >= CPUVER_7_20_A) { | ||
521 | INFO("wt_msr_noirq"); | ||
522 | mbc = (struct scache *)&wt_msr_noirq; | ||
523 | } else { | ||
524 | INFO("wt_msr"); | ||
525 | mbc = (struct scache *)&wt_msr; | ||
526 | } | ||
527 | } | ||
528 | } else { | ||
529 | if (cpuinfo.dcache_wb) { | ||
530 | INFO("wb_nomsr"); | ||
531 | mbc = (struct scache *)&wb_nomsr; | ||
532 | if (cpuinfo.ver_code < CPUVER_7_20_D) { | ||
533 | /* MS: problem with signal handling - hw bug */ | ||
534 | INFO("WB won't work properly"); | ||
535 | } | ||
536 | } else { | ||
537 | if (cpuinfo.ver_code >= CPUVER_7_20_A) { | ||
538 | INFO("wt_nomsr_noirq"); | ||
539 | mbc = (struct scache *)&wt_nomsr_noirq; | ||
540 | } else { | ||
541 | INFO("wt_nomsr"); | ||
542 | mbc = (struct scache *)&wt_nomsr; | ||
543 | } | ||
544 | } | ||
545 | } | ||
255 | } | 546 | } |
diff --git a/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c index c259786e7faa..f72dbd66c844 100644 --- a/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c +++ b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c | |||
@@ -21,8 +21,14 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | #define CI(c, p) { ci->c = PVR_##p(pvr); } | 23 | #define CI(c, p) { ci->c = PVR_##p(pvr); } |
24 | |||
25 | #if defined(CONFIG_EARLY_PRINTK) && defined(CONFIG_SERIAL_UARTLITE_CONSOLE) | ||
24 | #define err_printk(x) \ | 26 | #define err_printk(x) \ |
25 | early_printk("ERROR: Microblaze " x "-different for PVR and DTS\n"); | 27 | early_printk("ERROR: Microblaze " x "-different for PVR and DTS\n"); |
28 | #else | ||
29 | #define err_printk(x) \ | ||
30 | printk(KERN_INFO "ERROR: Microblaze " x "-different for PVR and DTS\n"); | ||
31 | #endif | ||
26 | 32 | ||
27 | void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu) | 33 | void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu) |
28 | { | 34 | { |
@@ -70,7 +76,7 @@ void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu) | |||
70 | CI(use_icache, USE_ICACHE); | 76 | CI(use_icache, USE_ICACHE); |
71 | CI(icache_tagbits, ICACHE_ADDR_TAG_BITS); | 77 | CI(icache_tagbits, ICACHE_ADDR_TAG_BITS); |
72 | CI(icache_write, ICACHE_ALLOW_WR); | 78 | CI(icache_write, ICACHE_ALLOW_WR); |
73 | CI(icache_line, ICACHE_LINE_LEN); | 79 | ci->icache_line_length = PVR_ICACHE_LINE_LEN(pvr) << 2; |
74 | CI(icache_size, ICACHE_BYTE_SIZE); | 80 | CI(icache_size, ICACHE_BYTE_SIZE); |
75 | CI(icache_base, ICACHE_BASEADDR); | 81 | CI(icache_base, ICACHE_BASEADDR); |
76 | CI(icache_high, ICACHE_HIGHADDR); | 82 | CI(icache_high, ICACHE_HIGHADDR); |
@@ -78,11 +84,16 @@ void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu) | |||
78 | CI(use_dcache, USE_DCACHE); | 84 | CI(use_dcache, USE_DCACHE); |
79 | CI(dcache_tagbits, DCACHE_ADDR_TAG_BITS); | 85 | CI(dcache_tagbits, DCACHE_ADDR_TAG_BITS); |
80 | CI(dcache_write, DCACHE_ALLOW_WR); | 86 | CI(dcache_write, DCACHE_ALLOW_WR); |
81 | CI(dcache_line, DCACHE_LINE_LEN); | 87 | ci->dcache_line_length = PVR_DCACHE_LINE_LEN(pvr) << 2; |
82 | CI(dcache_size, DCACHE_BYTE_SIZE); | 88 | CI(dcache_size, DCACHE_BYTE_SIZE); |
83 | CI(dcache_base, DCACHE_BASEADDR); | 89 | CI(dcache_base, DCACHE_BASEADDR); |
84 | CI(dcache_high, DCACHE_HIGHADDR); | 90 | CI(dcache_high, DCACHE_HIGHADDR); |
85 | 91 | ||
92 | temp = PVR_DCACHE_USE_WRITEBACK(pvr); | ||
93 | if (ci->dcache_wb != temp) | ||
94 | err_printk("DCACHE WB"); | ||
95 | ci->dcache_wb = temp; | ||
96 | |||
86 | CI(use_dopb, D_OPB); | 97 | CI(use_dopb, D_OPB); |
87 | CI(use_iopb, I_OPB); | 98 | CI(use_iopb, I_OPB); |
88 | CI(use_dlmb, D_LMB); | 99 | CI(use_dlmb, D_LMB); |
diff --git a/arch/microblaze/kernel/cpu/cpuinfo-static.c b/arch/microblaze/kernel/cpu/cpuinfo-static.c index adb448f93d5f..6095aa6b5c88 100644 --- a/arch/microblaze/kernel/cpu/cpuinfo-static.c +++ b/arch/microblaze/kernel/cpu/cpuinfo-static.c | |||
@@ -72,12 +72,12 @@ void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu) | |||
72 | ci->use_icache = fcpu(cpu, "xlnx,use-icache"); | 72 | ci->use_icache = fcpu(cpu, "xlnx,use-icache"); |
73 | ci->icache_tagbits = fcpu(cpu, "xlnx,addr-tag-bits"); | 73 | ci->icache_tagbits = fcpu(cpu, "xlnx,addr-tag-bits"); |
74 | ci->icache_write = fcpu(cpu, "xlnx,allow-icache-wr"); | 74 | ci->icache_write = fcpu(cpu, "xlnx,allow-icache-wr"); |
75 | ci->icache_line = fcpu(cpu, "xlnx,icache-line-len") << 2; | 75 | ci->icache_line_length = fcpu(cpu, "xlnx,icache-line-len") << 2; |
76 | if (!ci->icache_line) { | 76 | if (!ci->icache_line_length) { |
77 | if (fcpu(cpu, "xlnx,icache-use-fsl")) | 77 | if (fcpu(cpu, "xlnx,icache-use-fsl")) |
78 | ci->icache_line = 4 << 2; | 78 | ci->icache_line_length = 4 << 2; |
79 | else | 79 | else |
80 | ci->icache_line = 1 << 2; | 80 | ci->icache_line_length = 1 << 2; |
81 | } | 81 | } |
82 | ci->icache_size = fcpu(cpu, "i-cache-size"); | 82 | ci->icache_size = fcpu(cpu, "i-cache-size"); |
83 | ci->icache_base = fcpu(cpu, "i-cache-baseaddr"); | 83 | ci->icache_base = fcpu(cpu, "i-cache-baseaddr"); |
@@ -86,16 +86,17 @@ void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu) | |||
86 | ci->use_dcache = fcpu(cpu, "xlnx,use-dcache"); | 86 | ci->use_dcache = fcpu(cpu, "xlnx,use-dcache"); |
87 | ci->dcache_tagbits = fcpu(cpu, "xlnx,dcache-addr-tag"); | 87 | ci->dcache_tagbits = fcpu(cpu, "xlnx,dcache-addr-tag"); |
88 | ci->dcache_write = fcpu(cpu, "xlnx,allow-dcache-wr"); | 88 | ci->dcache_write = fcpu(cpu, "xlnx,allow-dcache-wr"); |
89 | ci->dcache_line = fcpu(cpu, "xlnx,dcache-line-len") << 2; | 89 | ci->dcache_line_length = fcpu(cpu, "xlnx,dcache-line-len") << 2; |
90 | if (!ci->dcache_line) { | 90 | if (!ci->dcache_line_length) { |
91 | if (fcpu(cpu, "xlnx,dcache-use-fsl")) | 91 | if (fcpu(cpu, "xlnx,dcache-use-fsl")) |
92 | ci->dcache_line = 4 << 2; | 92 | ci->dcache_line_length = 4 << 2; |
93 | else | 93 | else |
94 | ci->dcache_line = 1 << 2; | 94 | ci->dcache_line_length = 1 << 2; |
95 | } | 95 | } |
96 | ci->dcache_size = fcpu(cpu, "d-cache-size"); | 96 | ci->dcache_size = fcpu(cpu, "d-cache-size"); |
97 | ci->dcache_base = fcpu(cpu, "d-cache-baseaddr"); | 97 | ci->dcache_base = fcpu(cpu, "d-cache-baseaddr"); |
98 | ci->dcache_high = fcpu(cpu, "d-cache-highaddr"); | 98 | ci->dcache_high = fcpu(cpu, "d-cache-highaddr"); |
99 | ci->dcache_wb = fcpu(cpu, "xlnx,dcache-use-writeback"); | ||
99 | 100 | ||
100 | ci->use_dopb = fcpu(cpu, "xlnx,d-opb"); | 101 | ci->use_dopb = fcpu(cpu, "xlnx,d-opb"); |
101 | ci->use_iopb = fcpu(cpu, "xlnx,i-opb"); | 102 | ci->use_iopb = fcpu(cpu, "xlnx,i-opb"); |
diff --git a/arch/microblaze/kernel/cpu/cpuinfo.c b/arch/microblaze/kernel/cpu/cpuinfo.c index 3539babc1c18..991d71311b0e 100644 --- a/arch/microblaze/kernel/cpu/cpuinfo.c +++ b/arch/microblaze/kernel/cpu/cpuinfo.c | |||
@@ -29,11 +29,8 @@ const struct cpu_ver_key cpu_ver_lookup[] = { | |||
29 | {"7.20.a", 0x0c}, | 29 | {"7.20.a", 0x0c}, |
30 | {"7.20.b", 0x0d}, | 30 | {"7.20.b", 0x0d}, |
31 | {"7.20.c", 0x0e}, | 31 | {"7.20.c", 0x0e}, |
32 | /* FIXME There is no keycode defined in MBV for these versions */ | 32 | {"7.20.d", 0x0f}, |
33 | {"2.10.a", 0x10}, | 33 | {"7.30.a", 0x10}, |
34 | {"3.00.a", 0x20}, | ||
35 | {"4.00.a", 0x30}, | ||
36 | {"4.00.b", 0x40}, | ||
37 | {NULL, 0}, | 34 | {NULL, 0}, |
38 | }; | 35 | }; |
39 | 36 | ||
diff --git a/arch/microblaze/kernel/cpu/mb.c b/arch/microblaze/kernel/cpu/mb.c index 4dcfccdbc364..0c912b2a8e03 100644 --- a/arch/microblaze/kernel/cpu/mb.c +++ b/arch/microblaze/kernel/cpu/mb.c | |||
@@ -103,11 +103,15 @@ static int show_cpuinfo(struct seq_file *m, void *v) | |||
103 | else | 103 | else |
104 | count += seq_printf(m, "Icache:\t\tno\n"); | 104 | count += seq_printf(m, "Icache:\t\tno\n"); |
105 | 105 | ||
106 | if (cpuinfo.use_dcache) | 106 | if (cpuinfo.use_dcache) { |
107 | count += seq_printf(m, | 107 | count += seq_printf(m, |
108 | "Dcache:\t\t%ukB\n", | 108 | "Dcache:\t\t%ukB\n", |
109 | cpuinfo.dcache_size >> 10); | 109 | cpuinfo.dcache_size >> 10); |
110 | else | 110 | if (cpuinfo.dcache_wb) |
111 | count += seq_printf(m, "\t\twrite-back\n"); | ||
112 | else | ||
113 | count += seq_printf(m, "\t\twrite-through\n"); | ||
114 | } else | ||
111 | count += seq_printf(m, "Dcache:\t\tno\n"); | 115 | count += seq_printf(m, "Dcache:\t\tno\n"); |
112 | 116 | ||
113 | count += seq_printf(m, | 117 | count += seq_printf(m, |
diff --git a/arch/microblaze/kernel/cpu/pvr.c b/arch/microblaze/kernel/cpu/pvr.c index c9a4340ddd53..9bee9382bf74 100644 --- a/arch/microblaze/kernel/cpu/pvr.c +++ b/arch/microblaze/kernel/cpu/pvr.c | |||
@@ -45,7 +45,7 @@ | |||
45 | 45 | ||
46 | int cpu_has_pvr(void) | 46 | int cpu_has_pvr(void) |
47 | { | 47 | { |
48 | unsigned flags; | 48 | unsigned long flags; |
49 | unsigned pvr0; | 49 | unsigned pvr0; |
50 | 50 | ||
51 | local_save_flags(flags); | 51 | local_save_flags(flags); |
diff --git a/arch/microblaze/kernel/entry-nommu.S b/arch/microblaze/kernel/entry-nommu.S index 9083d85376a4..95b0855802df 100644 --- a/arch/microblaze/kernel/entry-nommu.S +++ b/arch/microblaze/kernel/entry-nommu.S | |||
@@ -208,8 +208,6 @@ ENTRY(_user_exception) | |||
208 | lwi r1, r1, TS_THREAD_INFO /* get the thread info */ | 208 | lwi r1, r1, TS_THREAD_INFO /* get the thread info */ |
209 | /* calculate kernel stack pointer */ | 209 | /* calculate kernel stack pointer */ |
210 | addik r1, r1, THREAD_SIZE - PT_SIZE | 210 | addik r1, r1, THREAD_SIZE - PT_SIZE |
211 | swi r11, r0, PER_CPU(R11_SAVE) /* temporarily save r11 */ | ||
212 | lwi r11, r0, PER_CPU(KM) /* load mode indicator */ | ||
213 | 2: | 211 | 2: |
214 | swi r11, r1, PT_MODE /* store the mode */ | 212 | swi r11, r1, PT_MODE /* store the mode */ |
215 | lwi r11, r0, PER_CPU(R11_SAVE) /* reload r11 */ | 213 | lwi r11, r0, PER_CPU(R11_SAVE) /* reload r11 */ |
diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index acc1f05d1e2c..3bad4ff49471 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S | |||
@@ -31,6 +31,8 @@ | |||
31 | #include <linux/errno.h> | 31 | #include <linux/errno.h> |
32 | #include <asm/signal.h> | 32 | #include <asm/signal.h> |
33 | 33 | ||
34 | #undef DEBUG | ||
35 | |||
34 | /* The size of a state save frame. */ | 36 | /* The size of a state save frame. */ |
35 | #define STATE_SAVE_SIZE (PT_SIZE + STATE_SAVE_ARG_SPACE) | 37 | #define STATE_SAVE_SIZE (PT_SIZE + STATE_SAVE_ARG_SPACE) |
36 | 38 | ||
@@ -352,10 +354,12 @@ C_ENTRY(_user_exception): | |||
352 | add r12, r12, r12; /* convert num -> ptr */ | 354 | add r12, r12, r12; /* convert num -> ptr */ |
353 | add r12, r12, r12; | 355 | add r12, r12, r12; |
354 | 356 | ||
357 | #ifdef DEBUG | ||
355 | /* Trac syscalls and stored them to r0_ram */ | 358 | /* Trac syscalls and stored them to r0_ram */ |
356 | lwi r3, r12, 0x400 + r0_ram | 359 | lwi r3, r12, 0x400 + r0_ram |
357 | addi r3, r3, 1 | 360 | addi r3, r3, 1 |
358 | swi r3, r12, 0x400 + r0_ram | 361 | swi r3, r12, 0x400 + r0_ram |
362 | #endif | ||
359 | 363 | ||
360 | # Find and jump into the syscall handler. | 364 | # Find and jump into the syscall handler. |
361 | lwi r12, r12, sys_call_table | 365 | lwi r12, r12, sys_call_table |
@@ -496,17 +500,6 @@ C_ENTRY(sys_execve): | |||
496 | brid microblaze_execve; /* Do real work (tail-call).*/ | 500 | brid microblaze_execve; /* Do real work (tail-call).*/ |
497 | nop; | 501 | nop; |
498 | 502 | ||
499 | C_ENTRY(sys_rt_sigsuspend_wrapper): | ||
500 | swi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ | ||
501 | swi r4, r1, PTO+PT_R4; | ||
502 | la r7, r1, PTO; /* add user context as 3rd arg */ | ||
503 | brlid r15, sys_rt_sigsuspend; /* Do real work.*/ | ||
504 | nop; | ||
505 | lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ | ||
506 | lwi r4, r1, PTO+PT_R4; | ||
507 | bri ret_from_trap /* fall through will not work here due to align */ | ||
508 | nop; | ||
509 | |||
510 | C_ENTRY(sys_rt_sigreturn_wrapper): | 503 | C_ENTRY(sys_rt_sigreturn_wrapper): |
511 | swi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ | 504 | swi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ |
512 | swi r4, r1, PTO+PT_R4; | 505 | swi r4, r1, PTO+PT_R4; |
@@ -592,6 +585,8 @@ C_ENTRY(full_exception_trap): | |||
592 | nop | 585 | nop |
593 | mfs r7, rfsr; /* save FSR */ | 586 | mfs r7, rfsr; /* save FSR */ |
594 | nop | 587 | nop |
588 | mts rfsr, r0; /* Clear sticky fsr */ | ||
589 | nop | ||
595 | la r12, r0, full_exception | 590 | la r12, r0, full_exception |
596 | set_vms; | 591 | set_vms; |
597 | rtbd r12, 0; | 592 | rtbd r12, 0; |
@@ -709,15 +704,11 @@ C_ENTRY(ret_from_exc): | |||
709 | * (in a possibly modified form) after do_signal returns. | 704 | * (in a possibly modified form) after do_signal returns. |
710 | * store return registers separately because this macros is use | 705 | * store return registers separately because this macros is use |
711 | * for others exceptions */ | 706 | * for others exceptions */ |
712 | swi r3, r1, PTO + PT_R3; | ||
713 | swi r4, r1, PTO + PT_R4; | ||
714 | la r5, r1, PTO; /* Arg 1: struct pt_regs *regs */ | 707 | la r5, r1, PTO; /* Arg 1: struct pt_regs *regs */ |
715 | add r6, r0, r0; /* Arg 2: sigset_t *oldset */ | 708 | add r6, r0, r0; /* Arg 2: sigset_t *oldset */ |
716 | addi r7, r0, 0; /* Arg 3: int in_syscall */ | 709 | addi r7, r0, 0; /* Arg 3: int in_syscall */ |
717 | bralid r15, do_signal; /* Handle any signals */ | 710 | bralid r15, do_signal; /* Handle any signals */ |
718 | nop; | 711 | nop; |
719 | lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ | ||
720 | lwi r4, r1, PTO+PT_R4; | ||
721 | 712 | ||
722 | /* Finally, return to user state. */ | 713 | /* Finally, return to user state. */ |
723 | 1: swi r0, r0, PER_CPU(KM); /* Now officially in user state. */ | 714 | 1: swi r0, r0, PER_CPU(KM); /* Now officially in user state. */ |
diff --git a/arch/microblaze/kernel/ftrace.c b/arch/microblaze/kernel/ftrace.c new file mode 100644 index 000000000000..388b31ca65a1 --- /dev/null +++ b/arch/microblaze/kernel/ftrace.c | |||
@@ -0,0 +1,237 @@ | |||
1 | /* | ||
2 | * Ftrace support for Microblaze. | ||
3 | * | ||
4 | * Copyright (C) 2009 Michal Simek <monstr@monstr.eu> | ||
5 | * Copyright (C) 2009 PetaLogix | ||
6 | * | ||
7 | * Based on MIPS and PowerPC ftrace code | ||
8 | * | ||
9 | * This file is subject to the terms and conditions of the GNU General Public | ||
10 | * License. See the file "COPYING" in the main directory of this archive | ||
11 | * for more details. | ||
12 | */ | ||
13 | |||
14 | #include <asm/cacheflush.h> | ||
15 | #include <linux/ftrace.h> | ||
16 | |||
17 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
18 | /* | ||
19 | * Hook the return address and push it in the stack of return addrs | ||
20 | * in current thread info. | ||
21 | */ | ||
22 | void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) | ||
23 | { | ||
24 | unsigned long old; | ||
25 | int faulted, err; | ||
26 | struct ftrace_graph_ent trace; | ||
27 | unsigned long return_hooker = (unsigned long) | ||
28 | &return_to_handler; | ||
29 | |||
30 | if (unlikely(atomic_read(¤t->tracing_graph_pause))) | ||
31 | return; | ||
32 | |||
33 | /* | ||
34 | * Protect against fault, even if it shouldn't | ||
35 | * happen. This tool is too much intrusive to | ||
36 | * ignore such a protection. | ||
37 | */ | ||
38 | asm volatile(" 1: lwi %0, %2, 0; \ | ||
39 | 2: swi %3, %2, 0; \ | ||
40 | addik %1, r0, 0; \ | ||
41 | 3: \ | ||
42 | .section .fixup, \"ax\"; \ | ||
43 | 4: brid 3b; \ | ||
44 | addik %1, r0, 1; \ | ||
45 | .previous; \ | ||
46 | .section __ex_table,\"a\"; \ | ||
47 | .word 1b,4b; \ | ||
48 | .word 2b,4b; \ | ||
49 | .previous;" \ | ||
50 | : "=&r" (old), "=r" (faulted) | ||
51 | : "r" (parent), "r" (return_hooker) | ||
52 | ); | ||
53 | |||
54 | if (unlikely(faulted)) { | ||
55 | ftrace_graph_stop(); | ||
56 | WARN_ON(1); | ||
57 | return; | ||
58 | } | ||
59 | |||
60 | err = ftrace_push_return_trace(old, self_addr, &trace.depth, 0); | ||
61 | if (err == -EBUSY) { | ||
62 | *parent = old; | ||
63 | return; | ||
64 | } | ||
65 | |||
66 | trace.func = self_addr; | ||
67 | /* Only trace if the calling function expects to */ | ||
68 | if (!ftrace_graph_entry(&trace)) { | ||
69 | current->curr_ret_stack--; | ||
70 | *parent = old; | ||
71 | } | ||
72 | } | ||
73 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
74 | |||
75 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
76 | /* save value to addr - it is save to do it in asm */ | ||
77 | static int ftrace_modify_code(unsigned long addr, unsigned int value) | ||
78 | { | ||
79 | int faulted = 0; | ||
80 | |||
81 | __asm__ __volatile__(" 1: swi %2, %1, 0; \ | ||
82 | addik %0, r0, 0; \ | ||
83 | 2: \ | ||
84 | .section .fixup, \"ax\"; \ | ||
85 | 3: brid 2b; \ | ||
86 | addik %0, r0, 1; \ | ||
87 | .previous; \ | ||
88 | .section __ex_table,\"a\"; \ | ||
89 | .word 1b,3b; \ | ||
90 | .previous;" \ | ||
91 | : "=r" (faulted) | ||
92 | : "r" (addr), "r" (value) | ||
93 | ); | ||
94 | |||
95 | if (unlikely(faulted)) | ||
96 | return -EFAULT; | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | #define MICROBLAZE_NOP 0x80000000 | ||
102 | #define MICROBLAZE_BRI 0xb800000C | ||
103 | |||
104 | static unsigned int recorded; /* if save was or not */ | ||
105 | static unsigned int imm; /* saving whole imm instruction */ | ||
106 | |||
107 | /* There are two approaches howto solve ftrace_make nop function - look below */ | ||
108 | #undef USE_FTRACE_NOP | ||
109 | |||
110 | #ifdef USE_FTRACE_NOP | ||
111 | static unsigned int bralid; /* saving whole bralid instruction */ | ||
112 | #endif | ||
113 | |||
114 | int ftrace_make_nop(struct module *mod, | ||
115 | struct dyn_ftrace *rec, unsigned long addr) | ||
116 | { | ||
117 | /* we have this part of code which we are working with | ||
118 | * b000c000 imm -16384 | ||
119 | * b9fc8e30 bralid r15, -29136 // c0008e30 <_mcount> | ||
120 | * 80000000 or r0, r0, r0 | ||
121 | * | ||
122 | * The first solution (!USE_FTRACE_NOP-could be called branch solution) | ||
123 | * b000c000 bri 12 (0xC - jump to any other instruction) | ||
124 | * b9fc8e30 bralid r15, -29136 // c0008e30 <_mcount> | ||
125 | * 80000000 or r0, r0, r0 | ||
126 | * any other instruction | ||
127 | * | ||
128 | * The second solution (USE_FTRACE_NOP) - no jump just nops | ||
129 | * 80000000 or r0, r0, r0 | ||
130 | * 80000000 or r0, r0, r0 | ||
131 | * 80000000 or r0, r0, r0 | ||
132 | */ | ||
133 | int ret = 0; | ||
134 | |||
135 | if (recorded == 0) { | ||
136 | recorded = 1; | ||
137 | imm = *(unsigned int *)rec->ip; | ||
138 | pr_debug("%s: imm:0x%x\n", __func__, imm); | ||
139 | #ifdef USE_FTRACE_NOP | ||
140 | bralid = *(unsigned int *)(rec->ip + 4); | ||
141 | pr_debug("%s: bralid 0x%x\n", __func__, bralid); | ||
142 | #endif /* USE_FTRACE_NOP */ | ||
143 | } | ||
144 | |||
145 | #ifdef USE_FTRACE_NOP | ||
146 | ret = ftrace_modify_code(rec->ip, MICROBLAZE_NOP); | ||
147 | ret += ftrace_modify_code(rec->ip + 4, MICROBLAZE_NOP); | ||
148 | #else /* USE_FTRACE_NOP */ | ||
149 | ret = ftrace_modify_code(rec->ip, MICROBLAZE_BRI); | ||
150 | #endif /* USE_FTRACE_NOP */ | ||
151 | return ret; | ||
152 | } | ||
153 | |||
154 | static int ret_addr; /* initialized as 0 by default */ | ||
155 | |||
156 | /* I believe that first is called ftrace_make_nop before this function */ | ||
157 | int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | ||
158 | { | ||
159 | int ret; | ||
160 | ret_addr = addr; /* saving where the barrier jump is */ | ||
161 | pr_debug("%s: addr:0x%x, rec->ip: 0x%x, imm:0x%x\n", | ||
162 | __func__, (unsigned int)addr, (unsigned int)rec->ip, imm); | ||
163 | ret = ftrace_modify_code(rec->ip, imm); | ||
164 | #ifdef USE_FTRACE_NOP | ||
165 | pr_debug("%s: bralid:0x%x\n", __func__, bralid); | ||
166 | ret += ftrace_modify_code(rec->ip + 4, bralid); | ||
167 | #endif /* USE_FTRACE_NOP */ | ||
168 | return ret; | ||
169 | } | ||
170 | |||
171 | int __init ftrace_dyn_arch_init(void *data) | ||
172 | { | ||
173 | /* The return code is retured via data */ | ||
174 | *(unsigned long *)data = 0; | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | int ftrace_update_ftrace_func(ftrace_func_t func) | ||
180 | { | ||
181 | unsigned long ip = (unsigned long)(&ftrace_call); | ||
182 | unsigned int upper = (unsigned int)func; | ||
183 | unsigned int lower = (unsigned int)func; | ||
184 | int ret = 0; | ||
185 | |||
186 | /* create proper saving to ftrace_call poll */ | ||
187 | upper = 0xb0000000 + (upper >> 16); /* imm func_upper */ | ||
188 | lower = 0x32800000 + (lower & 0xFFFF); /* addik r20, r0, func_lower */ | ||
189 | |||
190 | pr_debug("%s: func=0x%x, ip=0x%x, upper=0x%x, lower=0x%x\n", | ||
191 | __func__, (unsigned int)func, (unsigned int)ip, upper, lower); | ||
192 | |||
193 | /* save upper and lower code */ | ||
194 | ret = ftrace_modify_code(ip, upper); | ||
195 | ret += ftrace_modify_code(ip + 4, lower); | ||
196 | |||
197 | /* We just need to remove the rtsd r15, 8 by NOP */ | ||
198 | BUG_ON(!ret_addr); | ||
199 | if (ret_addr) | ||
200 | ret += ftrace_modify_code(ret_addr, MICROBLAZE_NOP); | ||
201 | else | ||
202 | ret = 1; /* fault */ | ||
203 | |||
204 | /* All changes are done - lets do caches consistent */ | ||
205 | flush_icache(); | ||
206 | return ret; | ||
207 | } | ||
208 | |||
209 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
210 | unsigned int old_jump; /* saving place for jump instruction */ | ||
211 | |||
212 | int ftrace_enable_ftrace_graph_caller(void) | ||
213 | { | ||
214 | unsigned int ret; | ||
215 | unsigned long ip = (unsigned long)(&ftrace_call_graph); | ||
216 | |||
217 | old_jump = *(unsigned int *)ip; /* save jump over instruction */ | ||
218 | ret = ftrace_modify_code(ip, MICROBLAZE_NOP); | ||
219 | flush_icache(); | ||
220 | |||
221 | pr_debug("%s: Replace instruction: 0x%x\n", __func__, old_jump); | ||
222 | return ret; | ||
223 | } | ||
224 | |||
225 | int ftrace_disable_ftrace_graph_caller(void) | ||
226 | { | ||
227 | unsigned int ret; | ||
228 | unsigned long ip = (unsigned long)(&ftrace_call_graph); | ||
229 | |||
230 | ret = ftrace_modify_code(ip, old_jump); | ||
231 | flush_icache(); | ||
232 | |||
233 | pr_debug("%s\n", __func__); | ||
234 | return ret; | ||
235 | } | ||
236 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
237 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S index 697ce3007f30..30916193fcc7 100644 --- a/arch/microblaze/kernel/head.S +++ b/arch/microblaze/kernel/head.S | |||
@@ -31,7 +31,7 @@ | |||
31 | #include <linux/linkage.h> | 31 | #include <linux/linkage.h> |
32 | #include <asm/thread_info.h> | 32 | #include <asm/thread_info.h> |
33 | #include <asm/page.h> | 33 | #include <asm/page.h> |
34 | #include <asm/prom.h> /* for OF_DT_HEADER */ | 34 | #include <linux/of_fdt.h> /* for OF_DT_HEADER */ |
35 | 35 | ||
36 | #ifdef CONFIG_MMU | 36 | #ifdef CONFIG_MMU |
37 | #include <asm/setup.h> /* COMMAND_LINE_SIZE */ | 37 | #include <asm/setup.h> /* COMMAND_LINE_SIZE */ |
diff --git a/arch/microblaze/kernel/heartbeat.c b/arch/microblaze/kernel/heartbeat.c index 1bdf20222b92..522751737cfa 100644 --- a/arch/microblaze/kernel/heartbeat.c +++ b/arch/microblaze/kernel/heartbeat.c | |||
@@ -45,6 +45,7 @@ void heartbeat(void) | |||
45 | void setup_heartbeat(void) | 45 | void setup_heartbeat(void) |
46 | { | 46 | { |
47 | struct device_node *gpio = NULL; | 47 | struct device_node *gpio = NULL; |
48 | int *prop; | ||
48 | int j; | 49 | int j; |
49 | char *gpio_list[] = { | 50 | char *gpio_list[] = { |
50 | "xlnx,xps-gpio-1.00.a", | 51 | "xlnx,xps-gpio-1.00.a", |
@@ -58,10 +59,14 @@ void setup_heartbeat(void) | |||
58 | break; | 59 | break; |
59 | } | 60 | } |
60 | 61 | ||
61 | base_addr = *(int *) of_get_property(gpio, "reg", NULL); | 62 | if (gpio) { |
62 | base_addr = (unsigned long) ioremap(base_addr, PAGE_SIZE); | 63 | base_addr = *(int *) of_get_property(gpio, "reg", NULL); |
63 | printk(KERN_NOTICE "Heartbeat GPIO at 0x%x\n", base_addr); | 64 | base_addr = (unsigned long) ioremap(base_addr, PAGE_SIZE); |
65 | printk(KERN_NOTICE "Heartbeat GPIO at 0x%x\n", base_addr); | ||
64 | 66 | ||
65 | if (*(int *) of_get_property(gpio, "xlnx,is-bidir", NULL)) | 67 | /* GPIO is configured as output */ |
66 | out_be32(base_addr + 4, 0); /* GPIO is configured as output */ | 68 | prop = (int *) of_get_property(gpio, "xlnx,is-bidir", NULL); |
69 | if (prop) | ||
70 | out_be32(base_addr + 4, 0); | ||
71 | } | ||
67 | } | 72 | } |
diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S index 6b0288ebccd6..2b86c03aa841 100644 --- a/arch/microblaze/kernel/hw_exception_handler.S +++ b/arch/microblaze/kernel/hw_exception_handler.S | |||
@@ -384,7 +384,7 @@ handle_other_ex: /* Handle Other exceptions here */ | |||
384 | addk r8, r17, r0; /* Load exception address */ | 384 | addk r8, r17, r0; /* Load exception address */ |
385 | bralid r15, full_exception; /* Branch to the handler */ | 385 | bralid r15, full_exception; /* Branch to the handler */ |
386 | nop; | 386 | nop; |
387 | mts r0, rfsr; /* Clear sticky fsr */ | 387 | mts rfsr, r0; /* Clear sticky fsr */ |
388 | nop | 388 | nop |
389 | 389 | ||
390 | /* | 390 | /* |
diff --git a/arch/microblaze/kernel/intc.c b/arch/microblaze/kernel/intc.c index 6eea6f92b84e..03172c1da770 100644 --- a/arch/microblaze/kernel/intc.c +++ b/arch/microblaze/kernel/intc.c | |||
@@ -42,8 +42,16 @@ unsigned int nr_irq; | |||
42 | 42 | ||
43 | static void intc_enable_or_unmask(unsigned int irq) | 43 | static void intc_enable_or_unmask(unsigned int irq) |
44 | { | 44 | { |
45 | unsigned long mask = 1 << irq; | ||
45 | pr_debug("enable_or_unmask: %d\n", irq); | 46 | pr_debug("enable_or_unmask: %d\n", irq); |
46 | out_be32(INTC_BASE + SIE, 1 << irq); | 47 | out_be32(INTC_BASE + SIE, mask); |
48 | |||
49 | /* ack level irqs because they can't be acked during | ||
50 | * ack function since the handle_level_irq function | ||
51 | * acks the irq before calling the interrupt handler | ||
52 | */ | ||
53 | if (irq_desc[irq].status & IRQ_LEVEL) | ||
54 | out_be32(INTC_BASE + IAR, mask); | ||
47 | } | 55 | } |
48 | 56 | ||
49 | static void intc_disable_or_mask(unsigned int irq) | 57 | static void intc_disable_or_mask(unsigned int irq) |
diff --git a/arch/microblaze/kernel/irq.c b/arch/microblaze/kernel/irq.c index 7d5ddd62d4d2..0f06034d1fe0 100644 --- a/arch/microblaze/kernel/irq.c +++ b/arch/microblaze/kernel/irq.c | |||
@@ -68,7 +68,7 @@ int show_interrupts(struct seq_file *p, void *v) | |||
68 | } | 68 | } |
69 | 69 | ||
70 | if (i < nr_irq) { | 70 | if (i < nr_irq) { |
71 | spin_lock_irqsave(&irq_desc[i].lock, flags); | 71 | raw_spin_lock_irqsave(&irq_desc[i].lock, flags); |
72 | action = irq_desc[i].action; | 72 | action = irq_desc[i].action; |
73 | if (!action) | 73 | if (!action) |
74 | goto skip; | 74 | goto skip; |
@@ -89,7 +89,7 @@ int show_interrupts(struct seq_file *p, void *v) | |||
89 | 89 | ||
90 | seq_putc(p, '\n'); | 90 | seq_putc(p, '\n'); |
91 | skip: | 91 | skip: |
92 | spin_unlock_irqrestore(&irq_desc[i].lock, flags); | 92 | raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags); |
93 | } | 93 | } |
94 | return 0; | 94 | return 0; |
95 | } | 95 | } |
diff --git a/arch/microblaze/kernel/mcount.S b/arch/microblaze/kernel/mcount.S new file mode 100644 index 000000000000..e7eaa7a8cbd3 --- /dev/null +++ b/arch/microblaze/kernel/mcount.S | |||
@@ -0,0 +1,170 @@ | |||
1 | /* | ||
2 | * Low-level ftrace handling | ||
3 | * | ||
4 | * Copyright (C) 2009 Michal Simek <monstr@monstr.eu> | ||
5 | * Copyright (C) 2009 PetaLogix | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General | ||
8 | * Public License. See the file COPYING in the main directory of this | ||
9 | * archive for more details. | ||
10 | */ | ||
11 | |||
12 | #include <linux/linkage.h> | ||
13 | |||
14 | #define NOALIGN_ENTRY(name) .globl name; name: | ||
15 | |||
16 | /* FIXME MS: I think that I don't need to save all regs */ | ||
17 | #define SAVE_REGS \ | ||
18 | addik r1, r1, -120; \ | ||
19 | swi r2, r1, 4; \ | ||
20 | swi r3, r1, 8; \ | ||
21 | swi r4, r1, 12; \ | ||
22 | swi r5, r1, 116; \ | ||
23 | swi r6, r1, 16; \ | ||
24 | swi r7, r1, 20; \ | ||
25 | swi r8, r1, 24; \ | ||
26 | swi r9, r1, 28; \ | ||
27 | swi r10, r1, 32; \ | ||
28 | swi r11, r1, 36; \ | ||
29 | swi r12, r1, 40; \ | ||
30 | swi r13, r1, 44; \ | ||
31 | swi r14, r1, 48; \ | ||
32 | swi r16, r1, 52; \ | ||
33 | swi r17, r1, 56; \ | ||
34 | swi r18, r1, 60; \ | ||
35 | swi r19, r1, 64; \ | ||
36 | swi r20, r1, 68; \ | ||
37 | swi r21, r1, 72; \ | ||
38 | swi r22, r1, 76; \ | ||
39 | swi r23, r1, 80; \ | ||
40 | swi r24, r1, 84; \ | ||
41 | swi r25, r1, 88; \ | ||
42 | swi r26, r1, 92; \ | ||
43 | swi r27, r1, 96; \ | ||
44 | swi r28, r1, 100; \ | ||
45 | swi r29, r1, 104; \ | ||
46 | swi r30, r1, 108; \ | ||
47 | swi r31, r1, 112; | ||
48 | |||
49 | #define RESTORE_REGS \ | ||
50 | lwi r2, r1, 4; \ | ||
51 | lwi r3, r1, 8; \ | ||
52 | lwi r4, r1, 12; \ | ||
53 | lwi r5, r1, 116; \ | ||
54 | lwi r6, r1, 16; \ | ||
55 | lwi r7, r1, 20; \ | ||
56 | lwi r8, r1, 24; \ | ||
57 | lwi r9, r1, 28; \ | ||
58 | lwi r10, r1, 32; \ | ||
59 | lwi r11, r1, 36; \ | ||
60 | lwi r12, r1, 40; \ | ||
61 | lwi r13, r1, 44; \ | ||
62 | lwi r14, r1, 48; \ | ||
63 | lwi r16, r1, 52; \ | ||
64 | lwi r17, r1, 56; \ | ||
65 | lwi r18, r1, 60; \ | ||
66 | lwi r19, r1, 64; \ | ||
67 | lwi r20, r1, 68; \ | ||
68 | lwi r21, r1, 72; \ | ||
69 | lwi r22, r1, 76; \ | ||
70 | lwi r23, r1, 80; \ | ||
71 | lwi r24, r1, 84; \ | ||
72 | lwi r25, r1, 88; \ | ||
73 | lwi r26, r1, 92; \ | ||
74 | lwi r27, r1, 96; \ | ||
75 | lwi r28, r1, 100; \ | ||
76 | lwi r29, r1, 104; \ | ||
77 | lwi r30, r1, 108; \ | ||
78 | lwi r31, r1, 112; \ | ||
79 | addik r1, r1, 120; | ||
80 | |||
81 | ENTRY(ftrace_stub) | ||
82 | rtsd r15, 8; | ||
83 | nop; | ||
84 | |||
85 | ENTRY(_mcount) | ||
86 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
87 | ENTRY(ftrace_caller) | ||
88 | /* MS: It is just barrier which is removed from C code */ | ||
89 | rtsd r15, 8 | ||
90 | nop | ||
91 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
92 | SAVE_REGS | ||
93 | swi r15, r1, 0; | ||
94 | /* MS: HAVE_FUNCTION_TRACE_MCOUNT_TEST begin of checking */ | ||
95 | lwi r5, r0, function_trace_stop; | ||
96 | bneid r5, end; | ||
97 | nop; | ||
98 | /* MS: HAVE_FUNCTION_TRACE_MCOUNT_TEST end of checking */ | ||
99 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
100 | #ifndef CONFIG_DYNAMIC_FTRACE | ||
101 | lwi r5, r0, ftrace_graph_return; | ||
102 | addik r6, r0, ftrace_stub; /* asm implementation */ | ||
103 | cmpu r5, r5, r6; /* ftrace_graph_return != ftrace_stub */ | ||
104 | beqid r5, end_graph_tracer; | ||
105 | nop; | ||
106 | |||
107 | lwi r6, r0, ftrace_graph_entry; | ||
108 | addik r5, r0, ftrace_graph_entry_stub; /* implemented in C */ | ||
109 | cmpu r5, r5, r6; /* ftrace_graph_entry != ftrace_graph_entry_stub */ | ||
110 | beqid r5, end_graph_tracer; | ||
111 | nop; | ||
112 | #else /* CONFIG_DYNAMIC_FTRACE */ | ||
113 | NOALIGN_ENTRY(ftrace_call_graph) | ||
114 | /* MS: jump over graph function - replaced from C code */ | ||
115 | bri end_graph_tracer | ||
116 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
117 | addik r5, r1, 120; /* MS: load parent addr */ | ||
118 | addik r6, r15, 0; /* MS: load current function addr */ | ||
119 | bralid r15, prepare_ftrace_return; | ||
120 | nop; | ||
121 | /* MS: graph was taken that's why - can jump over function trace */ | ||
122 | brid end; | ||
123 | nop; | ||
124 | end_graph_tracer: | ||
125 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
126 | #ifndef CONFIG_DYNAMIC_FTRACE | ||
127 | /* MS: test function trace if is taken or not */ | ||
128 | lwi r20, r0, ftrace_trace_function; | ||
129 | addik r6, r0, ftrace_stub; | ||
130 | cmpu r5, r20, r6; /* ftrace_trace_function != ftrace_stub */ | ||
131 | beqid r5, end; /* MS: not taken -> jump over */ | ||
132 | nop; | ||
133 | #else /* CONFIG_DYNAMIC_FTRACE */ | ||
134 | NOALIGN_ENTRY(ftrace_call) | ||
135 | /* instruction for setup imm FUNC_part1, addik r20, r0, FUNC_part2 */ | ||
136 | nop | ||
137 | nop | ||
138 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
139 | /* static normal trace */ | ||
140 | lwi r6, r1, 120; /* MS: load parent addr */ | ||
141 | addik r5, r15, 0; /* MS: load current function addr */ | ||
142 | /* MS: here is dependency on previous code */ | ||
143 | brald r15, r20; /* MS: jump to ftrace handler */ | ||
144 | nop; | ||
145 | end: | ||
146 | lwi r15, r1, 0; | ||
147 | RESTORE_REGS | ||
148 | |||
149 | rtsd r15, 8; /* MS: jump back */ | ||
150 | nop; | ||
151 | |||
152 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
153 | ENTRY(return_to_handler) | ||
154 | nop; /* MS: just barrier for rtsd r15, 8 */ | ||
155 | nop; | ||
156 | SAVE_REGS | ||
157 | swi r15, r1, 0; | ||
158 | |||
159 | /* MS: find out returning address */ | ||
160 | bralid r15, ftrace_return_to_handler; | ||
161 | nop; | ||
162 | |||
163 | /* MS: return value from ftrace_return_to_handler is my returning addr | ||
164 | * must be before restore regs because I have to restore r3 content */ | ||
165 | addik r15, r3, 0; | ||
166 | RESTORE_REGS | ||
167 | |||
168 | rtsd r15, 8; /* MS: jump back */ | ||
169 | nop; | ||
170 | #endif /* CONFIG_FUNCTION_TRACER */ | ||
diff --git a/arch/microblaze/kernel/microblaze_ksyms.c b/arch/microblaze/kernel/microblaze_ksyms.c index 59ff20e33e0c..bc4dcb7d3861 100644 --- a/arch/microblaze/kernel/microblaze_ksyms.c +++ b/arch/microblaze/kernel/microblaze_ksyms.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
19 | #include <asm/page.h> | 19 | #include <asm/page.h> |
20 | #include <asm/system.h> | 20 | #include <asm/system.h> |
21 | #include <linux/ftrace.h> | ||
21 | #include <linux/uaccess.h> | 22 | #include <linux/uaccess.h> |
22 | 23 | ||
23 | /* | 24 | /* |
@@ -47,3 +48,7 @@ extern void __umodsi3(void); | |||
47 | EXPORT_SYMBOL(__umodsi3); | 48 | EXPORT_SYMBOL(__umodsi3); |
48 | extern char *_ebss; | 49 | extern char *_ebss; |
49 | EXPORT_SYMBOL_GPL(_ebss); | 50 | EXPORT_SYMBOL_GPL(_ebss); |
51 | #ifdef CONFIG_FUNCTION_TRACER | ||
52 | extern void _mcount(void); | ||
53 | EXPORT_SYMBOL(_mcount); | ||
54 | #endif | ||
diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c index 4201c743cc9f..812f1bf06c9e 100644 --- a/arch/microblaze/kernel/process.c +++ b/arch/microblaze/kernel/process.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/bitops.h> | 15 | #include <linux/bitops.h> |
16 | #include <asm/system.h> | 16 | #include <asm/system.h> |
17 | #include <asm/pgalloc.h> | 17 | #include <asm/pgalloc.h> |
18 | #include <asm/cacheflush.h> | ||
18 | 19 | ||
19 | void show_regs(struct pt_regs *regs) | 20 | void show_regs(struct pt_regs *regs) |
20 | { | 21 | { |
@@ -235,7 +236,9 @@ void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp) | |||
235 | regs->pc = pc; | 236 | regs->pc = pc; |
236 | regs->r1 = usp; | 237 | regs->r1 = usp; |
237 | regs->pt_mode = 0; | 238 | regs->pt_mode = 0; |
239 | #ifdef CONFIG_MMU | ||
238 | regs->msr |= MSR_UMS; | 240 | regs->msr |= MSR_UMS; |
241 | #endif | ||
239 | } | 242 | } |
240 | 243 | ||
241 | #ifdef CONFIG_MMU | 244 | #ifdef CONFIG_MMU |
diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index c005cc6f1aaf..b817df172aa9 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c | |||
@@ -860,29 +860,6 @@ struct device_node *of_find_node_by_phandle(phandle handle) | |||
860 | EXPORT_SYMBOL(of_find_node_by_phandle); | 860 | EXPORT_SYMBOL(of_find_node_by_phandle); |
861 | 861 | ||
862 | /** | 862 | /** |
863 | * of_find_all_nodes - Get next node in global list | ||
864 | * @prev: Previous node or NULL to start iteration | ||
865 | * of_node_put() will be called on it | ||
866 | * | ||
867 | * Returns a node pointer with refcount incremented, use | ||
868 | * of_node_put() on it when done. | ||
869 | */ | ||
870 | struct device_node *of_find_all_nodes(struct device_node *prev) | ||
871 | { | ||
872 | struct device_node *np; | ||
873 | |||
874 | read_lock(&devtree_lock); | ||
875 | np = prev ? prev->allnext : allnodes; | ||
876 | for (; np != NULL; np = np->allnext) | ||
877 | if (of_node_get(np)) | ||
878 | break; | ||
879 | of_node_put(prev); | ||
880 | read_unlock(&devtree_lock); | ||
881 | return np; | ||
882 | } | ||
883 | EXPORT_SYMBOL(of_find_all_nodes); | ||
884 | |||
885 | /** | ||
886 | * of_node_get - Increment refcount of a node | 863 | * of_node_get - Increment refcount of a node |
887 | * @node: Node to inc refcount, NULL is supported to | 864 | * @node: Node to inc refcount, NULL is supported to |
888 | * simplify writing of callers | 865 | * simplify writing of callers |
diff --git a/arch/microblaze/kernel/reset.c b/arch/microblaze/kernel/reset.c new file mode 100644 index 000000000000..a1721a33042e --- /dev/null +++ b/arch/microblaze/kernel/reset.c | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Michal Simek <monstr@monstr.eu> | ||
3 | * Copyright (C) 2009 PetaLogix | ||
4 | * | ||
5 | * This file is subject to the terms and conditions of the GNU General Public | ||
6 | * License. See the file "COPYING" in the main directory of this archive | ||
7 | * for more details. | ||
8 | */ | ||
9 | |||
10 | #include <linux/init.h> | ||
11 | #include <linux/of_platform.h> | ||
12 | #include <asm/prom.h> | ||
13 | |||
14 | /* Trigger specific functions */ | ||
15 | #ifdef CONFIG_GPIOLIB | ||
16 | |||
17 | #include <linux/of_gpio.h> | ||
18 | |||
19 | static int handle; /* reset pin handle */ | ||
20 | static unsigned int reset_val; | ||
21 | |||
22 | static int of_reset_gpio_handle(void) | ||
23 | { | ||
24 | int ret; /* variable which stored handle reset gpio pin */ | ||
25 | struct device_node *root; /* root node */ | ||
26 | struct device_node *gpio; /* gpio node */ | ||
27 | struct of_gpio_chip *of_gc = NULL; | ||
28 | enum of_gpio_flags flags ; | ||
29 | const void *gpio_spec; | ||
30 | |||
31 | /* find out root node */ | ||
32 | root = of_find_node_by_path("/"); | ||
33 | |||
34 | /* give me handle for gpio node to be possible allocate pin */ | ||
35 | ret = of_parse_phandles_with_args(root, "hard-reset-gpios", | ||
36 | "#gpio-cells", 0, &gpio, &gpio_spec); | ||
37 | if (ret) { | ||
38 | pr_debug("%s: can't parse gpios property\n", __func__); | ||
39 | goto err0; | ||
40 | } | ||
41 | |||
42 | of_gc = gpio->data; | ||
43 | if (!of_gc) { | ||
44 | pr_debug("%s: gpio controller %s isn't registered\n", | ||
45 | root->full_name, gpio->full_name); | ||
46 | ret = -ENODEV; | ||
47 | goto err1; | ||
48 | } | ||
49 | |||
50 | ret = of_gc->xlate(of_gc, root, gpio_spec, &flags); | ||
51 | if (ret < 0) | ||
52 | goto err1; | ||
53 | |||
54 | ret += of_gc->gc.base; | ||
55 | err1: | ||
56 | of_node_put(gpio); | ||
57 | err0: | ||
58 | pr_debug("%s exited with status %d\n", __func__, ret); | ||
59 | return ret; | ||
60 | } | ||
61 | |||
62 | void of_platform_reset_gpio_probe(void) | ||
63 | { | ||
64 | int ret; | ||
65 | handle = of_reset_gpio_handle(); | ||
66 | |||
67 | if (!gpio_is_valid(handle)) { | ||
68 | printk(KERN_INFO "Skipping unavailable RESET gpio %d (%s)\n", | ||
69 | handle, "reset"); | ||
70 | } | ||
71 | |||
72 | ret = gpio_request(handle, "reset"); | ||
73 | if (ret < 0) { | ||
74 | printk(KERN_INFO "GPIO pin is already allocated\n"); | ||
75 | return; | ||
76 | } | ||
77 | |||
78 | /* get current setup value */ | ||
79 | reset_val = gpio_get_value(handle); | ||
80 | /* FIXME maybe worth to perform any action */ | ||
81 | pr_debug("Reset: Gpio output state: 0x%x\n", reset_val); | ||
82 | |||
83 | /* Setup GPIO as output */ | ||
84 | ret = gpio_direction_output(handle, 0); | ||
85 | if (ret < 0) | ||
86 | goto err; | ||
87 | |||
88 | /* Setup output direction */ | ||
89 | gpio_set_value(handle, 0); | ||
90 | |||
91 | printk(KERN_INFO "RESET: Registered gpio device: %d, current val: %d\n", | ||
92 | handle, reset_val); | ||
93 | return; | ||
94 | err: | ||
95 | gpio_free(handle); | ||
96 | return; | ||
97 | } | ||
98 | |||
99 | |||
100 | static void gpio_system_reset(void) | ||
101 | { | ||
102 | gpio_set_value(handle, 1 - reset_val); | ||
103 | } | ||
104 | #else | ||
105 | #define gpio_system_reset() do {} while (0) | ||
106 | void of_platform_reset_gpio_probe(void) | ||
107 | { | ||
108 | return; | ||
109 | } | ||
110 | #endif | ||
111 | |||
112 | void machine_restart(char *cmd) | ||
113 | { | ||
114 | printk(KERN_NOTICE "Machine restart...\n"); | ||
115 | gpio_system_reset(); | ||
116 | dump_stack(); | ||
117 | while (1) | ||
118 | ; | ||
119 | } | ||
120 | |||
121 | void machine_shutdown(void) | ||
122 | { | ||
123 | printk(KERN_NOTICE "Machine shutdown...\n"); | ||
124 | while (1) | ||
125 | ; | ||
126 | } | ||
127 | |||
128 | void machine_halt(void) | ||
129 | { | ||
130 | printk(KERN_NOTICE "Machine halt...\n"); | ||
131 | while (1) | ||
132 | ; | ||
133 | } | ||
134 | |||
135 | void machine_power_off(void) | ||
136 | { | ||
137 | printk(KERN_NOTICE "Machine power off...\n"); | ||
138 | while (1) | ||
139 | ; | ||
140 | } | ||
diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c index 8c1e0f4dcf18..5372b24ad049 100644 --- a/arch/microblaze/kernel/setup.c +++ b/arch/microblaze/kernel/setup.c | |||
@@ -52,13 +52,12 @@ void __init setup_arch(char **cmdline_p) | |||
52 | /* irq_early_init(); */ | 52 | /* irq_early_init(); */ |
53 | setup_cpuinfo(); | 53 | setup_cpuinfo(); |
54 | 54 | ||
55 | __invalidate_icache_all(); | 55 | microblaze_cache_init(); |
56 | __enable_icache(); | ||
57 | 56 | ||
58 | __invalidate_dcache_all(); | 57 | enable_dcache(); |
59 | __enable_dcache(); | ||
60 | 58 | ||
61 | panic_timeout = 120; | 59 | invalidate_icache(); |
60 | enable_icache(); | ||
62 | 61 | ||
63 | setup_memory(); | 62 | setup_memory(); |
64 | 63 | ||
@@ -131,6 +130,8 @@ void __init machine_early_init(const char *cmdline, unsigned int ram, | |||
131 | strlcpy(cmd_line, cmdline, COMMAND_LINE_SIZE); | 130 | strlcpy(cmd_line, cmdline, COMMAND_LINE_SIZE); |
132 | #endif | 131 | #endif |
133 | 132 | ||
133 | lockdep_init(); | ||
134 | |||
134 | /* initialize device tree for usage in early_printk */ | 135 | /* initialize device tree for usage in early_printk */ |
135 | early_init_devtree((void *)_fdt_start); | 136 | early_init_devtree((void *)_fdt_start); |
136 | 137 | ||
@@ -186,32 +187,3 @@ static int microblaze_debugfs_init(void) | |||
186 | } | 187 | } |
187 | arch_initcall(microblaze_debugfs_init); | 188 | arch_initcall(microblaze_debugfs_init); |
188 | #endif | 189 | #endif |
189 | |||
190 | void machine_restart(char *cmd) | ||
191 | { | ||
192 | printk(KERN_NOTICE "Machine restart...\n"); | ||
193 | dump_stack(); | ||
194 | while (1) | ||
195 | ; | ||
196 | } | ||
197 | |||
198 | void machine_shutdown(void) | ||
199 | { | ||
200 | printk(KERN_NOTICE "Machine shutdown...\n"); | ||
201 | while (1) | ||
202 | ; | ||
203 | } | ||
204 | |||
205 | void machine_halt(void) | ||
206 | { | ||
207 | printk(KERN_NOTICE "Machine halt...\n"); | ||
208 | while (1) | ||
209 | ; | ||
210 | } | ||
211 | |||
212 | void machine_power_off(void) | ||
213 | { | ||
214 | printk(KERN_NOTICE "Machine power off...\n"); | ||
215 | while (1) | ||
216 | ; | ||
217 | } | ||
diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c index 1c80e4fc40ce..d8d3bb396cd6 100644 --- a/arch/microblaze/kernel/signal.c +++ b/arch/microblaze/kernel/signal.c | |||
@@ -44,7 +44,6 @@ | |||
44 | 44 | ||
45 | asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_sycall); | 45 | asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_sycall); |
46 | 46 | ||
47 | |||
48 | asmlinkage long | 47 | asmlinkage long |
49 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | 48 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, |
50 | struct pt_regs *regs) | 49 | struct pt_regs *regs) |
@@ -176,6 +175,11 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
176 | struct rt_sigframe __user *frame; | 175 | struct rt_sigframe __user *frame; |
177 | int err = 0; | 176 | int err = 0; |
178 | int signal; | 177 | int signal; |
178 | unsigned long address = 0; | ||
179 | #ifdef CONFIG_MMU | ||
180 | pmd_t *pmdp; | ||
181 | pte_t *ptep; | ||
182 | #endif | ||
179 | 183 | ||
180 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 184 | frame = get_sigframe(ka, regs, sizeof(*frame)); |
181 | 185 | ||
@@ -216,8 +220,29 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
216 | Negative 8 offset because return is rtsd r15, 8 */ | 220 | Negative 8 offset because return is rtsd r15, 8 */ |
217 | regs->r15 = ((unsigned long)frame->tramp)-8; | 221 | regs->r15 = ((unsigned long)frame->tramp)-8; |
218 | 222 | ||
219 | __invalidate_cache_sigtramp((unsigned long)frame->tramp); | 223 | address = ((unsigned long)frame->tramp); |
220 | 224 | #ifdef CONFIG_MMU | |
225 | pmdp = pmd_offset(pud_offset( | ||
226 | pgd_offset(current->mm, address), | ||
227 | address), address); | ||
228 | |||
229 | preempt_disable(); | ||
230 | ptep = pte_offset_map(pmdp, address); | ||
231 | if (pte_present(*ptep)) { | ||
232 | address = (unsigned long) page_address(pte_page(*ptep)); | ||
233 | /* MS: I need add offset in page */ | ||
234 | address += ((unsigned long)frame->tramp) & ~PAGE_MASK; | ||
235 | /* MS address is virtual */ | ||
236 | address = virt_to_phys(address); | ||
237 | invalidate_icache_range(address, address + 8); | ||
238 | flush_dcache_range(address, address + 8); | ||
239 | } | ||
240 | pte_unmap(ptep); | ||
241 | preempt_enable(); | ||
242 | #else | ||
243 | flush_icache_range(address, address + 8); | ||
244 | flush_dcache_range(address, address + 8); | ||
245 | #endif | ||
221 | if (err) | 246 | if (err) |
222 | goto give_sigsegv; | 247 | goto give_sigsegv; |
223 | 248 | ||
@@ -233,6 +258,10 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
233 | 258 | ||
234 | set_fs(USER_DS); | 259 | set_fs(USER_DS); |
235 | 260 | ||
261 | /* the tracer may want to single-step inside the handler */ | ||
262 | if (test_thread_flag(TIF_SINGLESTEP)) | ||
263 | ptrace_notify(SIGTRAP); | ||
264 | |||
236 | #ifdef DEBUG_SIG | 265 | #ifdef DEBUG_SIG |
237 | printk(KERN_INFO "SIG deliver (%s:%d): sp=%p pc=%08lx\n", | 266 | printk(KERN_INFO "SIG deliver (%s:%d): sp=%p pc=%08lx\n", |
238 | current->comm, current->pid, frame, regs->pc); | 267 | current->comm, current->pid, frame, regs->pc); |
diff --git a/arch/microblaze/kernel/stacktrace.c b/arch/microblaze/kernel/stacktrace.c new file mode 100644 index 000000000000..123692f22647 --- /dev/null +++ b/arch/microblaze/kernel/stacktrace.c | |||
@@ -0,0 +1,65 @@ | |||
1 | /* | ||
2 | * Stack trace support for Microblaze. | ||
3 | * | ||
4 | * Copyright (C) 2009 Michal Simek <monstr@monstr.eu> | ||
5 | * Copyright (C) 2009 PetaLogix | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General Public | ||
8 | * License. See the file "COPYING" in the main directory of this archive | ||
9 | * for more details. | ||
10 | */ | ||
11 | |||
12 | #include <linux/sched.h> | ||
13 | #include <linux/stacktrace.h> | ||
14 | #include <linux/thread_info.h> | ||
15 | #include <linux/ptrace.h> | ||
16 | #include <linux/module.h> | ||
17 | |||
18 | /* FIXME initial support */ | ||
19 | void save_stack_trace(struct stack_trace *trace) | ||
20 | { | ||
21 | unsigned long *sp; | ||
22 | unsigned long addr; | ||
23 | asm("addik %0, r1, 0" : "=r" (sp)); | ||
24 | |||
25 | while (!kstack_end(sp)) { | ||
26 | addr = *sp++; | ||
27 | if (__kernel_text_address(addr)) { | ||
28 | if (trace->skip > 0) | ||
29 | trace->skip--; | ||
30 | else | ||
31 | trace->entries[trace->nr_entries++] = addr; | ||
32 | |||
33 | if (trace->nr_entries >= trace->max_entries) | ||
34 | break; | ||
35 | } | ||
36 | } | ||
37 | } | ||
38 | EXPORT_SYMBOL_GPL(save_stack_trace); | ||
39 | |||
40 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) | ||
41 | { | ||
42 | unsigned int *sp; | ||
43 | unsigned long addr; | ||
44 | |||
45 | struct thread_info *ti = task_thread_info(tsk); | ||
46 | |||
47 | if (tsk == current) | ||
48 | asm("addik %0, r1, 0" : "=r" (sp)); | ||
49 | else | ||
50 | sp = (unsigned int *)ti->cpu_context.r1; | ||
51 | |||
52 | while (!kstack_end(sp)) { | ||
53 | addr = *sp++; | ||
54 | if (__kernel_text_address(addr)) { | ||
55 | if (trace->skip > 0) | ||
56 | trace->skip--; | ||
57 | else | ||
58 | trace->entries[trace->nr_entries++] = addr; | ||
59 | |||
60 | if (trace->nr_entries >= trace->max_entries) | ||
61 | break; | ||
62 | } | ||
63 | } | ||
64 | } | ||
65 | EXPORT_SYMBOL_GPL(save_stack_trace_tsk); | ||
diff --git a/arch/microblaze/kernel/sys_microblaze.c b/arch/microblaze/kernel/sys_microblaze.c index 07cabed4b947..9f3c205fb75b 100644 --- a/arch/microblaze/kernel/sys_microblaze.c +++ b/arch/microblaze/kernel/sys_microblaze.c | |||
@@ -62,46 +62,14 @@ out: | |||
62 | return error; | 62 | return error; |
63 | } | 63 | } |
64 | 64 | ||
65 | asmlinkage long | ||
66 | sys_mmap2(unsigned long addr, unsigned long len, | ||
67 | unsigned long prot, unsigned long flags, | ||
68 | unsigned long fd, unsigned long pgoff) | ||
69 | { | ||
70 | struct file *file = NULL; | ||
71 | int ret = -EBADF; | ||
72 | |||
73 | flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); | ||
74 | if (!(flags & MAP_ANONYMOUS)) { | ||
75 | file = fget(fd); | ||
76 | if (!file) { | ||
77 | printk(KERN_INFO "no fd in mmap\r\n"); | ||
78 | goto out; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | down_write(¤t->mm->mmap_sem); | ||
83 | ret = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); | ||
84 | up_write(¤t->mm->mmap_sem); | ||
85 | if (file) | ||
86 | fput(file); | ||
87 | out: | ||
88 | return ret; | ||
89 | } | ||
90 | |||
91 | asmlinkage long sys_mmap(unsigned long addr, unsigned long len, | 65 | asmlinkage long sys_mmap(unsigned long addr, unsigned long len, |
92 | unsigned long prot, unsigned long flags, | 66 | unsigned long prot, unsigned long flags, |
93 | unsigned long fd, off_t pgoff) | 67 | unsigned long fd, off_t pgoff) |
94 | { | 68 | { |
95 | int err = -EINVAL; | 69 | if (pgoff & ~PAGE_MASK) |
96 | 70 | return -EINVAL; | |
97 | if (pgoff & ~PAGE_MASK) { | ||
98 | printk(KERN_INFO "no pagemask in mmap\r\n"); | ||
99 | goto out; | ||
100 | } | ||
101 | 71 | ||
102 | err = sys_mmap2(addr, len, prot, flags, fd, pgoff >> PAGE_SHIFT); | 72 | return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff >> PAGE_SHIFT); |
103 | out: | ||
104 | return err; | ||
105 | } | 73 | } |
106 | 74 | ||
107 | /* | 75 | /* |
diff --git a/arch/microblaze/kernel/syscall_table.S b/arch/microblaze/kernel/syscall_table.S index ecec19155135..4088be7d4e29 100644 --- a/arch/microblaze/kernel/syscall_table.S +++ b/arch/microblaze/kernel/syscall_table.S | |||
@@ -183,7 +183,7 @@ ENTRY(sys_call_table) | |||
183 | .long sys_rt_sigpending | 183 | .long sys_rt_sigpending |
184 | .long sys_rt_sigtimedwait | 184 | .long sys_rt_sigtimedwait |
185 | .long sys_rt_sigqueueinfo | 185 | .long sys_rt_sigqueueinfo |
186 | .long sys_rt_sigsuspend_wrapper | 186 | .long sys_rt_sigsuspend |
187 | .long sys_pread64 /* 180 */ | 187 | .long sys_pread64 /* 180 */ |
188 | .long sys_pwrite64 | 188 | .long sys_pwrite64 |
189 | .long sys_chown | 189 | .long sys_chown |
@@ -196,7 +196,7 @@ ENTRY(sys_call_table) | |||
196 | .long sys_ni_syscall /* reserved for streams2 */ | 196 | .long sys_ni_syscall /* reserved for streams2 */ |
197 | .long sys_vfork /* 190 */ | 197 | .long sys_vfork /* 190 */ |
198 | .long sys_getrlimit | 198 | .long sys_getrlimit |
199 | .long sys_mmap2 /* mmap2 */ | 199 | .long sys_mmap_pgoff /* mmap2 */ |
200 | .long sys_truncate64 | 200 | .long sys_truncate64 |
201 | .long sys_ftruncate64 | 201 | .long sys_ftruncate64 |
202 | .long sys_stat64 /* 195 */ | 202 | .long sys_stat64 /* 195 */ |
@@ -303,7 +303,7 @@ ENTRY(sys_call_table) | |||
303 | .long sys_mkdirat | 303 | .long sys_mkdirat |
304 | .long sys_mknodat | 304 | .long sys_mknodat |
305 | .long sys_fchownat | 305 | .long sys_fchownat |
306 | .long sys_ni_syscall | 306 | .long sys_futimesat |
307 | .long sys_fstatat64 /* 300 */ | 307 | .long sys_fstatat64 /* 300 */ |
308 | .long sys_unlinkat | 308 | .long sys_unlinkat |
309 | .long sys_renameat | 309 | .long sys_renameat |
@@ -371,3 +371,4 @@ ENTRY(sys_call_table) | |||
371 | .long sys_ni_syscall | 371 | .long sys_ni_syscall |
372 | .long sys_rt_tgsigqueueinfo /* 365 */ | 372 | .long sys_rt_tgsigqueueinfo /* 365 */ |
373 | .long sys_perf_event_open | 373 | .long sys_perf_event_open |
374 | .long sys_recvmmsg | ||
diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c index 5499deae7fa6..ed61b2f17719 100644 --- a/arch/microblaze/kernel/timer.c +++ b/arch/microblaze/kernel/timer.c | |||
@@ -183,6 +183,31 @@ static cycle_t microblaze_read(struct clocksource *cs) | |||
183 | return (cycle_t) (in_be32(TIMER_BASE + TCR1)); | 183 | return (cycle_t) (in_be32(TIMER_BASE + TCR1)); |
184 | } | 184 | } |
185 | 185 | ||
186 | static struct timecounter microblaze_tc = { | ||
187 | .cc = NULL, | ||
188 | }; | ||
189 | |||
190 | static cycle_t microblaze_cc_read(const struct cyclecounter *cc) | ||
191 | { | ||
192 | return microblaze_read(NULL); | ||
193 | } | ||
194 | |||
195 | static struct cyclecounter microblaze_cc = { | ||
196 | .read = microblaze_cc_read, | ||
197 | .mask = CLOCKSOURCE_MASK(32), | ||
198 | .shift = 24, | ||
199 | }; | ||
200 | |||
201 | int __init init_microblaze_timecounter(void) | ||
202 | { | ||
203 | microblaze_cc.mult = div_sc(cpuinfo.cpu_clock_freq, NSEC_PER_SEC, | ||
204 | microblaze_cc.shift); | ||
205 | |||
206 | timecounter_init(µblaze_tc, µblaze_cc, sched_clock()); | ||
207 | |||
208 | return 0; | ||
209 | } | ||
210 | |||
186 | static struct clocksource clocksource_microblaze = { | 211 | static struct clocksource clocksource_microblaze = { |
187 | .name = "microblaze_clocksource", | 212 | .name = "microblaze_clocksource", |
188 | .rating = 300, | 213 | .rating = 300, |
@@ -204,6 +229,9 @@ static int __init microblaze_clocksource_init(void) | |||
204 | out_be32(TIMER_BASE + TCSR1, in_be32(TIMER_BASE + TCSR1) & ~TCSR_ENT); | 229 | out_be32(TIMER_BASE + TCSR1, in_be32(TIMER_BASE + TCSR1) & ~TCSR_ENT); |
205 | /* start timer1 - up counting without interrupt */ | 230 | /* start timer1 - up counting without interrupt */ |
206 | out_be32(TIMER_BASE + TCSR1, TCSR_TINT|TCSR_ENT|TCSR_ARHT); | 231 | out_be32(TIMER_BASE + TCSR1, TCSR_TINT|TCSR_ENT|TCSR_ARHT); |
232 | |||
233 | /* register timecounter - for ftrace support */ | ||
234 | init_microblaze_timecounter(); | ||
207 | return 0; | 235 | return 0; |
208 | } | 236 | } |
209 | 237 | ||
diff --git a/arch/microblaze/kernel/vmlinux.lds.S b/arch/microblaze/kernel/vmlinux.lds.S index e704188d7855..5ef619aad634 100644 --- a/arch/microblaze/kernel/vmlinux.lds.S +++ b/arch/microblaze/kernel/vmlinux.lds.S | |||
@@ -26,11 +26,12 @@ SECTIONS { | |||
26 | _stext = . ; | 26 | _stext = . ; |
27 | *(.text .text.*) | 27 | *(.text .text.*) |
28 | *(.fixup) | 28 | *(.fixup) |
29 | EXIT_TEXT | 29 | EXIT_TEXT |
30 | EXIT_CALL | 30 | EXIT_CALL |
31 | SCHED_TEXT | 31 | SCHED_TEXT |
32 | LOCK_TEXT | 32 | LOCK_TEXT |
33 | KPROBES_TEXT | 33 | KPROBES_TEXT |
34 | IRQENTRY_TEXT | ||
34 | . = ALIGN (4) ; | 35 | . = ALIGN (4) ; |
35 | _etext = . ; | 36 | _etext = . ; |
36 | } | 37 | } |
@@ -86,6 +87,7 @@ SECTIONS { | |||
86 | _KERNEL_SDA_BASE_ = _ssro + (_ssro_size / 2) ; | 87 | _KERNEL_SDA_BASE_ = _ssro + (_ssro_size / 2) ; |
87 | } | 88 | } |
88 | 89 | ||
90 | . = ALIGN(PAGE_SIZE); | ||
89 | __init_begin = .; | 91 | __init_begin = .; |
90 | 92 | ||
91 | INIT_TEXT_SECTION(PAGE_SIZE) | 93 | INIT_TEXT_SECTION(PAGE_SIZE) |