aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/include/asm/system.h
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/include/asm/system.h')
-rw-r--r--arch/arm/include/asm/system.h474
1 files changed, 8 insertions, 466 deletions
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 774c41e8addf..74542c52f9be 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -1,466 +1,8 @@
1#ifndef __ASM_ARM_SYSTEM_H 1/* FILE TO BE DELETED. DO NOT ADD STUFF HERE! */
2#define __ASM_ARM_SYSTEM_H 2#include <asm/barrier.h>
3 3#include <asm/compiler.h>
4#ifdef __KERNEL__ 4#include <asm/cmpxchg.h>
5 5#include <asm/exec.h>
6#define CPU_ARCH_UNKNOWN 0 6#include <asm/switch_to.h>
7#define CPU_ARCH_ARMv3 1 7#include <asm/system_info.h>
8#define CPU_ARCH_ARMv4 2 8#include <asm/system_misc.h>
9#define CPU_ARCH_ARMv4T 3
10#define CPU_ARCH_ARMv5 4
11#define CPU_ARCH_ARMv5T 5
12#define CPU_ARCH_ARMv5TE 6
13#define CPU_ARCH_ARMv5TEJ 7
14#define CPU_ARCH_ARMv6 8
15#define CPU_ARCH_ARMv7 9
16
17/*
18 * This is used to ensure the compiler did actually allocate the register we
19 * asked it for some inline assembly sequences. Apparently we can't trust
20 * the compiler from one version to another so a bit of paranoia won't hurt.
21 * This string is meant to be concatenated with the inline asm string and
22 * will cause compilation to stop on mismatch.
23 * (for details, see gcc PR 15089)
24 */
25#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t"
26
27#ifndef __ASSEMBLY__
28
29#include <linux/compiler.h>
30#include <linux/linkage.h>
31#include <linux/irqflags.h>
32
33#include <asm/outercache.h>
34
35struct thread_info;
36struct task_struct;
37
38/* information about the system we're running on */
39extern unsigned int system_rev;
40extern unsigned int system_serial_low;
41extern unsigned int system_serial_high;
42extern unsigned int mem_fclk_21285;
43
44struct pt_regs;
45
46void die(const char *msg, struct pt_regs *regs, int err);
47
48struct siginfo;
49void arm_notify_die(const char *str, struct pt_regs *regs, struct siginfo *info,
50 unsigned long err, unsigned long trap);
51
52#ifdef CONFIG_ARM_LPAE
53#define FAULT_CODE_ALIGNMENT 33
54#define FAULT_CODE_DEBUG 34
55#else
56#define FAULT_CODE_ALIGNMENT 1
57#define FAULT_CODE_DEBUG 2
58#endif
59
60void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
61 struct pt_regs *),
62 int sig, int code, const char *name);
63
64void hook_ifault_code(int nr, int (*fn)(unsigned long, unsigned int,
65 struct pt_regs *),
66 int sig, int code, const char *name);
67
68#define xchg(ptr,x) \
69 ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
70
71extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
72
73struct mm_struct;
74extern void show_pte(struct mm_struct *mm, unsigned long addr);
75extern void __show_regs(struct pt_regs *);
76
77extern int __pure cpu_architecture(void);
78extern void cpu_init(void);
79
80void soft_restart(unsigned long);
81extern void (*arm_pm_restart)(char str, const char *cmd);
82
83#define UDBG_UNDEFINED (1 << 0)
84#define UDBG_SYSCALL (1 << 1)
85#define UDBG_BADABORT (1 << 2)
86#define UDBG_SEGV (1 << 3)
87#define UDBG_BUS (1 << 4)
88
89extern unsigned int user_debug;
90
91#if __LINUX_ARM_ARCH__ >= 7 || \
92 (__LINUX_ARM_ARCH__ == 6 && defined(CONFIG_CPU_32v6K))
93#define sev() __asm__ __volatile__ ("sev" : : : "memory")
94#define wfe() __asm__ __volatile__ ("wfe" : : : "memory")
95#define wfi() __asm__ __volatile__ ("wfi" : : : "memory")
96#endif
97
98#if __LINUX_ARM_ARCH__ >= 7
99#define isb() __asm__ __volatile__ ("isb" : : : "memory")
100#define dsb() __asm__ __volatile__ ("dsb" : : : "memory")
101#define dmb() __asm__ __volatile__ ("dmb" : : : "memory")
102#elif defined(CONFIG_CPU_XSC3) || __LINUX_ARM_ARCH__ == 6
103#define isb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \
104 : : "r" (0) : "memory")
105#define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
106 : : "r" (0) : "memory")
107#define dmb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \
108 : : "r" (0) : "memory")
109#elif defined(CONFIG_CPU_FA526)
110#define isb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \
111 : : "r" (0) : "memory")
112#define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
113 : : "r" (0) : "memory")
114#define dmb() __asm__ __volatile__ ("" : : : "memory")
115#else
116#define isb() __asm__ __volatile__ ("" : : : "memory")
117#define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
118 : : "r" (0) : "memory")
119#define dmb() __asm__ __volatile__ ("" : : : "memory")
120#endif
121
122#ifdef CONFIG_ARCH_HAS_BARRIERS
123#include <mach/barriers.h>
124#elif defined(CONFIG_ARM_DMA_MEM_BUFFERABLE) || defined(CONFIG_SMP)
125#define mb() do { dsb(); outer_sync(); } while (0)
126#define rmb() dsb()
127#define wmb() mb()
128#else
129#include <asm/memory.h>
130#define mb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
131#define rmb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
132#define wmb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
133#endif
134
135#ifndef CONFIG_SMP
136#define smp_mb() barrier()
137#define smp_rmb() barrier()
138#define smp_wmb() barrier()
139#else
140#define smp_mb() dmb()
141#define smp_rmb() dmb()
142#define smp_wmb() dmb()
143#endif
144
145#define read_barrier_depends() do { } while(0)
146#define smp_read_barrier_depends() do { } while(0)
147
148#define set_mb(var, value) do { var = value; smp_mb(); } while (0)
149#define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t");
150
151/*
152 * switch_mm() may do a full cache flush over the context switch,
153 * so enable interrupts over the context switch to avoid high
154 * latency.
155 */
156#define __ARCH_WANT_INTERRUPTS_ON_CTXSW
157
158/*
159 * switch_to(prev, next) should switch from task `prev' to `next'
160 * `prev' will never be the same as `next'. schedule() itself
161 * contains the memory barrier to tell GCC not to cache `current'.
162 */
163extern struct task_struct *__switch_to(struct task_struct *, struct thread_info *, struct thread_info *);
164
165#define switch_to(prev,next,last) \
166do { \
167 last = __switch_to(prev,task_thread_info(prev), task_thread_info(next)); \
168} while (0)
169
170#if defined(CONFIG_CPU_SA1100) || defined(CONFIG_CPU_SA110)
171/*
172 * On the StrongARM, "swp" is terminally broken since it bypasses the
173 * cache totally. This means that the cache becomes inconsistent, and,
174 * since we use normal loads/stores as well, this is really bad.
175 * Typically, this causes oopsen in filp_close, but could have other,
176 * more disastrous effects. There are two work-arounds:
177 * 1. Disable interrupts and emulate the atomic swap
178 * 2. Clean the cache, perform atomic swap, flush the cache
179 *
180 * We choose (1) since its the "easiest" to achieve here and is not
181 * dependent on the processor type.
182 *
183 * NOTE that this solution won't work on an SMP system, so explcitly
184 * forbid it here.
185 */
186#define swp_is_buggy
187#endif
188
189static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
190{
191 extern void __bad_xchg(volatile void *, int);
192 unsigned long ret;
193#ifdef swp_is_buggy
194 unsigned long flags;
195#endif
196#if __LINUX_ARM_ARCH__ >= 6
197 unsigned int tmp;
198#endif
199
200 smp_mb();
201
202 switch (size) {
203#if __LINUX_ARM_ARCH__ >= 6
204 case 1:
205 asm volatile("@ __xchg1\n"
206 "1: ldrexb %0, [%3]\n"
207 " strexb %1, %2, [%3]\n"
208 " teq %1, #0\n"
209 " bne 1b"
210 : "=&r" (ret), "=&r" (tmp)
211 : "r" (x), "r" (ptr)
212 : "memory", "cc");
213 break;
214 case 4:
215 asm volatile("@ __xchg4\n"
216 "1: ldrex %0, [%3]\n"
217 " strex %1, %2, [%3]\n"
218 " teq %1, #0\n"
219 " bne 1b"
220 : "=&r" (ret), "=&r" (tmp)
221 : "r" (x), "r" (ptr)
222 : "memory", "cc");
223 break;
224#elif defined(swp_is_buggy)
225#ifdef CONFIG_SMP
226#error SMP is not supported on this platform
227#endif
228 case 1:
229 raw_local_irq_save(flags);
230 ret = *(volatile unsigned char *)ptr;
231 *(volatile unsigned char *)ptr = x;
232 raw_local_irq_restore(flags);
233 break;
234
235 case 4:
236 raw_local_irq_save(flags);
237 ret = *(volatile unsigned long *)ptr;
238 *(volatile unsigned long *)ptr = x;
239 raw_local_irq_restore(flags);
240 break;
241#else
242 case 1:
243 asm volatile("@ __xchg1\n"
244 " swpb %0, %1, [%2]"
245 : "=&r" (ret)
246 : "r" (x), "r" (ptr)
247 : "memory", "cc");
248 break;
249 case 4:
250 asm volatile("@ __xchg4\n"
251 " swp %0, %1, [%2]"
252 : "=&r" (ret)
253 : "r" (x), "r" (ptr)
254 : "memory", "cc");
255 break;
256#endif
257 default:
258 __bad_xchg(ptr, size), ret = 0;
259 break;
260 }
261 smp_mb();
262
263 return ret;
264}
265
266extern void disable_hlt(void);
267extern void enable_hlt(void);
268
269void cpu_idle_wait(void);
270
271#include <asm-generic/cmpxchg-local.h>
272
273#if __LINUX_ARM_ARCH__ < 6
274/* min ARCH < ARMv6 */
275
276#ifdef CONFIG_SMP
277#error "SMP is not supported on this platform"
278#endif
279
280/*
281 * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
282 * them available.
283 */
284#define cmpxchg_local(ptr, o, n) \
285 ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
286 (unsigned long)(n), sizeof(*(ptr))))
287#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
288
289#ifndef CONFIG_SMP
290#include <asm-generic/cmpxchg.h>
291#endif
292
293#else /* min ARCH >= ARMv6 */
294
295extern void __bad_cmpxchg(volatile void *ptr, int size);
296
297/*
298 * cmpxchg only support 32-bits operands on ARMv6.
299 */
300
301static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
302 unsigned long new, int size)
303{
304 unsigned long oldval, res;
305
306 switch (size) {
307#ifndef CONFIG_CPU_V6 /* min ARCH >= ARMv6K */
308 case 1:
309 do {
310 asm volatile("@ __cmpxchg1\n"
311 " ldrexb %1, [%2]\n"
312 " mov %0, #0\n"
313 " teq %1, %3\n"
314 " strexbeq %0, %4, [%2]\n"
315 : "=&r" (res), "=&r" (oldval)
316 : "r" (ptr), "Ir" (old), "r" (new)
317 : "memory", "cc");
318 } while (res);
319 break;
320 case 2:
321 do {
322 asm volatile("@ __cmpxchg1\n"
323 " ldrexh %1, [%2]\n"
324 " mov %0, #0\n"
325 " teq %1, %3\n"
326 " strexheq %0, %4, [%2]\n"
327 : "=&r" (res), "=&r" (oldval)
328 : "r" (ptr), "Ir" (old), "r" (new)
329 : "memory", "cc");
330 } while (res);
331 break;
332#endif
333 case 4:
334 do {
335 asm volatile("@ __cmpxchg4\n"
336 " ldrex %1, [%2]\n"
337 " mov %0, #0\n"
338 " teq %1, %3\n"
339 " strexeq %0, %4, [%2]\n"
340 : "=&r" (res), "=&r" (oldval)
341 : "r" (ptr), "Ir" (old), "r" (new)
342 : "memory", "cc");
343 } while (res);
344 break;
345 default:
346 __bad_cmpxchg(ptr, size);
347 oldval = 0;
348 }
349
350 return oldval;
351}
352
353static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
354 unsigned long new, int size)
355{
356 unsigned long ret;
357
358 smp_mb();
359 ret = __cmpxchg(ptr, old, new, size);
360 smp_mb();
361
362 return ret;
363}
364
365#define cmpxchg(ptr,o,n) \
366 ((__typeof__(*(ptr)))__cmpxchg_mb((ptr), \
367 (unsigned long)(o), \
368 (unsigned long)(n), \
369 sizeof(*(ptr))))
370
371static inline unsigned long __cmpxchg_local(volatile void *ptr,
372 unsigned long old,
373 unsigned long new, int size)
374{
375 unsigned long ret;
376
377 switch (size) {
378#ifdef CONFIG_CPU_V6 /* min ARCH == ARMv6 */
379 case 1:
380 case 2:
381 ret = __cmpxchg_local_generic(ptr, old, new, size);
382 break;
383#endif
384 default:
385 ret = __cmpxchg(ptr, old, new, size);
386 }
387
388 return ret;
389}
390
391#define cmpxchg_local(ptr,o,n) \
392 ((__typeof__(*(ptr)))__cmpxchg_local((ptr), \
393 (unsigned long)(o), \
394 (unsigned long)(n), \
395 sizeof(*(ptr))))
396
397#ifndef CONFIG_CPU_V6 /* min ARCH >= ARMv6K */
398
399/*
400 * Note : ARMv7-M (currently unsupported by Linux) does not support
401 * ldrexd/strexd. If ARMv7-M is ever supported by the Linux kernel, it should
402 * not be allowed to use __cmpxchg64.
403 */
404static inline unsigned long long __cmpxchg64(volatile void *ptr,
405 unsigned long long old,
406 unsigned long long new)
407{
408 register unsigned long long oldval asm("r0");
409 register unsigned long long __old asm("r2") = old;
410 register unsigned long long __new asm("r4") = new;
411 unsigned long res;
412
413 do {
414 asm volatile(
415 " @ __cmpxchg8\n"
416 " ldrexd %1, %H1, [%2]\n"
417 " mov %0, #0\n"
418 " teq %1, %3\n"
419 " teqeq %H1, %H3\n"
420 " strexdeq %0, %4, %H4, [%2]\n"
421 : "=&r" (res), "=&r" (oldval)
422 : "r" (ptr), "Ir" (__old), "r" (__new)
423 : "memory", "cc");
424 } while (res);
425
426 return oldval;
427}
428
429static inline unsigned long long __cmpxchg64_mb(volatile void *ptr,
430 unsigned long long old,
431 unsigned long long new)
432{
433 unsigned long long ret;
434
435 smp_mb();
436 ret = __cmpxchg64(ptr, old, new);
437 smp_mb();
438
439 return ret;
440}
441
442#define cmpxchg64(ptr,o,n) \
443 ((__typeof__(*(ptr)))__cmpxchg64_mb((ptr), \
444 (unsigned long long)(o), \
445 (unsigned long long)(n)))
446
447#define cmpxchg64_local(ptr,o,n) \
448 ((__typeof__(*(ptr)))__cmpxchg64((ptr), \
449 (unsigned long long)(o), \
450 (unsigned long long)(n)))
451
452#else /* min ARCH = ARMv6 */
453
454#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
455
456#endif
457
458#endif /* __LINUX_ARM_ARCH__ >= 6 */
459
460#endif /* __ASSEMBLY__ */
461
462#define arch_align_stack(x) (x)
463
464#endif /* __KERNEL__ */
465
466#endif