diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-24 21:37:03 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-24 21:37:03 -0500 |
commit | 9e314890292c0dd357eadef6a043704fa0b4c157 (patch) | |
tree | d70b074818b4dc45b180ea860ba66ce573129688 | |
parent | f8e6859ea9d06ae1565b21278c4e10fbce5f1eab (diff) | |
parent | a4d4426635804379d618dd28e29f574a2bc11184 (diff) |
Merge tag 'openrisc-for-linus' of git://github.com/openrisc/linux
Pull OpenRISC updates from Stafford Horne:
"Highlights include:
- optimized memset and memcpy routines, ~20% boot time saving
- support for cpu idling
- adding support for l.swa and l.lwa atomic operations (in spec from
2014)
- use atomics to implement: bitops, cmpxchg, futex
- the atomics are in preparation for SMP support"
* tag 'openrisc-for-linus' of git://github.com/openrisc/linux: (25 commits)
openrisc: head: Init r0 to 0 on start
openrisc: Export ioremap symbols used by modules
arch/openrisc/lib/memcpy.c: use correct OR1200 option
openrisc: head: Remove unused strings
openrisc: head: Move init strings to rodata section
openrisc: entry: Fix delay slot detection
openrisc: entry: Whitespace and comment cleanups
scripts/checkstack.pl: Add openrisc support
MAINTAINERS: Add the openrisc official repository
openrisc: Add .gitignore
openrisc: Add optimized memcpy routine
openrisc: Add optimized memset
openrisc: Initial support for the idle state
openrisc: Fix the bitmask for the unit present register
openrisc: remove unnecessary stddef.h include
openrisc: add futex_atomic_* implementations
openrisc: add optimized atomic operations
openrisc: add cmpxchg and xchg implementations
openrisc: add atomic bitops
openrisc: add l.lwa/l.swa emulation
...
26 files changed, 1064 insertions, 187 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 4b03c4701030..8f05facab3b5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -9315,6 +9315,7 @@ OPENRISC ARCHITECTURE | |||
9315 | M: Jonas Bonn <jonas@southpole.se> | 9315 | M: Jonas Bonn <jonas@southpole.se> |
9316 | M: Stefan Kristiansson <stefan.kristiansson@saunalahti.fi> | 9316 | M: Stefan Kristiansson <stefan.kristiansson@saunalahti.fi> |
9317 | M: Stafford Horne <shorne@gmail.com> | 9317 | M: Stafford Horne <shorne@gmail.com> |
9318 | T: git git://github.com/openrisc/linux.git | ||
9318 | L: openrisc@lists.librecores.org | 9319 | L: openrisc@lists.librecores.org |
9319 | W: http://openrisc.io | 9320 | W: http://openrisc.io |
9320 | S: Maintained | 9321 | S: Maintained |
diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig index 8d22015fde3e..1e95920b0737 100644 --- a/arch/openrisc/Kconfig +++ b/arch/openrisc/Kconfig | |||
@@ -12,6 +12,7 @@ config OPENRISC | |||
12 | select HAVE_MEMBLOCK | 12 | select HAVE_MEMBLOCK |
13 | select GPIOLIB | 13 | select GPIOLIB |
14 | select HAVE_ARCH_TRACEHOOK | 14 | select HAVE_ARCH_TRACEHOOK |
15 | select SPARSE_IRQ | ||
15 | select GENERIC_IRQ_CHIP | 16 | select GENERIC_IRQ_CHIP |
16 | select GENERIC_IRQ_PROBE | 17 | select GENERIC_IRQ_PROBE |
17 | select GENERIC_IRQ_SHOW | 18 | select GENERIC_IRQ_SHOW |
diff --git a/arch/openrisc/TODO.openrisc b/arch/openrisc/TODO.openrisc index 0eb04c8240f9..c43d4e1d14eb 100644 --- a/arch/openrisc/TODO.openrisc +++ b/arch/openrisc/TODO.openrisc | |||
@@ -10,4 +10,3 @@ that are due for investigation shortly, i.e. our TODO list: | |||
10 | or1k and this change is slowly trickling through the stack. For the time | 10 | or1k and this change is slowly trickling through the stack. For the time |
11 | being, or32 is equivalent to or1k. | 11 | being, or32 is equivalent to or1k. |
12 | 12 | ||
13 | -- Implement optimized version of memcpy and memset | ||
diff --git a/arch/openrisc/include/asm/Kbuild b/arch/openrisc/include/asm/Kbuild index ef8d1ccc3e45..fb241757f7f0 100644 --- a/arch/openrisc/include/asm/Kbuild +++ b/arch/openrisc/include/asm/Kbuild | |||
@@ -1,7 +1,6 @@ | |||
1 | 1 | ||
2 | header-y += ucontext.h | 2 | header-y += ucontext.h |
3 | 3 | ||
4 | generic-y += atomic.h | ||
5 | generic-y += auxvec.h | 4 | generic-y += auxvec.h |
6 | generic-y += barrier.h | 5 | generic-y += barrier.h |
7 | generic-y += bitsperlong.h | 6 | generic-y += bitsperlong.h |
@@ -10,8 +9,6 @@ generic-y += bugs.h | |||
10 | generic-y += cacheflush.h | 9 | generic-y += cacheflush.h |
11 | generic-y += checksum.h | 10 | generic-y += checksum.h |
12 | generic-y += clkdev.h | 11 | generic-y += clkdev.h |
13 | generic-y += cmpxchg-local.h | ||
14 | generic-y += cmpxchg.h | ||
15 | generic-y += current.h | 12 | generic-y += current.h |
16 | generic-y += device.h | 13 | generic-y += device.h |
17 | generic-y += div64.h | 14 | generic-y += div64.h |
@@ -22,12 +19,12 @@ generic-y += exec.h | |||
22 | generic-y += fb.h | 19 | generic-y += fb.h |
23 | generic-y += fcntl.h | 20 | generic-y += fcntl.h |
24 | generic-y += ftrace.h | 21 | generic-y += ftrace.h |
25 | generic-y += futex.h | ||
26 | generic-y += hardirq.h | 22 | generic-y += hardirq.h |
27 | generic-y += hw_irq.h | 23 | generic-y += hw_irq.h |
28 | generic-y += ioctl.h | 24 | generic-y += ioctl.h |
29 | generic-y += ioctls.h | 25 | generic-y += ioctls.h |
30 | generic-y += ipcbuf.h | 26 | generic-y += ipcbuf.h |
27 | generic-y += irq.h | ||
31 | generic-y += irq_regs.h | 28 | generic-y += irq_regs.h |
32 | generic-y += irq_work.h | 29 | generic-y += irq_work.h |
33 | generic-y += kdebug.h | 30 | generic-y += kdebug.h |
diff --git a/arch/openrisc/include/asm/atomic.h b/arch/openrisc/include/asm/atomic.h new file mode 100644 index 000000000000..146e1660f00e --- /dev/null +++ b/arch/openrisc/include/asm/atomic.h | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi> | ||
3 | * | ||
4 | * This file is licensed under the terms of the GNU General Public License | ||
5 | * version 2. This program is licensed "as is" without any warranty of any | ||
6 | * kind, whether express or implied. | ||
7 | */ | ||
8 | |||
9 | #ifndef __ASM_OPENRISC_ATOMIC_H | ||
10 | #define __ASM_OPENRISC_ATOMIC_H | ||
11 | |||
12 | #include <linux/types.h> | ||
13 | |||
14 | /* Atomically perform op with v->counter and i */ | ||
15 | #define ATOMIC_OP(op) \ | ||
16 | static inline void atomic_##op(int i, atomic_t *v) \ | ||
17 | { \ | ||
18 | int tmp; \ | ||
19 | \ | ||
20 | __asm__ __volatile__( \ | ||
21 | "1: l.lwa %0,0(%1) \n" \ | ||
22 | " l." #op " %0,%0,%2 \n" \ | ||
23 | " l.swa 0(%1),%0 \n" \ | ||
24 | " l.bnf 1b \n" \ | ||
25 | " l.nop \n" \ | ||
26 | : "=&r"(tmp) \ | ||
27 | : "r"(&v->counter), "r"(i) \ | ||
28 | : "cc", "memory"); \ | ||
29 | } | ||
30 | |||
31 | /* Atomically perform op with v->counter and i, return the result */ | ||
32 | #define ATOMIC_OP_RETURN(op) \ | ||
33 | static inline int atomic_##op##_return(int i, atomic_t *v) \ | ||
34 | { \ | ||
35 | int tmp; \ | ||
36 | \ | ||
37 | __asm__ __volatile__( \ | ||
38 | "1: l.lwa %0,0(%1) \n" \ | ||
39 | " l." #op " %0,%0,%2 \n" \ | ||
40 | " l.swa 0(%1),%0 \n" \ | ||
41 | " l.bnf 1b \n" \ | ||
42 | " l.nop \n" \ | ||
43 | : "=&r"(tmp) \ | ||
44 | : "r"(&v->counter), "r"(i) \ | ||
45 | : "cc", "memory"); \ | ||
46 | \ | ||
47 | return tmp; \ | ||
48 | } | ||
49 | |||
50 | /* Atomically perform op with v->counter and i, return orig v->counter */ | ||
51 | #define ATOMIC_FETCH_OP(op) \ | ||
52 | static inline int atomic_fetch_##op(int i, atomic_t *v) \ | ||
53 | { \ | ||
54 | int tmp, old; \ | ||
55 | \ | ||
56 | __asm__ __volatile__( \ | ||
57 | "1: l.lwa %0,0(%2) \n" \ | ||
58 | " l." #op " %1,%0,%3 \n" \ | ||
59 | " l.swa 0(%2),%1 \n" \ | ||
60 | " l.bnf 1b \n" \ | ||
61 | " l.nop \n" \ | ||
62 | : "=&r"(old), "=&r"(tmp) \ | ||
63 | : "r"(&v->counter), "r"(i) \ | ||
64 | : "cc", "memory"); \ | ||
65 | \ | ||
66 | return old; \ | ||
67 | } | ||
68 | |||
69 | ATOMIC_OP_RETURN(add) | ||
70 | ATOMIC_OP_RETURN(sub) | ||
71 | |||
72 | ATOMIC_FETCH_OP(add) | ||
73 | ATOMIC_FETCH_OP(sub) | ||
74 | ATOMIC_FETCH_OP(and) | ||
75 | ATOMIC_FETCH_OP(or) | ||
76 | ATOMIC_FETCH_OP(xor) | ||
77 | |||
78 | ATOMIC_OP(and) | ||
79 | ATOMIC_OP(or) | ||
80 | ATOMIC_OP(xor) | ||
81 | |||
82 | #undef ATOMIC_FETCH_OP | ||
83 | #undef ATOMIC_OP_RETURN | ||
84 | #undef ATOMIC_OP | ||
85 | |||
86 | #define atomic_add_return atomic_add_return | ||
87 | #define atomic_sub_return atomic_sub_return | ||
88 | #define atomic_fetch_add atomic_fetch_add | ||
89 | #define atomic_fetch_sub atomic_fetch_sub | ||
90 | #define atomic_fetch_and atomic_fetch_and | ||
91 | #define atomic_fetch_or atomic_fetch_or | ||
92 | #define atomic_fetch_xor atomic_fetch_xor | ||
93 | #define atomic_and atomic_and | ||
94 | #define atomic_or atomic_or | ||
95 | #define atomic_xor atomic_xor | ||
96 | |||
97 | /* | ||
98 | * Atomically add a to v->counter as long as v is not already u. | ||
99 | * Returns the original value at v->counter. | ||
100 | * | ||
101 | * This is often used through atomic_inc_not_zero() | ||
102 | */ | ||
103 | static inline int __atomic_add_unless(atomic_t *v, int a, int u) | ||
104 | { | ||
105 | int old, tmp; | ||
106 | |||
107 | __asm__ __volatile__( | ||
108 | "1: l.lwa %0, 0(%2) \n" | ||
109 | " l.sfeq %0, %4 \n" | ||
110 | " l.bf 2f \n" | ||
111 | " l.add %1, %0, %3 \n" | ||
112 | " l.swa 0(%2), %1 \n" | ||
113 | " l.bnf 1b \n" | ||
114 | " l.nop \n" | ||
115 | "2: \n" | ||
116 | : "=&r"(old), "=&r" (tmp) | ||
117 | : "r"(&v->counter), "r"(a), "r"(u) | ||
118 | : "cc", "memory"); | ||
119 | |||
120 | return old; | ||
121 | } | ||
122 | #define __atomic_add_unless __atomic_add_unless | ||
123 | |||
124 | #include <asm-generic/atomic.h> | ||
125 | |||
126 | #endif /* __ASM_OPENRISC_ATOMIC_H */ | ||
diff --git a/arch/openrisc/include/asm/bitops.h b/arch/openrisc/include/asm/bitops.h index 3003cdad561b..689f56819d53 100644 --- a/arch/openrisc/include/asm/bitops.h +++ b/arch/openrisc/include/asm/bitops.h | |||
@@ -45,7 +45,7 @@ | |||
45 | #include <asm-generic/bitops/hweight.h> | 45 | #include <asm-generic/bitops/hweight.h> |
46 | #include <asm-generic/bitops/lock.h> | 46 | #include <asm-generic/bitops/lock.h> |
47 | 47 | ||
48 | #include <asm-generic/bitops/atomic.h> | 48 | #include <asm/bitops/atomic.h> |
49 | #include <asm-generic/bitops/non-atomic.h> | 49 | #include <asm-generic/bitops/non-atomic.h> |
50 | #include <asm-generic/bitops/le.h> | 50 | #include <asm-generic/bitops/le.h> |
51 | #include <asm-generic/bitops/ext2-atomic.h> | 51 | #include <asm-generic/bitops/ext2-atomic.h> |
diff --git a/arch/openrisc/include/asm/bitops/atomic.h b/arch/openrisc/include/asm/bitops/atomic.h new file mode 100644 index 000000000000..35fb85f61b4a --- /dev/null +++ b/arch/openrisc/include/asm/bitops/atomic.h | |||
@@ -0,0 +1,123 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi> | ||
3 | * | ||
4 | * This file is licensed under the terms of the GNU General Public License | ||
5 | * version 2. This program is licensed "as is" without any warranty of any | ||
6 | * kind, whether express or implied. | ||
7 | */ | ||
8 | |||
9 | #ifndef __ASM_OPENRISC_BITOPS_ATOMIC_H | ||
10 | #define __ASM_OPENRISC_BITOPS_ATOMIC_H | ||
11 | |||
12 | static inline void set_bit(int nr, volatile unsigned long *addr) | ||
13 | { | ||
14 | unsigned long mask = BIT_MASK(nr); | ||
15 | unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); | ||
16 | unsigned long tmp; | ||
17 | |||
18 | __asm__ __volatile__( | ||
19 | "1: l.lwa %0,0(%1) \n" | ||
20 | " l.or %0,%0,%2 \n" | ||
21 | " l.swa 0(%1),%0 \n" | ||
22 | " l.bnf 1b \n" | ||
23 | " l.nop \n" | ||
24 | : "=&r"(tmp) | ||
25 | : "r"(p), "r"(mask) | ||
26 | : "cc", "memory"); | ||
27 | } | ||
28 | |||
29 | static inline void clear_bit(int nr, volatile unsigned long *addr) | ||
30 | { | ||
31 | unsigned long mask = BIT_MASK(nr); | ||
32 | unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); | ||
33 | unsigned long tmp; | ||
34 | |||
35 | __asm__ __volatile__( | ||
36 | "1: l.lwa %0,0(%1) \n" | ||
37 | " l.and %0,%0,%2 \n" | ||
38 | " l.swa 0(%1),%0 \n" | ||
39 | " l.bnf 1b \n" | ||
40 | " l.nop \n" | ||
41 | : "=&r"(tmp) | ||
42 | : "r"(p), "r"(~mask) | ||
43 | : "cc", "memory"); | ||
44 | } | ||
45 | |||
46 | static inline void change_bit(int nr, volatile unsigned long *addr) | ||
47 | { | ||
48 | unsigned long mask = BIT_MASK(nr); | ||
49 | unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); | ||
50 | unsigned long tmp; | ||
51 | |||
52 | __asm__ __volatile__( | ||
53 | "1: l.lwa %0,0(%1) \n" | ||
54 | " l.xor %0,%0,%2 \n" | ||
55 | " l.swa 0(%1),%0 \n" | ||
56 | " l.bnf 1b \n" | ||
57 | " l.nop \n" | ||
58 | : "=&r"(tmp) | ||
59 | : "r"(p), "r"(mask) | ||
60 | : "cc", "memory"); | ||
61 | } | ||
62 | |||
63 | static inline int test_and_set_bit(int nr, volatile unsigned long *addr) | ||
64 | { | ||
65 | unsigned long mask = BIT_MASK(nr); | ||
66 | unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); | ||
67 | unsigned long old; | ||
68 | unsigned long tmp; | ||
69 | |||
70 | __asm__ __volatile__( | ||
71 | "1: l.lwa %0,0(%2) \n" | ||
72 | " l.or %1,%0,%3 \n" | ||
73 | " l.swa 0(%2),%1 \n" | ||
74 | " l.bnf 1b \n" | ||
75 | " l.nop \n" | ||
76 | : "=&r"(old), "=&r"(tmp) | ||
77 | : "r"(p), "r"(mask) | ||
78 | : "cc", "memory"); | ||
79 | |||
80 | return (old & mask) != 0; | ||
81 | } | ||
82 | |||
83 | static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) | ||
84 | { | ||
85 | unsigned long mask = BIT_MASK(nr); | ||
86 | unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); | ||
87 | unsigned long old; | ||
88 | unsigned long tmp; | ||
89 | |||
90 | __asm__ __volatile__( | ||
91 | "1: l.lwa %0,0(%2) \n" | ||
92 | " l.and %1,%0,%3 \n" | ||
93 | " l.swa 0(%2),%1 \n" | ||
94 | " l.bnf 1b \n" | ||
95 | " l.nop \n" | ||
96 | : "=&r"(old), "=&r"(tmp) | ||
97 | : "r"(p), "r"(~mask) | ||
98 | : "cc", "memory"); | ||
99 | |||
100 | return (old & mask) != 0; | ||
101 | } | ||
102 | |||
103 | static inline int test_and_change_bit(int nr, volatile unsigned long *addr) | ||
104 | { | ||
105 | unsigned long mask = BIT_MASK(nr); | ||
106 | unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); | ||
107 | unsigned long old; | ||
108 | unsigned long tmp; | ||
109 | |||
110 | __asm__ __volatile__( | ||
111 | "1: l.lwa %0,0(%2) \n" | ||
112 | " l.xor %1,%0,%3 \n" | ||
113 | " l.swa 0(%2),%1 \n" | ||
114 | " l.bnf 1b \n" | ||
115 | " l.nop \n" | ||
116 | : "=&r"(old), "=&r"(tmp) | ||
117 | : "r"(p), "r"(mask) | ||
118 | : "cc", "memory"); | ||
119 | |||
120 | return (old & mask) != 0; | ||
121 | } | ||
122 | |||
123 | #endif /* __ASM_OPENRISC_BITOPS_ATOMIC_H */ | ||
diff --git a/arch/openrisc/include/asm/cmpxchg.h b/arch/openrisc/include/asm/cmpxchg.h new file mode 100644 index 000000000000..5fcb9ac72693 --- /dev/null +++ b/arch/openrisc/include/asm/cmpxchg.h | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi> | ||
3 | * | ||
4 | * This file is licensed under the terms of the GNU General Public License | ||
5 | * version 2. This program is licensed "as is" without any warranty of any | ||
6 | * kind, whether express or implied. | ||
7 | */ | ||
8 | |||
9 | #ifndef __ASM_OPENRISC_CMPXCHG_H | ||
10 | #define __ASM_OPENRISC_CMPXCHG_H | ||
11 | |||
12 | #include <linux/types.h> | ||
13 | |||
14 | /* | ||
15 | * This function doesn't exist, so you'll get a linker error | ||
16 | * if something tries to do an invalid cmpxchg(). | ||
17 | */ | ||
18 | extern void __cmpxchg_called_with_bad_pointer(void); | ||
19 | |||
20 | #define __HAVE_ARCH_CMPXCHG 1 | ||
21 | |||
22 | static inline unsigned long | ||
23 | __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) | ||
24 | { | ||
25 | if (size != 4) { | ||
26 | __cmpxchg_called_with_bad_pointer(); | ||
27 | return old; | ||
28 | } | ||
29 | |||
30 | __asm__ __volatile__( | ||
31 | "1: l.lwa %0, 0(%1) \n" | ||
32 | " l.sfeq %0, %2 \n" | ||
33 | " l.bnf 2f \n" | ||
34 | " l.nop \n" | ||
35 | " l.swa 0(%1), %3 \n" | ||
36 | " l.bnf 1b \n" | ||
37 | " l.nop \n" | ||
38 | "2: \n" | ||
39 | : "=&r"(old) | ||
40 | : "r"(ptr), "r"(old), "r"(new) | ||
41 | : "cc", "memory"); | ||
42 | |||
43 | return old; | ||
44 | } | ||
45 | |||
46 | #define cmpxchg(ptr, o, n) \ | ||
47 | ({ \ | ||
48 | (__typeof__(*(ptr))) __cmpxchg((ptr), \ | ||
49 | (unsigned long)(o), \ | ||
50 | (unsigned long)(n), \ | ||
51 | sizeof(*(ptr))); \ | ||
52 | }) | ||
53 | |||
54 | /* | ||
55 | * This function doesn't exist, so you'll get a linker error if | ||
56 | * something tries to do an invalidly-sized xchg(). | ||
57 | */ | ||
58 | extern void __xchg_called_with_bad_pointer(void); | ||
59 | |||
60 | static inline unsigned long __xchg(unsigned long val, volatile void *ptr, | ||
61 | int size) | ||
62 | { | ||
63 | if (size != 4) { | ||
64 | __xchg_called_with_bad_pointer(); | ||
65 | return val; | ||
66 | } | ||
67 | |||
68 | __asm__ __volatile__( | ||
69 | "1: l.lwa %0, 0(%1) \n" | ||
70 | " l.swa 0(%1), %2 \n" | ||
71 | " l.bnf 1b \n" | ||
72 | " l.nop \n" | ||
73 | : "=&r"(val) | ||
74 | : "r"(ptr), "r"(val) | ||
75 | : "cc", "memory"); | ||
76 | |||
77 | return val; | ||
78 | } | ||
79 | |||
80 | #define xchg(ptr, with) \ | ||
81 | ((typeof(*(ptr)))__xchg((unsigned long)(with), (ptr), sizeof(*(ptr)))) | ||
82 | |||
83 | #endif /* __ASM_OPENRISC_CMPXCHG_H */ | ||
diff --git a/arch/openrisc/include/asm/cpuinfo.h b/arch/openrisc/include/asm/cpuinfo.h index 917318b6a970..ec10679d6429 100644 --- a/arch/openrisc/include/asm/cpuinfo.h +++ b/arch/openrisc/include/asm/cpuinfo.h | |||
@@ -24,9 +24,11 @@ struct cpuinfo { | |||
24 | 24 | ||
25 | u32 icache_size; | 25 | u32 icache_size; |
26 | u32 icache_block_size; | 26 | u32 icache_block_size; |
27 | u32 icache_ways; | ||
27 | 28 | ||
28 | u32 dcache_size; | 29 | u32 dcache_size; |
29 | u32 dcache_block_size; | 30 | u32 dcache_block_size; |
31 | u32 dcache_ways; | ||
30 | }; | 32 | }; |
31 | 33 | ||
32 | extern struct cpuinfo cpuinfo; | 34 | extern struct cpuinfo cpuinfo; |
diff --git a/arch/openrisc/include/asm/futex.h b/arch/openrisc/include/asm/futex.h new file mode 100644 index 000000000000..778087341977 --- /dev/null +++ b/arch/openrisc/include/asm/futex.h | |||
@@ -0,0 +1,135 @@ | |||
1 | #ifndef __ASM_OPENRISC_FUTEX_H | ||
2 | #define __ASM_OPENRISC_FUTEX_H | ||
3 | |||
4 | #ifdef __KERNEL__ | ||
5 | |||
6 | #include <linux/futex.h> | ||
7 | #include <linux/uaccess.h> | ||
8 | #include <asm/errno.h> | ||
9 | |||
10 | #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ | ||
11 | ({ \ | ||
12 | __asm__ __volatile__ ( \ | ||
13 | "1: l.lwa %0, %2 \n" \ | ||
14 | insn "\n" \ | ||
15 | "2: l.swa %2, %1 \n" \ | ||
16 | " l.bnf 1b \n" \ | ||
17 | " l.ori %1, r0, 0 \n" \ | ||
18 | "3: \n" \ | ||
19 | ".section .fixup,\"ax\" \n" \ | ||
20 | "4: l.j 3b \n" \ | ||
21 | " l.addi %1, r0, %3 \n" \ | ||
22 | ".previous \n" \ | ||
23 | ".section __ex_table,\"a\" \n" \ | ||
24 | ".word 1b,4b,2b,4b \n" \ | ||
25 | ".previous \n" \ | ||
26 | : "=&r" (oldval), "=&r" (ret), "+m" (*uaddr) \ | ||
27 | : "i" (-EFAULT), "r" (oparg) \ | ||
28 | : "cc", "memory" \ | ||
29 | ); \ | ||
30 | }) | ||
31 | |||
32 | static inline int | ||
33 | futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) | ||
34 | { | ||
35 | int op = (encoded_op >> 28) & 7; | ||
36 | int cmp = (encoded_op >> 24) & 15; | ||
37 | int oparg = (encoded_op << 8) >> 20; | ||
38 | int cmparg = (encoded_op << 20) >> 20; | ||
39 | int oldval = 0, ret; | ||
40 | |||
41 | if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | ||
42 | oparg = 1 << oparg; | ||
43 | |||
44 | if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) | ||
45 | return -EFAULT; | ||
46 | |||
47 | pagefault_disable(); | ||
48 | |||
49 | switch (op) { | ||
50 | case FUTEX_OP_SET: | ||
51 | __futex_atomic_op("l.or %1,%4,%4", ret, oldval, uaddr, oparg); | ||
52 | break; | ||
53 | case FUTEX_OP_ADD: | ||
54 | __futex_atomic_op("l.add %1,%0,%4", ret, oldval, uaddr, oparg); | ||
55 | break; | ||
56 | case FUTEX_OP_OR: | ||
57 | __futex_atomic_op("l.or %1,%0,%4", ret, oldval, uaddr, oparg); | ||
58 | break; | ||
59 | case FUTEX_OP_ANDN: | ||
60 | __futex_atomic_op("l.and %1,%0,%4", ret, oldval, uaddr, ~oparg); | ||
61 | break; | ||
62 | case FUTEX_OP_XOR: | ||
63 | __futex_atomic_op("l.xor %1,%0,%4", ret, oldval, uaddr, oparg); | ||
64 | break; | ||
65 | default: | ||
66 | ret = -ENOSYS; | ||
67 | } | ||
68 | |||
69 | pagefault_enable(); | ||
70 | |||
71 | if (!ret) { | ||
72 | switch (cmp) { | ||
73 | case FUTEX_OP_CMP_EQ: | ||
74 | ret = (oldval == cmparg); | ||
75 | break; | ||
76 | case FUTEX_OP_CMP_NE: | ||
77 | ret = (oldval != cmparg); | ||
78 | break; | ||
79 | case FUTEX_OP_CMP_LT: | ||
80 | ret = (oldval < cmparg); | ||
81 | break; | ||
82 | case FUTEX_OP_CMP_GE: | ||
83 | ret = (oldval >= cmparg); | ||
84 | break; | ||
85 | case FUTEX_OP_CMP_LE: | ||
86 | ret = (oldval <= cmparg); | ||
87 | break; | ||
88 | case FUTEX_OP_CMP_GT: | ||
89 | ret = (oldval > cmparg); | ||
90 | break; | ||
91 | default: | ||
92 | ret = -ENOSYS; | ||
93 | } | ||
94 | } | ||
95 | return ret; | ||
96 | } | ||
97 | |||
98 | static inline int | ||
99 | futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, | ||
100 | u32 oldval, u32 newval) | ||
101 | { | ||
102 | int ret = 0; | ||
103 | u32 prev; | ||
104 | |||
105 | if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) | ||
106 | return -EFAULT; | ||
107 | |||
108 | __asm__ __volatile__ ( \ | ||
109 | "1: l.lwa %1, %2 \n" \ | ||
110 | " l.sfeq %1, %3 \n" \ | ||
111 | " l.bnf 3f \n" \ | ||
112 | " l.nop \n" \ | ||
113 | "2: l.swa %2, %4 \n" \ | ||
114 | " l.bnf 1b \n" \ | ||
115 | " l.nop \n" \ | ||
116 | "3: \n" \ | ||
117 | ".section .fixup,\"ax\" \n" \ | ||
118 | "4: l.j 3b \n" \ | ||
119 | " l.addi %0, r0, %5 \n" \ | ||
120 | ".previous \n" \ | ||
121 | ".section __ex_table,\"a\" \n" \ | ||
122 | ".word 1b,4b,2b,4b \n" \ | ||
123 | ".previous \n" \ | ||
124 | : "+r" (ret), "=&r" (prev), "+m" (*uaddr) \ | ||
125 | : "r" (oldval), "r" (newval), "i" (-EFAULT) \ | ||
126 | : "cc", "memory" \ | ||
127 | ); | ||
128 | |||
129 | *uval = prev; | ||
130 | return ret; | ||
131 | } | ||
132 | |||
133 | #endif /* __KERNEL__ */ | ||
134 | |||
135 | #endif /* __ASM_OPENRISC_FUTEX_H */ | ||
diff --git a/arch/openrisc/include/asm/spr_defs.h b/arch/openrisc/include/asm/spr_defs.h index 5dbc668865c4..367dac70326a 100644 --- a/arch/openrisc/include/asm/spr_defs.h +++ b/arch/openrisc/include/asm/spr_defs.h | |||
@@ -152,8 +152,8 @@ | |||
152 | #define SPR_UPR_MP 0x00000020 /* MAC present */ | 152 | #define SPR_UPR_MP 0x00000020 /* MAC present */ |
153 | #define SPR_UPR_DUP 0x00000040 /* Debug unit present */ | 153 | #define SPR_UPR_DUP 0x00000040 /* Debug unit present */ |
154 | #define SPR_UPR_PCUP 0x00000080 /* Performance counters unit present */ | 154 | #define SPR_UPR_PCUP 0x00000080 /* Performance counters unit present */ |
155 | #define SPR_UPR_PMP 0x00000100 /* Power management present */ | 155 | #define SPR_UPR_PICP 0x00000100 /* PIC present */ |
156 | #define SPR_UPR_PICP 0x00000200 /* PIC present */ | 156 | #define SPR_UPR_PMP 0x00000200 /* Power management present */ |
157 | #define SPR_UPR_TTP 0x00000400 /* Tick timer present */ | 157 | #define SPR_UPR_TTP 0x00000400 /* Tick timer present */ |
158 | #define SPR_UPR_RES 0x00fe0000 /* Reserved */ | 158 | #define SPR_UPR_RES 0x00fe0000 /* Reserved */ |
159 | #define SPR_UPR_CUP 0xff000000 /* Context units present */ | 159 | #define SPR_UPR_CUP 0xff000000 /* Context units present */ |
diff --git a/arch/openrisc/include/asm/string.h b/arch/openrisc/include/asm/string.h new file mode 100644 index 000000000000..64939ccd7531 --- /dev/null +++ b/arch/openrisc/include/asm/string.h | |||
@@ -0,0 +1,10 @@ | |||
1 | #ifndef __ASM_OPENRISC_STRING_H | ||
2 | #define __ASM_OPENRISC_STRING_H | ||
3 | |||
4 | #define __HAVE_ARCH_MEMSET | ||
5 | extern void *memset(void *s, int c, __kernel_size_t n); | ||
6 | |||
7 | #define __HAVE_ARCH_MEMCPY | ||
8 | extern void *memcpy(void *dest, __const void *src, __kernel_size_t n); | ||
9 | |||
10 | #endif /* __ASM_OPENRISC_STRING_H */ | ||
diff --git a/arch/openrisc/kernel/.gitignore b/arch/openrisc/kernel/.gitignore new file mode 100644 index 000000000000..c5f676c3c224 --- /dev/null +++ b/arch/openrisc/kernel/.gitignore | |||
@@ -0,0 +1 @@ | |||
vmlinux.lds | |||
diff --git a/arch/openrisc/kernel/entry.S b/arch/openrisc/kernel/entry.S index aac0bde3330c..bc6500860f4d 100644 --- a/arch/openrisc/kernel/entry.S +++ b/arch/openrisc/kernel/entry.S | |||
@@ -173,6 +173,11 @@ handler: ;\ | |||
173 | l.j _ret_from_exception ;\ | 173 | l.j _ret_from_exception ;\ |
174 | l.nop | 174 | l.nop |
175 | 175 | ||
176 | /* clobbers 'reg' */ | ||
177 | #define CLEAR_LWA_FLAG(reg) \ | ||
178 | l.movhi reg,hi(lwa_flag) ;\ | ||
179 | l.ori reg,reg,lo(lwa_flag) ;\ | ||
180 | l.sw 0(reg),r0 | ||
176 | /* | 181 | /* |
177 | * NOTE: one should never assume that SPR_EPC, SPR_ESR, SPR_EEAR | 182 | * NOTE: one should never assume that SPR_EPC, SPR_ESR, SPR_EEAR |
178 | * contain the same values as when exception we're handling | 183 | * contain the same values as when exception we're handling |
@@ -193,6 +198,7 @@ EXCEPTION_ENTRY(_tng_kernel_start) | |||
193 | /* ---[ 0x200: BUS exception ]------------------------------------------- */ | 198 | /* ---[ 0x200: BUS exception ]------------------------------------------- */ |
194 | 199 | ||
195 | EXCEPTION_ENTRY(_bus_fault_handler) | 200 | EXCEPTION_ENTRY(_bus_fault_handler) |
201 | CLEAR_LWA_FLAG(r3) | ||
196 | /* r4: EA of fault (set by EXCEPTION_HANDLE) */ | 202 | /* r4: EA of fault (set by EXCEPTION_HANDLE) */ |
197 | l.jal do_bus_fault | 203 | l.jal do_bus_fault |
198 | l.addi r3,r1,0 /* pt_regs */ | 204 | l.addi r3,r1,0 /* pt_regs */ |
@@ -202,11 +208,13 @@ EXCEPTION_ENTRY(_bus_fault_handler) | |||
202 | 208 | ||
203 | /* ---[ 0x300: Data Page Fault exception ]------------------------------- */ | 209 | /* ---[ 0x300: Data Page Fault exception ]------------------------------- */ |
204 | EXCEPTION_ENTRY(_dtlb_miss_page_fault_handler) | 210 | EXCEPTION_ENTRY(_dtlb_miss_page_fault_handler) |
211 | CLEAR_LWA_FLAG(r3) | ||
205 | l.and r5,r5,r0 | 212 | l.and r5,r5,r0 |
206 | l.j 1f | 213 | l.j 1f |
207 | l.nop | 214 | l.nop |
208 | 215 | ||
209 | EXCEPTION_ENTRY(_data_page_fault_handler) | 216 | EXCEPTION_ENTRY(_data_page_fault_handler) |
217 | CLEAR_LWA_FLAG(r3) | ||
210 | /* set up parameters for do_page_fault */ | 218 | /* set up parameters for do_page_fault */ |
211 | l.ori r5,r0,0x300 // exception vector | 219 | l.ori r5,r0,0x300 // exception vector |
212 | 1: | 220 | 1: |
@@ -220,7 +228,7 @@ EXCEPTION_ENTRY(_data_page_fault_handler) | |||
220 | * DTLB miss handler in the CONFIG_GUARD_PROTECTED_CORE part | 228 | * DTLB miss handler in the CONFIG_GUARD_PROTECTED_CORE part |
221 | */ | 229 | */ |
222 | #ifdef CONFIG_OPENRISC_NO_SPR_SR_DSX | 230 | #ifdef CONFIG_OPENRISC_NO_SPR_SR_DSX |
223 | l.lwz r6,PT_PC(r3) // address of an offending insn | 231 | l.lwz r6,PT_PC(r3) // address of an offending insn |
224 | l.lwz r6,0(r6) // instruction that caused pf | 232 | l.lwz r6,0(r6) // instruction that caused pf |
225 | 233 | ||
226 | l.srli r6,r6,26 // check opcode for jump insn | 234 | l.srli r6,r6,26 // check opcode for jump insn |
@@ -236,57 +244,57 @@ EXCEPTION_ENTRY(_data_page_fault_handler) | |||
236 | l.bf 8f | 244 | l.bf 8f |
237 | l.sfeqi r6,0x12 // l.jalr | 245 | l.sfeqi r6,0x12 // l.jalr |
238 | l.bf 8f | 246 | l.bf 8f |
239 | 247 | l.nop | |
240 | l.nop | ||
241 | 248 | ||
242 | l.j 9f | 249 | l.j 9f |
243 | l.nop | 250 | l.nop |
244 | 8: | ||
245 | 251 | ||
246 | l.lwz r6,PT_PC(r3) // address of an offending insn | 252 | 8: // offending insn is in delay slot |
253 | l.lwz r6,PT_PC(r3) // address of an offending insn | ||
247 | l.addi r6,r6,4 | 254 | l.addi r6,r6,4 |
248 | l.lwz r6,0(r6) // instruction that caused pf | 255 | l.lwz r6,0(r6) // instruction that caused pf |
249 | l.srli r6,r6,26 // get opcode | 256 | l.srli r6,r6,26 // get opcode |
250 | 9: | 257 | 9: // offending instruction opcode loaded in r6 |
251 | 258 | ||
252 | #else | 259 | #else |
253 | 260 | ||
254 | l.mfspr r6,r0,SPR_SR // SR | 261 | l.lwz r6,PT_SR(r3) // SR |
255 | // l.lwz r6,PT_SR(r3) // ESR | 262 | l.andi r6,r6,SPR_SR_DSX // check for delay slot exception |
256 | l.andi r6,r6,SPR_SR_DSX // check for delay slot exception | 263 | l.sfne r6,r0 // exception happened in delay slot |
257 | l.sfeqi r6,0x1 // exception happened in delay slot | 264 | l.bnf 7f |
258 | l.bnf 7f | 265 | l.lwz r6,PT_PC(r3) // address of an offending insn |
259 | l.lwz r6,PT_PC(r3) // address of an offending insn | ||
260 | 266 | ||
261 | l.addi r6,r6,4 // offending insn is in delay slot | 267 | l.addi r6,r6,4 // offending insn is in delay slot |
262 | 7: | 268 | 7: |
263 | l.lwz r6,0(r6) // instruction that caused pf | 269 | l.lwz r6,0(r6) // instruction that caused pf |
264 | l.srli r6,r6,26 // check opcode for write access | 270 | l.srli r6,r6,26 // check opcode for write access |
265 | #endif | 271 | #endif |
266 | 272 | ||
267 | l.sfgeui r6,0x33 // check opcode for write access | 273 | l.sfgeui r6,0x33 // check opcode for write access |
268 | l.bnf 1f | 274 | l.bnf 1f |
269 | l.sfleui r6,0x37 | 275 | l.sfleui r6,0x37 |
270 | l.bnf 1f | 276 | l.bnf 1f |
271 | l.ori r6,r0,0x1 // write access | 277 | l.ori r6,r0,0x1 // write access |
272 | l.j 2f | 278 | l.j 2f |
273 | l.nop | 279 | l.nop |
274 | 1: l.ori r6,r0,0x0 // !write access | 280 | 1: l.ori r6,r0,0x0 // !write access |
275 | 2: | 281 | 2: |
276 | 282 | ||
277 | /* call fault.c handler in or32/mm/fault.c */ | 283 | /* call fault.c handler in or32/mm/fault.c */ |
278 | l.jal do_page_fault | 284 | l.jal do_page_fault |
279 | l.nop | 285 | l.nop |
280 | l.j _ret_from_exception | 286 | l.j _ret_from_exception |
281 | l.nop | 287 | l.nop |
282 | 288 | ||
283 | /* ---[ 0x400: Insn Page Fault exception ]------------------------------- */ | 289 | /* ---[ 0x400: Insn Page Fault exception ]------------------------------- */ |
284 | EXCEPTION_ENTRY(_itlb_miss_page_fault_handler) | 290 | EXCEPTION_ENTRY(_itlb_miss_page_fault_handler) |
291 | CLEAR_LWA_FLAG(r3) | ||
285 | l.and r5,r5,r0 | 292 | l.and r5,r5,r0 |
286 | l.j 1f | 293 | l.j 1f |
287 | l.nop | 294 | l.nop |
288 | 295 | ||
289 | EXCEPTION_ENTRY(_insn_page_fault_handler) | 296 | EXCEPTION_ENTRY(_insn_page_fault_handler) |
297 | CLEAR_LWA_FLAG(r3) | ||
290 | /* set up parameters for do_page_fault */ | 298 | /* set up parameters for do_page_fault */ |
291 | l.ori r5,r0,0x400 // exception vector | 299 | l.ori r5,r0,0x400 // exception vector |
292 | 1: | 300 | 1: |
@@ -296,14 +304,15 @@ EXCEPTION_ENTRY(_insn_page_fault_handler) | |||
296 | 304 | ||
297 | /* call fault.c handler in or32/mm/fault.c */ | 305 | /* call fault.c handler in or32/mm/fault.c */ |
298 | l.jal do_page_fault | 306 | l.jal do_page_fault |
299 | l.nop | 307 | l.nop |
300 | l.j _ret_from_exception | 308 | l.j _ret_from_exception |
301 | l.nop | 309 | l.nop |
302 | 310 | ||
303 | 311 | ||
304 | /* ---[ 0x500: Timer exception ]----------------------------------------- */ | 312 | /* ---[ 0x500: Timer exception ]----------------------------------------- */ |
305 | 313 | ||
306 | EXCEPTION_ENTRY(_timer_handler) | 314 | EXCEPTION_ENTRY(_timer_handler) |
315 | CLEAR_LWA_FLAG(r3) | ||
307 | l.jal timer_interrupt | 316 | l.jal timer_interrupt |
308 | l.addi r3,r1,0 /* pt_regs */ | 317 | l.addi r3,r1,0 /* pt_regs */ |
309 | 318 | ||
@@ -313,6 +322,7 @@ EXCEPTION_ENTRY(_timer_handler) | |||
313 | /* ---[ 0x600: Aligment exception ]-------------------------------------- */ | 322 | /* ---[ 0x600: Aligment exception ]-------------------------------------- */ |
314 | 323 | ||
315 | EXCEPTION_ENTRY(_alignment_handler) | 324 | EXCEPTION_ENTRY(_alignment_handler) |
325 | CLEAR_LWA_FLAG(r3) | ||
316 | /* r4: EA of fault (set by EXCEPTION_HANDLE) */ | 326 | /* r4: EA of fault (set by EXCEPTION_HANDLE) */ |
317 | l.jal do_unaligned_access | 327 | l.jal do_unaligned_access |
318 | l.addi r3,r1,0 /* pt_regs */ | 328 | l.addi r3,r1,0 /* pt_regs */ |
@@ -509,6 +519,7 @@ EXCEPTION_ENTRY(_external_irq_handler) | |||
509 | // l.sw PT_SR(r1),r4 | 519 | // l.sw PT_SR(r1),r4 |
510 | 1: | 520 | 1: |
511 | #endif | 521 | #endif |
522 | CLEAR_LWA_FLAG(r3) | ||
512 | l.addi r3,r1,0 | 523 | l.addi r3,r1,0 |
513 | l.movhi r8,hi(do_IRQ) | 524 | l.movhi r8,hi(do_IRQ) |
514 | l.ori r8,r8,lo(do_IRQ) | 525 | l.ori r8,r8,lo(do_IRQ) |
@@ -556,8 +567,12 @@ ENTRY(_sys_call_handler) | |||
556 | * they should be clobbered, otherwise | 567 | * they should be clobbered, otherwise |
557 | */ | 568 | */ |
558 | l.sw PT_GPR3(r1),r3 | 569 | l.sw PT_GPR3(r1),r3 |
559 | /* r4 already saved */ | 570 | /* |
560 | /* r4 holds the EEAR address of the fault, load the original r4 */ | 571 | * r4 already saved |
572 | * r4 holds the EEAR address of the fault, use it as screatch reg and | ||
573 | * then load the original r4 | ||
574 | */ | ||
575 | CLEAR_LWA_FLAG(r4) | ||
561 | l.lwz r4,PT_GPR4(r1) | 576 | l.lwz r4,PT_GPR4(r1) |
562 | l.sw PT_GPR5(r1),r5 | 577 | l.sw PT_GPR5(r1),r5 |
563 | l.sw PT_GPR6(r1),r6 | 578 | l.sw PT_GPR6(r1),r6 |
@@ -776,6 +791,7 @@ UNHANDLED_EXCEPTION(_vector_0xd00,0xd00) | |||
776 | /* ---[ 0xe00: Trap exception ]------------------------------------------ */ | 791 | /* ---[ 0xe00: Trap exception ]------------------------------------------ */ |
777 | 792 | ||
778 | EXCEPTION_ENTRY(_trap_handler) | 793 | EXCEPTION_ENTRY(_trap_handler) |
794 | CLEAR_LWA_FLAG(r3) | ||
779 | /* r4: EA of fault (set by EXCEPTION_HANDLE) */ | 795 | /* r4: EA of fault (set by EXCEPTION_HANDLE) */ |
780 | l.jal do_trap | 796 | l.jal do_trap |
781 | l.addi r3,r1,0 /* pt_regs */ | 797 | l.addi r3,r1,0 /* pt_regs */ |
diff --git a/arch/openrisc/kernel/head.S b/arch/openrisc/kernel/head.S index f14793306b03..d01b82eace3e 100644 --- a/arch/openrisc/kernel/head.S +++ b/arch/openrisc/kernel/head.S | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <asm/page.h> | 24 | #include <asm/page.h> |
25 | #include <asm/mmu.h> | 25 | #include <asm/mmu.h> |
26 | #include <asm/pgtable.h> | 26 | #include <asm/pgtable.h> |
27 | #include <asm/thread_info.h> | ||
27 | #include <asm/cache.h> | 28 | #include <asm/cache.h> |
28 | #include <asm/spr_defs.h> | 29 | #include <asm/spr_defs.h> |
29 | #include <asm/asm-offsets.h> | 30 | #include <asm/asm-offsets.h> |
@@ -34,7 +35,7 @@ | |||
34 | l.add rd,rd,rs | 35 | l.add rd,rd,rs |
35 | 36 | ||
36 | #define CLEAR_GPR(gpr) \ | 37 | #define CLEAR_GPR(gpr) \ |
37 | l.or gpr,r0,r0 | 38 | l.movhi gpr,0x0 |
38 | 39 | ||
39 | #define LOAD_SYMBOL_2_GPR(gpr,symbol) \ | 40 | #define LOAD_SYMBOL_2_GPR(gpr,symbol) \ |
40 | l.movhi gpr,hi(symbol) ;\ | 41 | l.movhi gpr,hi(symbol) ;\ |
@@ -442,6 +443,9 @@ _dispatch_do_ipage_fault: | |||
442 | __HEAD | 443 | __HEAD |
443 | .global _start | 444 | .global _start |
444 | _start: | 445 | _start: |
446 | /* Init r0 to zero as per spec */ | ||
447 | CLEAR_GPR(r0) | ||
448 | |||
445 | /* save kernel parameters */ | 449 | /* save kernel parameters */ |
446 | l.or r25,r0,r3 /* pointer to fdt */ | 450 | l.or r25,r0,r3 /* pointer to fdt */ |
447 | 451 | ||
@@ -486,7 +490,8 @@ _start: | |||
486 | /* | 490 | /* |
487 | * set up initial ksp and current | 491 | * set up initial ksp and current |
488 | */ | 492 | */ |
489 | LOAD_SYMBOL_2_GPR(r1,init_thread_union+0x2000) // setup kernel stack | 493 | /* setup kernel stack */ |
494 | LOAD_SYMBOL_2_GPR(r1,init_thread_union + THREAD_SIZE) | ||
490 | LOAD_SYMBOL_2_GPR(r10,init_thread_union) // setup current | 495 | LOAD_SYMBOL_2_GPR(r10,init_thread_union) // setup current |
491 | tophys (r31,r10) | 496 | tophys (r31,r10) |
492 | l.sw TI_KSP(r31), r1 | 497 | l.sw TI_KSP(r31), r1 |
@@ -520,22 +525,8 @@ enable_dc: | |||
520 | l.nop | 525 | l.nop |
521 | 526 | ||
522 | flush_tlb: | 527 | flush_tlb: |
523 | /* | 528 | l.jal _flush_tlb |
524 | * I N V A L I D A T E T L B e n t r i e s | 529 | l.nop |
525 | */ | ||
526 | LOAD_SYMBOL_2_GPR(r5,SPR_DTLBMR_BASE(0)) | ||
527 | LOAD_SYMBOL_2_GPR(r6,SPR_ITLBMR_BASE(0)) | ||
528 | l.addi r7,r0,128 /* Maximum number of sets */ | ||
529 | 1: | ||
530 | l.mtspr r5,r0,0x0 | ||
531 | l.mtspr r6,r0,0x0 | ||
532 | |||
533 | l.addi r5,r5,1 | ||
534 | l.addi r6,r6,1 | ||
535 | l.sfeq r7,r0 | ||
536 | l.bnf 1b | ||
537 | l.addi r7,r7,-1 | ||
538 | |||
539 | 530 | ||
540 | /* The MMU needs to be enabled before or32_early_setup is called */ | 531 | /* The MMU needs to be enabled before or32_early_setup is called */ |
541 | 532 | ||
@@ -627,6 +618,26 @@ jump_start_kernel: | |||
627 | l.jr r30 | 618 | l.jr r30 |
628 | l.nop | 619 | l.nop |
629 | 620 | ||
621 | _flush_tlb: | ||
622 | /* | ||
623 | * I N V A L I D A T E T L B e n t r i e s | ||
624 | */ | ||
625 | LOAD_SYMBOL_2_GPR(r5,SPR_DTLBMR_BASE(0)) | ||
626 | LOAD_SYMBOL_2_GPR(r6,SPR_ITLBMR_BASE(0)) | ||
627 | l.addi r7,r0,128 /* Maximum number of sets */ | ||
628 | 1: | ||
629 | l.mtspr r5,r0,0x0 | ||
630 | l.mtspr r6,r0,0x0 | ||
631 | |||
632 | l.addi r5,r5,1 | ||
633 | l.addi r6,r6,1 | ||
634 | l.sfeq r7,r0 | ||
635 | l.bnf 1b | ||
636 | l.addi r7,r7,-1 | ||
637 | |||
638 | l.jr r9 | ||
639 | l.nop | ||
640 | |||
630 | /* ========================================[ cache ]=== */ | 641 | /* ========================================[ cache ]=== */ |
631 | 642 | ||
632 | /* aligment here so we don't change memory offsets with | 643 | /* aligment here so we don't change memory offsets with |
@@ -971,8 +982,6 @@ ENTRY(dtlb_miss_handler) | |||
971 | EXCEPTION_STORE_GPR2 | 982 | EXCEPTION_STORE_GPR2 |
972 | EXCEPTION_STORE_GPR3 | 983 | EXCEPTION_STORE_GPR3 |
973 | EXCEPTION_STORE_GPR4 | 984 | EXCEPTION_STORE_GPR4 |
974 | EXCEPTION_STORE_GPR5 | ||
975 | EXCEPTION_STORE_GPR6 | ||
976 | /* | 985 | /* |
977 | * get EA of the miss | 986 | * get EA of the miss |
978 | */ | 987 | */ |
@@ -980,91 +989,70 @@ ENTRY(dtlb_miss_handler) | |||
980 | /* | 989 | /* |
981 | * pmd = (pmd_t *)(current_pgd + pgd_index(daddr)); | 990 | * pmd = (pmd_t *)(current_pgd + pgd_index(daddr)); |
982 | */ | 991 | */ |
983 | GET_CURRENT_PGD(r3,r5) // r3 is current_pgd, r5 is temp | 992 | GET_CURRENT_PGD(r3,r4) // r3 is current_pgd, r4 is temp |
984 | l.srli r4,r2,0x18 // >> PAGE_SHIFT + (PAGE_SHIFT - 2) | 993 | l.srli r4,r2,0x18 // >> PAGE_SHIFT + (PAGE_SHIFT - 2) |
985 | l.slli r4,r4,0x2 // to get address << 2 | 994 | l.slli r4,r4,0x2 // to get address << 2 |
986 | l.add r5,r4,r3 // r4 is pgd_index(daddr) | 995 | l.add r3,r4,r3 // r4 is pgd_index(daddr) |
987 | /* | 996 | /* |
988 | * if (pmd_none(*pmd)) | 997 | * if (pmd_none(*pmd)) |
989 | * goto pmd_none: | 998 | * goto pmd_none: |
990 | */ | 999 | */ |
991 | tophys (r4,r5) | 1000 | tophys (r4,r3) |
992 | l.lwz r3,0x0(r4) // get *pmd value | 1001 | l.lwz r3,0x0(r4) // get *pmd value |
993 | l.sfne r3,r0 | 1002 | l.sfne r3,r0 |
994 | l.bnf d_pmd_none | 1003 | l.bnf d_pmd_none |
995 | l.andi r3,r3,~PAGE_MASK //0x1fff // ~PAGE_MASK | 1004 | l.addi r3,r0,0xffffe000 // PAGE_MASK |
996 | /* | 1005 | |
997 | * if (pmd_bad(*pmd)) | ||
998 | * pmd_clear(pmd) | ||
999 | * goto pmd_bad: | ||
1000 | */ | ||
1001 | // l.sfeq r3,r0 // check *pmd value | ||
1002 | // l.bf d_pmd_good | ||
1003 | l.addi r3,r0,0xffffe000 // PAGE_MASK | ||
1004 | // l.j d_pmd_bad | ||
1005 | // l.sw 0x0(r4),r0 // clear pmd | ||
1006 | d_pmd_good: | 1006 | d_pmd_good: |
1007 | /* | 1007 | /* |
1008 | * pte = *pte_offset(pmd, daddr); | 1008 | * pte = *pte_offset(pmd, daddr); |
1009 | */ | 1009 | */ |
1010 | l.lwz r4,0x0(r4) // get **pmd value | 1010 | l.lwz r4,0x0(r4) // get **pmd value |
1011 | l.and r4,r4,r3 // & PAGE_MASK | 1011 | l.and r4,r4,r3 // & PAGE_MASK |
1012 | l.srli r5,r2,0xd // >> PAGE_SHIFT, r2 == EEAR | 1012 | l.srli r2,r2,0xd // >> PAGE_SHIFT, r2 == EEAR |
1013 | l.andi r3,r5,0x7ff // (1UL << PAGE_SHIFT - 2) - 1 | 1013 | l.andi r3,r2,0x7ff // (1UL << PAGE_SHIFT - 2) - 1 |
1014 | l.slli r3,r3,0x2 // to get address << 2 | 1014 | l.slli r3,r3,0x2 // to get address << 2 |
1015 | l.add r3,r3,r4 | 1015 | l.add r3,r3,r4 |
1016 | l.lwz r2,0x0(r3) // this is pte at last | 1016 | l.lwz r3,0x0(r3) // this is pte at last |
1017 | /* | 1017 | /* |
1018 | * if (!pte_present(pte)) | 1018 | * if (!pte_present(pte)) |
1019 | */ | 1019 | */ |
1020 | l.andi r4,r2,0x1 | 1020 | l.andi r4,r3,0x1 |
1021 | l.sfne r4,r0 // is pte present | 1021 | l.sfne r4,r0 // is pte present |
1022 | l.bnf d_pte_not_present | 1022 | l.bnf d_pte_not_present |
1023 | l.addi r3,r0,0xffffe3fa // PAGE_MASK | DTLB_UP_CONVERT_MASK | 1023 | l.addi r4,r0,0xffffe3fa // PAGE_MASK | DTLB_UP_CONVERT_MASK |
1024 | /* | 1024 | /* |
1025 | * fill DTLB TR register | 1025 | * fill DTLB TR register |
1026 | */ | 1026 | */ |
1027 | l.and r4,r2,r3 // apply the mask | 1027 | l.and r4,r3,r4 // apply the mask |
1028 | // Determine number of DMMU sets | 1028 | // Determine number of DMMU sets |
1029 | l.mfspr r6, r0, SPR_DMMUCFGR | 1029 | l.mfspr r2, r0, SPR_DMMUCFGR |
1030 | l.andi r6, r6, SPR_DMMUCFGR_NTS | 1030 | l.andi r2, r2, SPR_DMMUCFGR_NTS |
1031 | l.srli r6, r6, SPR_DMMUCFGR_NTS_OFF | 1031 | l.srli r2, r2, SPR_DMMUCFGR_NTS_OFF |
1032 | l.ori r3, r0, 0x1 | 1032 | l.ori r3, r0, 0x1 |
1033 | l.sll r3, r3, r6 // r3 = number DMMU sets DMMUCFGR | 1033 | l.sll r3, r3, r2 // r3 = number DMMU sets DMMUCFGR |
1034 | l.addi r6, r3, -1 // r6 = nsets mask | 1034 | l.addi r2, r3, -1 // r2 = nsets mask |
1035 | l.and r5, r5, r6 // calc offset: & (NUM_TLB_ENTRIES-1) | 1035 | l.mfspr r3, r0, SPR_EEAR_BASE |
1036 | l.srli r3, r3, 0xd // >> PAGE_SHIFT | ||
1037 | l.and r2, r3, r2 // calc offset: & (NUM_TLB_ENTRIES-1) | ||
1036 | //NUM_TLB_ENTRIES | 1038 | //NUM_TLB_ENTRIES |
1037 | l.mtspr r5,r4,SPR_DTLBTR_BASE(0) | 1039 | l.mtspr r2,r4,SPR_DTLBTR_BASE(0) |
1038 | /* | 1040 | /* |
1039 | * fill DTLB MR register | 1041 | * fill DTLB MR register |
1040 | */ | 1042 | */ |
1041 | l.mfspr r2,r0,SPR_EEAR_BASE | 1043 | l.slli r3, r3, 0xd /* << PAGE_SHIFT => EA & PAGE_MASK */ |
1042 | l.addi r3,r0,0xffffe000 // PAGE_MASK | 1044 | l.ori r4,r3,0x1 // set hardware valid bit: DTBL_MR entry |
1043 | l.and r4,r2,r3 // apply PAGE_MASK to EA (__PHX__ do we really need this?) | 1045 | l.mtspr r2,r4,SPR_DTLBMR_BASE(0) |
1044 | l.ori r4,r4,0x1 // set hardware valid bit: DTBL_MR entry | ||
1045 | l.mtspr r5,r4,SPR_DTLBMR_BASE(0) | ||
1046 | 1046 | ||
1047 | EXCEPTION_LOAD_GPR2 | 1047 | EXCEPTION_LOAD_GPR2 |
1048 | EXCEPTION_LOAD_GPR3 | 1048 | EXCEPTION_LOAD_GPR3 |
1049 | EXCEPTION_LOAD_GPR4 | 1049 | EXCEPTION_LOAD_GPR4 |
1050 | EXCEPTION_LOAD_GPR5 | ||
1051 | EXCEPTION_LOAD_GPR6 | ||
1052 | l.rfe | ||
1053 | d_pmd_bad: | ||
1054 | l.nop 1 | ||
1055 | EXCEPTION_LOAD_GPR2 | ||
1056 | EXCEPTION_LOAD_GPR3 | ||
1057 | EXCEPTION_LOAD_GPR4 | ||
1058 | EXCEPTION_LOAD_GPR5 | ||
1059 | EXCEPTION_LOAD_GPR6 | ||
1060 | l.rfe | 1050 | l.rfe |
1061 | d_pmd_none: | 1051 | d_pmd_none: |
1062 | d_pte_not_present: | 1052 | d_pte_not_present: |
1063 | EXCEPTION_LOAD_GPR2 | 1053 | EXCEPTION_LOAD_GPR2 |
1064 | EXCEPTION_LOAD_GPR3 | 1054 | EXCEPTION_LOAD_GPR3 |
1065 | EXCEPTION_LOAD_GPR4 | 1055 | EXCEPTION_LOAD_GPR4 |
1066 | EXCEPTION_LOAD_GPR5 | ||
1067 | EXCEPTION_LOAD_GPR6 | ||
1068 | EXCEPTION_HANDLE(_dtlb_miss_page_fault_handler) | 1056 | EXCEPTION_HANDLE(_dtlb_miss_page_fault_handler) |
1069 | 1057 | ||
1070 | /* ==============================================[ ITLB miss handler ]=== */ | 1058 | /* ==============================================[ ITLB miss handler ]=== */ |
@@ -1072,8 +1060,6 @@ ENTRY(itlb_miss_handler) | |||
1072 | EXCEPTION_STORE_GPR2 | 1060 | EXCEPTION_STORE_GPR2 |
1073 | EXCEPTION_STORE_GPR3 | 1061 | EXCEPTION_STORE_GPR3 |
1074 | EXCEPTION_STORE_GPR4 | 1062 | EXCEPTION_STORE_GPR4 |
1075 | EXCEPTION_STORE_GPR5 | ||
1076 | EXCEPTION_STORE_GPR6 | ||
1077 | /* | 1063 | /* |
1078 | * get EA of the miss | 1064 | * get EA of the miss |
1079 | */ | 1065 | */ |
@@ -1083,30 +1069,19 @@ ENTRY(itlb_miss_handler) | |||
1083 | * pmd = (pmd_t *)(current_pgd + pgd_index(daddr)); | 1069 | * pmd = (pmd_t *)(current_pgd + pgd_index(daddr)); |
1084 | * | 1070 | * |
1085 | */ | 1071 | */ |
1086 | GET_CURRENT_PGD(r3,r5) // r3 is current_pgd, r5 is temp | 1072 | GET_CURRENT_PGD(r3,r4) // r3 is current_pgd, r5 is temp |
1087 | l.srli r4,r2,0x18 // >> PAGE_SHIFT + (PAGE_SHIFT - 2) | 1073 | l.srli r4,r2,0x18 // >> PAGE_SHIFT + (PAGE_SHIFT - 2) |
1088 | l.slli r4,r4,0x2 // to get address << 2 | 1074 | l.slli r4,r4,0x2 // to get address << 2 |
1089 | l.add r5,r4,r3 // r4 is pgd_index(daddr) | 1075 | l.add r3,r4,r3 // r4 is pgd_index(daddr) |
1090 | /* | 1076 | /* |
1091 | * if (pmd_none(*pmd)) | 1077 | * if (pmd_none(*pmd)) |
1092 | * goto pmd_none: | 1078 | * goto pmd_none: |
1093 | */ | 1079 | */ |
1094 | tophys (r4,r5) | 1080 | tophys (r4,r3) |
1095 | l.lwz r3,0x0(r4) // get *pmd value | 1081 | l.lwz r3,0x0(r4) // get *pmd value |
1096 | l.sfne r3,r0 | 1082 | l.sfne r3,r0 |
1097 | l.bnf i_pmd_none | 1083 | l.bnf i_pmd_none |
1098 | l.andi r3,r3,0x1fff // ~PAGE_MASK | 1084 | l.addi r3,r0,0xffffe000 // PAGE_MASK |
1099 | /* | ||
1100 | * if (pmd_bad(*pmd)) | ||
1101 | * pmd_clear(pmd) | ||
1102 | * goto pmd_bad: | ||
1103 | */ | ||
1104 | |||
1105 | // l.sfeq r3,r0 // check *pmd value | ||
1106 | // l.bf i_pmd_good | ||
1107 | l.addi r3,r0,0xffffe000 // PAGE_MASK | ||
1108 | // l.j i_pmd_bad | ||
1109 | // l.sw 0x0(r4),r0 // clear pmd | ||
1110 | 1085 | ||
1111 | i_pmd_good: | 1086 | i_pmd_good: |
1112 | /* | 1087 | /* |
@@ -1115,35 +1090,36 @@ i_pmd_good: | |||
1115 | */ | 1090 | */ |
1116 | l.lwz r4,0x0(r4) // get **pmd value | 1091 | l.lwz r4,0x0(r4) // get **pmd value |
1117 | l.and r4,r4,r3 // & PAGE_MASK | 1092 | l.and r4,r4,r3 // & PAGE_MASK |
1118 | l.srli r5,r2,0xd // >> PAGE_SHIFT, r2 == EEAR | 1093 | l.srli r2,r2,0xd // >> PAGE_SHIFT, r2 == EEAR |
1119 | l.andi r3,r5,0x7ff // (1UL << PAGE_SHIFT - 2) - 1 | 1094 | l.andi r3,r2,0x7ff // (1UL << PAGE_SHIFT - 2) - 1 |
1120 | l.slli r3,r3,0x2 // to get address << 2 | 1095 | l.slli r3,r3,0x2 // to get address << 2 |
1121 | l.add r3,r3,r4 | 1096 | l.add r3,r3,r4 |
1122 | l.lwz r2,0x0(r3) // this is pte at last | 1097 | l.lwz r3,0x0(r3) // this is pte at last |
1123 | /* | 1098 | /* |
1124 | * if (!pte_present(pte)) | 1099 | * if (!pte_present(pte)) |
1125 | * | 1100 | * |
1126 | */ | 1101 | */ |
1127 | l.andi r4,r2,0x1 | 1102 | l.andi r4,r3,0x1 |
1128 | l.sfne r4,r0 // is pte present | 1103 | l.sfne r4,r0 // is pte present |
1129 | l.bnf i_pte_not_present | 1104 | l.bnf i_pte_not_present |
1130 | l.addi r3,r0,0xffffe03a // PAGE_MASK | ITLB_UP_CONVERT_MASK | 1105 | l.addi r4,r0,0xffffe03a // PAGE_MASK | ITLB_UP_CONVERT_MASK |
1131 | /* | 1106 | /* |
1132 | * fill ITLB TR register | 1107 | * fill ITLB TR register |
1133 | */ | 1108 | */ |
1134 | l.and r4,r2,r3 // apply the mask | 1109 | l.and r4,r3,r4 // apply the mask |
1135 | l.andi r3,r2,0x7c0 // _PAGE_EXEC | _PAGE_SRE | _PAGE_SWE | _PAGE_URE | _PAGE_UWE | 1110 | l.andi r3,r3,0x7c0 // _PAGE_EXEC | _PAGE_SRE | _PAGE_SWE | _PAGE_URE | _PAGE_UWE |
1136 | // l.andi r3,r2,0x400 // _PAGE_EXEC | ||
1137 | l.sfeq r3,r0 | 1111 | l.sfeq r3,r0 |
1138 | l.bf itlb_tr_fill //_workaround | 1112 | l.bf itlb_tr_fill //_workaround |
1139 | // Determine number of IMMU sets | 1113 | // Determine number of IMMU sets |
1140 | l.mfspr r6, r0, SPR_IMMUCFGR | 1114 | l.mfspr r2, r0, SPR_IMMUCFGR |
1141 | l.andi r6, r6, SPR_IMMUCFGR_NTS | 1115 | l.andi r2, r2, SPR_IMMUCFGR_NTS |
1142 | l.srli r6, r6, SPR_IMMUCFGR_NTS_OFF | 1116 | l.srli r2, r2, SPR_IMMUCFGR_NTS_OFF |
1143 | l.ori r3, r0, 0x1 | 1117 | l.ori r3, r0, 0x1 |
1144 | l.sll r3, r3, r6 // r3 = number IMMU sets IMMUCFGR | 1118 | l.sll r3, r3, r2 // r3 = number IMMU sets IMMUCFGR |
1145 | l.addi r6, r3, -1 // r6 = nsets mask | 1119 | l.addi r2, r3, -1 // r2 = nsets mask |
1146 | l.and r5, r5, r6 // calc offset: & (NUM_TLB_ENTRIES-1) | 1120 | l.mfspr r3, r0, SPR_EEAR_BASE |
1121 | l.srli r3, r3, 0xd // >> PAGE_SHIFT | ||
1122 | l.and r2, r3, r2 // calc offset: & (NUM_TLB_ENTRIES-1) | ||
1147 | 1123 | ||
1148 | /* | 1124 | /* |
1149 | * __PHX__ :: fixme | 1125 | * __PHX__ :: fixme |
@@ -1155,38 +1131,24 @@ i_pmd_good: | |||
1155 | itlb_tr_fill_workaround: | 1131 | itlb_tr_fill_workaround: |
1156 | l.ori r4,r4,0xc0 // | (SPR_ITLBTR_UXE | ITLBTR_SXE) | 1132 | l.ori r4,r4,0xc0 // | (SPR_ITLBTR_UXE | ITLBTR_SXE) |
1157 | itlb_tr_fill: | 1133 | itlb_tr_fill: |
1158 | l.mtspr r5,r4,SPR_ITLBTR_BASE(0) | 1134 | l.mtspr r2,r4,SPR_ITLBTR_BASE(0) |
1159 | /* | 1135 | /* |
1160 | * fill DTLB MR register | 1136 | * fill DTLB MR register |
1161 | */ | 1137 | */ |
1162 | l.mfspr r2,r0,SPR_EEAR_BASE | 1138 | l.slli r3, r3, 0xd /* << PAGE_SHIFT => EA & PAGE_MASK */ |
1163 | l.addi r3,r0,0xffffe000 // PAGE_MASK | 1139 | l.ori r4,r3,0x1 // set hardware valid bit: ITBL_MR entry |
1164 | l.and r4,r2,r3 // apply PAGE_MASK to EA (__PHX__ do we really need this?) | 1140 | l.mtspr r2,r4,SPR_ITLBMR_BASE(0) |
1165 | l.ori r4,r4,0x1 // set hardware valid bit: DTBL_MR entry | ||
1166 | l.mtspr r5,r4,SPR_ITLBMR_BASE(0) | ||
1167 | 1141 | ||
1168 | EXCEPTION_LOAD_GPR2 | 1142 | EXCEPTION_LOAD_GPR2 |
1169 | EXCEPTION_LOAD_GPR3 | 1143 | EXCEPTION_LOAD_GPR3 |
1170 | EXCEPTION_LOAD_GPR4 | 1144 | EXCEPTION_LOAD_GPR4 |
1171 | EXCEPTION_LOAD_GPR5 | ||
1172 | EXCEPTION_LOAD_GPR6 | ||
1173 | l.rfe | 1145 | l.rfe |
1174 | 1146 | ||
1175 | i_pmd_bad: | ||
1176 | l.nop 1 | ||
1177 | EXCEPTION_LOAD_GPR2 | ||
1178 | EXCEPTION_LOAD_GPR3 | ||
1179 | EXCEPTION_LOAD_GPR4 | ||
1180 | EXCEPTION_LOAD_GPR5 | ||
1181 | EXCEPTION_LOAD_GPR6 | ||
1182 | l.rfe | ||
1183 | i_pmd_none: | 1147 | i_pmd_none: |
1184 | i_pte_not_present: | 1148 | i_pte_not_present: |
1185 | EXCEPTION_LOAD_GPR2 | 1149 | EXCEPTION_LOAD_GPR2 |
1186 | EXCEPTION_LOAD_GPR3 | 1150 | EXCEPTION_LOAD_GPR3 |
1187 | EXCEPTION_LOAD_GPR4 | 1151 | EXCEPTION_LOAD_GPR4 |
1188 | EXCEPTION_LOAD_GPR5 | ||
1189 | EXCEPTION_LOAD_GPR6 | ||
1190 | EXCEPTION_HANDLE(_itlb_miss_page_fault_handler) | 1152 | EXCEPTION_HANDLE(_itlb_miss_page_fault_handler) |
1191 | 1153 | ||
1192 | /* ==============================================[ boot tlb handlers ]=== */ | 1154 | /* ==============================================[ boot tlb handlers ]=== */ |
@@ -1571,12 +1533,7 @@ ENTRY(_early_uart_init) | |||
1571 | l.jr r9 | 1533 | l.jr r9 |
1572 | l.nop | 1534 | l.nop |
1573 | 1535 | ||
1574 | _string_copying_linux: | 1536 | .section .rodata |
1575 | .string "\n\n\n\n\n\rCopying Linux... \0" | ||
1576 | |||
1577 | _string_ok_booting: | ||
1578 | .string "Ok, booting the kernel.\n\r\0" | ||
1579 | |||
1580 | _string_unhandled_exception: | 1537 | _string_unhandled_exception: |
1581 | .string "\n\rRunarunaround: Unhandled exception 0x\0" | 1538 | .string "\n\rRunarunaround: Unhandled exception 0x\0" |
1582 | 1539 | ||
@@ -1586,11 +1543,6 @@ _string_epc_prefix: | |||
1586 | _string_nl: | 1543 | _string_nl: |
1587 | .string "\n\r\0" | 1544 | .string "\n\r\0" |
1588 | 1545 | ||
1589 | .global _string_esr_irq_bug | ||
1590 | _string_esr_irq_bug: | ||
1591 | .string "\n\rESR external interrupt bug, for details look into entry.S\n\r\0" | ||
1592 | |||
1593 | |||
1594 | 1546 | ||
1595 | /* ========================================[ page aligned structures ]=== */ | 1547 | /* ========================================[ page aligned structures ]=== */ |
1596 | 1548 | ||
diff --git a/arch/openrisc/kernel/or32_ksyms.c b/arch/openrisc/kernel/or32_ksyms.c index 86e31cf1de1d..5c4695d13542 100644 --- a/arch/openrisc/kernel/or32_ksyms.c +++ b/arch/openrisc/kernel/or32_ksyms.c | |||
@@ -44,3 +44,4 @@ DECLARE_EXPORT(__ashldi3); | |||
44 | DECLARE_EXPORT(__lshrdi3); | 44 | DECLARE_EXPORT(__lshrdi3); |
45 | 45 | ||
46 | EXPORT_SYMBOL(__copy_tofrom_user); | 46 | EXPORT_SYMBOL(__copy_tofrom_user); |
47 | EXPORT_SYMBOL(memset); | ||
diff --git a/arch/openrisc/kernel/process.c b/arch/openrisc/kernel/process.c index d7990df9025a..6e9d1cb519f2 100644 --- a/arch/openrisc/kernel/process.c +++ b/arch/openrisc/kernel/process.c | |||
@@ -75,6 +75,17 @@ void machine_power_off(void) | |||
75 | __asm__("l.nop 1"); | 75 | __asm__("l.nop 1"); |
76 | } | 76 | } |
77 | 77 | ||
78 | /* | ||
79 | * Send the doze signal to the cpu if available. | ||
80 | * Make sure, that all interrupts are enabled | ||
81 | */ | ||
82 | void arch_cpu_idle(void) | ||
83 | { | ||
84 | local_irq_enable(); | ||
85 | if (mfspr(SPR_UPR) & SPR_UPR_PMP) | ||
86 | mtspr(SPR_PMR, mfspr(SPR_PMR) | SPR_PMR_DME); | ||
87 | } | ||
88 | |||
78 | void (*pm_power_off) (void) = machine_power_off; | 89 | void (*pm_power_off) (void) = machine_power_off; |
79 | 90 | ||
80 | /* | 91 | /* |
@@ -226,6 +237,7 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpu) | |||
226 | 237 | ||
227 | extern struct thread_info *_switch(struct thread_info *old_ti, | 238 | extern struct thread_info *_switch(struct thread_info *old_ti, |
228 | struct thread_info *new_ti); | 239 | struct thread_info *new_ti); |
240 | extern int lwa_flag; | ||
229 | 241 | ||
230 | struct task_struct *__switch_to(struct task_struct *old, | 242 | struct task_struct *__switch_to(struct task_struct *old, |
231 | struct task_struct *new) | 243 | struct task_struct *new) |
@@ -243,6 +255,8 @@ struct task_struct *__switch_to(struct task_struct *old, | |||
243 | new_ti = new->stack; | 255 | new_ti = new->stack; |
244 | old_ti = old->stack; | 256 | old_ti = old->stack; |
245 | 257 | ||
258 | lwa_flag = 0; | ||
259 | |||
246 | current_thread_info_set[smp_processor_id()] = new_ti; | 260 | current_thread_info_set[smp_processor_id()] = new_ti; |
247 | last = (_switch(old_ti, new_ti))->task; | 261 | last = (_switch(old_ti, new_ti))->task; |
248 | 262 | ||
diff --git a/arch/openrisc/kernel/ptrace.c b/arch/openrisc/kernel/ptrace.c index 4f59fa4e34e5..228288887d74 100644 --- a/arch/openrisc/kernel/ptrace.c +++ b/arch/openrisc/kernel/ptrace.c | |||
@@ -16,7 +16,6 @@ | |||
16 | * 2 of the License, or (at your option) any later version. | 16 | * 2 of the License, or (at your option) any later version. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <stddef.h> | ||
20 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
21 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
22 | #include <linux/string.h> | 21 | #include <linux/string.h> |
diff --git a/arch/openrisc/kernel/setup.c b/arch/openrisc/kernel/setup.c index cb797a3beb47..dbf5ee95a0d5 100644 --- a/arch/openrisc/kernel/setup.c +++ b/arch/openrisc/kernel/setup.c | |||
@@ -117,13 +117,15 @@ static void print_cpuinfo(void) | |||
117 | if (upr & SPR_UPR_DCP) | 117 | if (upr & SPR_UPR_DCP) |
118 | printk(KERN_INFO | 118 | printk(KERN_INFO |
119 | "-- dcache: %4d bytes total, %2d bytes/line, %d way(s)\n", | 119 | "-- dcache: %4d bytes total, %2d bytes/line, %d way(s)\n", |
120 | cpuinfo.dcache_size, cpuinfo.dcache_block_size, 1); | 120 | cpuinfo.dcache_size, cpuinfo.dcache_block_size, |
121 | cpuinfo.dcache_ways); | ||
121 | else | 122 | else |
122 | printk(KERN_INFO "-- dcache disabled\n"); | 123 | printk(KERN_INFO "-- dcache disabled\n"); |
123 | if (upr & SPR_UPR_ICP) | 124 | if (upr & SPR_UPR_ICP) |
124 | printk(KERN_INFO | 125 | printk(KERN_INFO |
125 | "-- icache: %4d bytes total, %2d bytes/line, %d way(s)\n", | 126 | "-- icache: %4d bytes total, %2d bytes/line, %d way(s)\n", |
126 | cpuinfo.icache_size, cpuinfo.icache_block_size, 1); | 127 | cpuinfo.icache_size, cpuinfo.icache_block_size, |
128 | cpuinfo.icache_ways); | ||
127 | else | 129 | else |
128 | printk(KERN_INFO "-- icache disabled\n"); | 130 | printk(KERN_INFO "-- icache disabled\n"); |
129 | 131 | ||
@@ -155,25 +157,25 @@ void __init setup_cpuinfo(void) | |||
155 | { | 157 | { |
156 | struct device_node *cpu; | 158 | struct device_node *cpu; |
157 | unsigned long iccfgr, dccfgr; | 159 | unsigned long iccfgr, dccfgr; |
158 | unsigned long cache_set_size, cache_ways; | 160 | unsigned long cache_set_size; |
159 | 161 | ||
160 | cpu = of_find_compatible_node(NULL, NULL, "opencores,or1200-rtlsvn481"); | 162 | cpu = of_find_compatible_node(NULL, NULL, "opencores,or1200-rtlsvn481"); |
161 | if (!cpu) | 163 | if (!cpu) |
162 | panic("No compatible CPU found in device tree...\n"); | 164 | panic("No compatible CPU found in device tree...\n"); |
163 | 165 | ||
164 | iccfgr = mfspr(SPR_ICCFGR); | 166 | iccfgr = mfspr(SPR_ICCFGR); |
165 | cache_ways = 1 << (iccfgr & SPR_ICCFGR_NCW); | 167 | cpuinfo.icache_ways = 1 << (iccfgr & SPR_ICCFGR_NCW); |
166 | cache_set_size = 1 << ((iccfgr & SPR_ICCFGR_NCS) >> 3); | 168 | cache_set_size = 1 << ((iccfgr & SPR_ICCFGR_NCS) >> 3); |
167 | cpuinfo.icache_block_size = 16 << ((iccfgr & SPR_ICCFGR_CBS) >> 7); | 169 | cpuinfo.icache_block_size = 16 << ((iccfgr & SPR_ICCFGR_CBS) >> 7); |
168 | cpuinfo.icache_size = | 170 | cpuinfo.icache_size = |
169 | cache_set_size * cache_ways * cpuinfo.icache_block_size; | 171 | cache_set_size * cpuinfo.icache_ways * cpuinfo.icache_block_size; |
170 | 172 | ||
171 | dccfgr = mfspr(SPR_DCCFGR); | 173 | dccfgr = mfspr(SPR_DCCFGR); |
172 | cache_ways = 1 << (dccfgr & SPR_DCCFGR_NCW); | 174 | cpuinfo.dcache_ways = 1 << (dccfgr & SPR_DCCFGR_NCW); |
173 | cache_set_size = 1 << ((dccfgr & SPR_DCCFGR_NCS) >> 3); | 175 | cache_set_size = 1 << ((dccfgr & SPR_DCCFGR_NCS) >> 3); |
174 | cpuinfo.dcache_block_size = 16 << ((dccfgr & SPR_DCCFGR_CBS) >> 7); | 176 | cpuinfo.dcache_block_size = 16 << ((dccfgr & SPR_DCCFGR_CBS) >> 7); |
175 | cpuinfo.dcache_size = | 177 | cpuinfo.dcache_size = |
176 | cache_set_size * cache_ways * cpuinfo.dcache_block_size; | 178 | cache_set_size * cpuinfo.dcache_ways * cpuinfo.dcache_block_size; |
177 | 179 | ||
178 | if (of_property_read_u32(cpu, "clock-frequency", | 180 | if (of_property_read_u32(cpu, "clock-frequency", |
179 | &cpuinfo.clock_frequency)) { | 181 | &cpuinfo.clock_frequency)) { |
@@ -308,30 +310,33 @@ static int show_cpuinfo(struct seq_file *m, void *v) | |||
308 | revision = vr & SPR_VR_REV; | 310 | revision = vr & SPR_VR_REV; |
309 | 311 | ||
310 | seq_printf(m, | 312 | seq_printf(m, |
311 | "cpu\t\t: OpenRISC-%x\n" | 313 | "cpu\t\t: OpenRISC-%x\n" |
312 | "revision\t: %d\n" | 314 | "revision\t: %d\n" |
313 | "frequency\t: %ld\n" | 315 | "frequency\t: %ld\n" |
314 | "dcache size\t: %d bytes\n" | 316 | "dcache size\t: %d bytes\n" |
315 | "dcache block size\t: %d bytes\n" | 317 | "dcache block size\t: %d bytes\n" |
316 | "icache size\t: %d bytes\n" | 318 | "dcache ways\t: %d\n" |
317 | "icache block size\t: %d bytes\n" | 319 | "icache size\t: %d bytes\n" |
318 | "immu\t\t: %d entries, %lu ways\n" | 320 | "icache block size\t: %d bytes\n" |
319 | "dmmu\t\t: %d entries, %lu ways\n" | 321 | "icache ways\t: %d\n" |
320 | "bogomips\t: %lu.%02lu\n", | 322 | "immu\t\t: %d entries, %lu ways\n" |
321 | version, | 323 | "dmmu\t\t: %d entries, %lu ways\n" |
322 | revision, | 324 | "bogomips\t: %lu.%02lu\n", |
323 | loops_per_jiffy * HZ, | 325 | version, |
324 | cpuinfo.dcache_size, | 326 | revision, |
325 | cpuinfo.dcache_block_size, | 327 | loops_per_jiffy * HZ, |
326 | cpuinfo.icache_size, | 328 | cpuinfo.dcache_size, |
327 | cpuinfo.icache_block_size, | 329 | cpuinfo.dcache_block_size, |
328 | 1 << ((mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTS) >> 2), | 330 | cpuinfo.dcache_ways, |
329 | 1 + (mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTW), | 331 | cpuinfo.icache_size, |
330 | 1 << ((mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTS) >> 2), | 332 | cpuinfo.icache_block_size, |
331 | 1 + (mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTW), | 333 | cpuinfo.icache_ways, |
332 | (loops_per_jiffy * HZ) / 500000, | 334 | 1 << ((mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTS) >> 2), |
333 | ((loops_per_jiffy * HZ) / 5000) % 100); | 335 | 1 + (mfspr(SPR_DMMUCFGR) & SPR_DMMUCFGR_NTW), |
334 | 336 | 1 << ((mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTS) >> 2), | |
337 | 1 + (mfspr(SPR_IMMUCFGR) & SPR_IMMUCFGR_NTW), | ||
338 | (loops_per_jiffy * HZ) / 500000, | ||
339 | ((loops_per_jiffy * HZ) / 5000) % 100); | ||
335 | return 0; | 340 | return 0; |
336 | } | 341 | } |
337 | 342 | ||
diff --git a/arch/openrisc/kernel/traps.c b/arch/openrisc/kernel/traps.c index d29c41bfbffa..7e81ad258bca 100644 --- a/arch/openrisc/kernel/traps.c +++ b/arch/openrisc/kernel/traps.c | |||
@@ -40,6 +40,8 @@ | |||
40 | extern char _etext, _stext; | 40 | extern char _etext, _stext; |
41 | 41 | ||
42 | int kstack_depth_to_print = 0x180; | 42 | int kstack_depth_to_print = 0x180; |
43 | int lwa_flag; | ||
44 | unsigned long __user *lwa_addr; | ||
43 | 45 | ||
44 | static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) | 46 | static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) |
45 | { | 47 | { |
@@ -334,10 +336,191 @@ asmlinkage void do_bus_fault(struct pt_regs *regs, unsigned long address) | |||
334 | } | 336 | } |
335 | } | 337 | } |
336 | 338 | ||
339 | static inline int in_delay_slot(struct pt_regs *regs) | ||
340 | { | ||
341 | #ifdef CONFIG_OPENRISC_NO_SPR_SR_DSX | ||
342 | /* No delay slot flag, do the old way */ | ||
343 | unsigned int op, insn; | ||
344 | |||
345 | insn = *((unsigned int *)regs->pc); | ||
346 | op = insn >> 26; | ||
347 | switch (op) { | ||
348 | case 0x00: /* l.j */ | ||
349 | case 0x01: /* l.jal */ | ||
350 | case 0x03: /* l.bnf */ | ||
351 | case 0x04: /* l.bf */ | ||
352 | case 0x11: /* l.jr */ | ||
353 | case 0x12: /* l.jalr */ | ||
354 | return 1; | ||
355 | default: | ||
356 | return 0; | ||
357 | } | ||
358 | #else | ||
359 | return regs->sr & SPR_SR_DSX; | ||
360 | #endif | ||
361 | } | ||
362 | |||
363 | static inline void adjust_pc(struct pt_regs *regs, unsigned long address) | ||
364 | { | ||
365 | int displacement; | ||
366 | unsigned int rb, op, jmp; | ||
367 | |||
368 | if (unlikely(in_delay_slot(regs))) { | ||
369 | /* In delay slot, instruction at pc is a branch, simulate it */ | ||
370 | jmp = *((unsigned int *)regs->pc); | ||
371 | |||
372 | displacement = sign_extend32(((jmp) & 0x3ffffff) << 2, 27); | ||
373 | rb = (jmp & 0x0000ffff) >> 11; | ||
374 | op = jmp >> 26; | ||
375 | |||
376 | switch (op) { | ||
377 | case 0x00: /* l.j */ | ||
378 | regs->pc += displacement; | ||
379 | return; | ||
380 | case 0x01: /* l.jal */ | ||
381 | regs->pc += displacement; | ||
382 | regs->gpr[9] = regs->pc + 8; | ||
383 | return; | ||
384 | case 0x03: /* l.bnf */ | ||
385 | if (regs->sr & SPR_SR_F) | ||
386 | regs->pc += 8; | ||
387 | else | ||
388 | regs->pc += displacement; | ||
389 | return; | ||
390 | case 0x04: /* l.bf */ | ||
391 | if (regs->sr & SPR_SR_F) | ||
392 | regs->pc += displacement; | ||
393 | else | ||
394 | regs->pc += 8; | ||
395 | return; | ||
396 | case 0x11: /* l.jr */ | ||
397 | regs->pc = regs->gpr[rb]; | ||
398 | return; | ||
399 | case 0x12: /* l.jalr */ | ||
400 | regs->pc = regs->gpr[rb]; | ||
401 | regs->gpr[9] = regs->pc + 8; | ||
402 | return; | ||
403 | default: | ||
404 | break; | ||
405 | } | ||
406 | } else { | ||
407 | regs->pc += 4; | ||
408 | } | ||
409 | } | ||
410 | |||
411 | static inline void simulate_lwa(struct pt_regs *regs, unsigned long address, | ||
412 | unsigned int insn) | ||
413 | { | ||
414 | unsigned int ra, rd; | ||
415 | unsigned long value; | ||
416 | unsigned long orig_pc; | ||
417 | long imm; | ||
418 | |||
419 | const struct exception_table_entry *entry; | ||
420 | |||
421 | orig_pc = regs->pc; | ||
422 | adjust_pc(regs, address); | ||
423 | |||
424 | ra = (insn >> 16) & 0x1f; | ||
425 | rd = (insn >> 21) & 0x1f; | ||
426 | imm = (short)insn; | ||
427 | lwa_addr = (unsigned long __user *)(regs->gpr[ra] + imm); | ||
428 | |||
429 | if ((unsigned long)lwa_addr & 0x3) { | ||
430 | do_unaligned_access(regs, address); | ||
431 | return; | ||
432 | } | ||
433 | |||
434 | if (get_user(value, lwa_addr)) { | ||
435 | if (user_mode(regs)) { | ||
436 | force_sig(SIGSEGV, current); | ||
437 | return; | ||
438 | } | ||
439 | |||
440 | if ((entry = search_exception_tables(orig_pc))) { | ||
441 | regs->pc = entry->fixup; | ||
442 | return; | ||
443 | } | ||
444 | |||
445 | /* kernel access in kernel space, load it directly */ | ||
446 | value = *((unsigned long *)lwa_addr); | ||
447 | } | ||
448 | |||
449 | lwa_flag = 1; | ||
450 | regs->gpr[rd] = value; | ||
451 | } | ||
452 | |||
453 | static inline void simulate_swa(struct pt_regs *regs, unsigned long address, | ||
454 | unsigned int insn) | ||
455 | { | ||
456 | unsigned long __user *vaddr; | ||
457 | unsigned long orig_pc; | ||
458 | unsigned int ra, rb; | ||
459 | long imm; | ||
460 | |||
461 | const struct exception_table_entry *entry; | ||
462 | |||
463 | orig_pc = regs->pc; | ||
464 | adjust_pc(regs, address); | ||
465 | |||
466 | ra = (insn >> 16) & 0x1f; | ||
467 | rb = (insn >> 11) & 0x1f; | ||
468 | imm = (short)(((insn & 0x2200000) >> 10) | (insn & 0x7ff)); | ||
469 | vaddr = (unsigned long __user *)(regs->gpr[ra] + imm); | ||
470 | |||
471 | if (!lwa_flag || vaddr != lwa_addr) { | ||
472 | regs->sr &= ~SPR_SR_F; | ||
473 | return; | ||
474 | } | ||
475 | |||
476 | if ((unsigned long)vaddr & 0x3) { | ||
477 | do_unaligned_access(regs, address); | ||
478 | return; | ||
479 | } | ||
480 | |||
481 | if (put_user(regs->gpr[rb], vaddr)) { | ||
482 | if (user_mode(regs)) { | ||
483 | force_sig(SIGSEGV, current); | ||
484 | return; | ||
485 | } | ||
486 | |||
487 | if ((entry = search_exception_tables(orig_pc))) { | ||
488 | regs->pc = entry->fixup; | ||
489 | return; | ||
490 | } | ||
491 | |||
492 | /* kernel access in kernel space, store it directly */ | ||
493 | *((unsigned long *)vaddr) = regs->gpr[rb]; | ||
494 | } | ||
495 | |||
496 | lwa_flag = 0; | ||
497 | regs->sr |= SPR_SR_F; | ||
498 | } | ||
499 | |||
500 | #define INSN_LWA 0x1b | ||
501 | #define INSN_SWA 0x33 | ||
502 | |||
337 | asmlinkage void do_illegal_instruction(struct pt_regs *regs, | 503 | asmlinkage void do_illegal_instruction(struct pt_regs *regs, |
338 | unsigned long address) | 504 | unsigned long address) |
339 | { | 505 | { |
340 | siginfo_t info; | 506 | siginfo_t info; |
507 | unsigned int op; | ||
508 | unsigned int insn = *((unsigned int *)address); | ||
509 | |||
510 | op = insn >> 26; | ||
511 | |||
512 | switch (op) { | ||
513 | case INSN_LWA: | ||
514 | simulate_lwa(regs, address, insn); | ||
515 | return; | ||
516 | |||
517 | case INSN_SWA: | ||
518 | simulate_swa(regs, address, insn); | ||
519 | return; | ||
520 | |||
521 | default: | ||
522 | break; | ||
523 | } | ||
341 | 524 | ||
342 | if (user_mode(regs)) { | 525 | if (user_mode(regs)) { |
343 | /* Send a SIGILL */ | 526 | /* Send a SIGILL */ |
diff --git a/arch/openrisc/lib/Makefile b/arch/openrisc/lib/Makefile index 966f65dbc6f0..17d9d37f32d2 100644 --- a/arch/openrisc/lib/Makefile +++ b/arch/openrisc/lib/Makefile | |||
@@ -2,4 +2,4 @@ | |||
2 | # Makefile for or32 specific library files.. | 2 | # Makefile for or32 specific library files.. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y = string.o delay.o | 5 | obj-y := delay.o string.o memset.o memcpy.o |
diff --git a/arch/openrisc/lib/memcpy.c b/arch/openrisc/lib/memcpy.c new file mode 100644 index 000000000000..669887a60e27 --- /dev/null +++ b/arch/openrisc/lib/memcpy.c | |||
@@ -0,0 +1,124 @@ | |||
1 | /* | ||
2 | * arch/openrisc/lib/memcpy.c | ||
3 | * | ||
4 | * Optimized memory copy routines for openrisc. These are mostly copied | ||
5 | * from ohter sources but slightly entended based on ideas discuassed in | ||
6 | * #openrisc. | ||
7 | * | ||
8 | * The word unroll implementation is an extension to the arm byte | ||
9 | * unrolled implementation, but using word copies (if things are | ||
10 | * properly aligned) | ||
11 | * | ||
12 | * The great arm loop unroll algorithm can be found at: | ||
13 | * arch/arm/boot/compressed/string.c | ||
14 | */ | ||
15 | |||
16 | #include <linux/export.h> | ||
17 | |||
18 | #include <linux/string.h> | ||
19 | |||
20 | #ifdef CONFIG_OR1K_1200 | ||
21 | /* | ||
22 | * Do memcpy with word copies and loop unrolling. This gives the | ||
23 | * best performance on the OR1200 and MOR1KX archirectures | ||
24 | */ | ||
25 | void *memcpy(void *dest, __const void *src, __kernel_size_t n) | ||
26 | { | ||
27 | int i = 0; | ||
28 | unsigned char *d, *s; | ||
29 | uint32_t *dest_w = (uint32_t *)dest, *src_w = (uint32_t *)src; | ||
30 | |||
31 | /* If both source and dest are word aligned copy words */ | ||
32 | if (!((unsigned int)dest_w & 3) && !((unsigned int)src_w & 3)) { | ||
33 | /* Copy 32 bytes per loop */ | ||
34 | for (i = n >> 5; i > 0; i--) { | ||
35 | *dest_w++ = *src_w++; | ||
36 | *dest_w++ = *src_w++; | ||
37 | *dest_w++ = *src_w++; | ||
38 | *dest_w++ = *src_w++; | ||
39 | *dest_w++ = *src_w++; | ||
40 | *dest_w++ = *src_w++; | ||
41 | *dest_w++ = *src_w++; | ||
42 | *dest_w++ = *src_w++; | ||
43 | } | ||
44 | |||
45 | if (n & 1 << 4) { | ||
46 | *dest_w++ = *src_w++; | ||
47 | *dest_w++ = *src_w++; | ||
48 | *dest_w++ = *src_w++; | ||
49 | *dest_w++ = *src_w++; | ||
50 | } | ||
51 | |||
52 | if (n & 1 << 3) { | ||
53 | *dest_w++ = *src_w++; | ||
54 | *dest_w++ = *src_w++; | ||
55 | } | ||
56 | |||
57 | if (n & 1 << 2) | ||
58 | *dest_w++ = *src_w++; | ||
59 | |||
60 | d = (unsigned char *)dest_w; | ||
61 | s = (unsigned char *)src_w; | ||
62 | |||
63 | } else { | ||
64 | d = (unsigned char *)dest_w; | ||
65 | s = (unsigned char *)src_w; | ||
66 | |||
67 | for (i = n >> 3; i > 0; i--) { | ||
68 | *d++ = *s++; | ||
69 | *d++ = *s++; | ||
70 | *d++ = *s++; | ||
71 | *d++ = *s++; | ||
72 | *d++ = *s++; | ||
73 | *d++ = *s++; | ||
74 | *d++ = *s++; | ||
75 | *d++ = *s++; | ||
76 | } | ||
77 | |||
78 | if (n & 1 << 2) { | ||
79 | *d++ = *s++; | ||
80 | *d++ = *s++; | ||
81 | *d++ = *s++; | ||
82 | *d++ = *s++; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | if (n & 1 << 1) { | ||
87 | *d++ = *s++; | ||
88 | *d++ = *s++; | ||
89 | } | ||
90 | |||
91 | if (n & 1) | ||
92 | *d++ = *s++; | ||
93 | |||
94 | return dest; | ||
95 | } | ||
96 | #else | ||
97 | /* | ||
98 | * Use word copies but no loop unrolling as we cannot assume there | ||
99 | * will be benefits on the archirecture | ||
100 | */ | ||
101 | void *memcpy(void *dest, __const void *src, __kernel_size_t n) | ||
102 | { | ||
103 | unsigned char *d = (unsigned char *)dest, *s = (unsigned char *)src; | ||
104 | uint32_t *dest_w = (uint32_t *)dest, *src_w = (uint32_t *)src; | ||
105 | |||
106 | /* If both source and dest are word aligned copy words */ | ||
107 | if (!((unsigned int)dest_w & 3) && !((unsigned int)src_w & 3)) { | ||
108 | for (; n >= 4; n -= 4) | ||
109 | *dest_w++ = *src_w++; | ||
110 | } | ||
111 | |||
112 | d = (unsigned char *)dest_w; | ||
113 | s = (unsigned char *)src_w; | ||
114 | |||
115 | /* For remaining or if not aligned, copy bytes */ | ||
116 | for (; n >= 1; n -= 1) | ||
117 | *d++ = *s++; | ||
118 | |||
119 | return dest; | ||
120 | |||
121 | } | ||
122 | #endif | ||
123 | |||
124 | EXPORT_SYMBOL(memcpy); | ||
diff --git a/arch/openrisc/lib/memset.S b/arch/openrisc/lib/memset.S new file mode 100644 index 000000000000..92cc2eac26fa --- /dev/null +++ b/arch/openrisc/lib/memset.S | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * OpenRISC memset.S | ||
3 | * | ||
4 | * Hand-optimized assembler version of memset for OpenRISC. | ||
5 | * Algorithm inspired by several other arch-specific memset routines | ||
6 | * in the kernel tree | ||
7 | * | ||
8 | * Copyright (C) 2015 Olof Kindgren <olof.kindgren@gmail.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License | ||
12 | * as published by the Free Software Foundation; either version | ||
13 | * 2 of the License, or (at your option) any later version. | ||
14 | */ | ||
15 | |||
16 | .global memset | ||
17 | .type memset, @function | ||
18 | memset: | ||
19 | /* arguments: | ||
20 | * r3 = *s | ||
21 | * r4 = c | ||
22 | * r5 = n | ||
23 | * r13, r15, r17, r19 used as temp regs | ||
24 | */ | ||
25 | |||
26 | /* Exit if n == 0 */ | ||
27 | l.sfeqi r5, 0 | ||
28 | l.bf 4f | ||
29 | |||
30 | /* Truncate c to char */ | ||
31 | l.andi r13, r4, 0xff | ||
32 | |||
33 | /* Skip word extension if c is 0 */ | ||
34 | l.sfeqi r13, 0 | ||
35 | l.bf 1f | ||
36 | /* Check for at least two whole words (8 bytes) */ | ||
37 | l.sfleui r5, 7 | ||
38 | |||
39 | /* Extend char c to 32-bit word cccc in r13 */ | ||
40 | l.slli r15, r13, 16 // r13 = 000c, r15 = 0c00 | ||
41 | l.or r13, r13, r15 // r13 = 0c0c, r15 = 0c00 | ||
42 | l.slli r15, r13, 8 // r13 = 0c0c, r15 = c0c0 | ||
43 | l.or r13, r13, r15 // r13 = cccc, r15 = c0c0 | ||
44 | |||
45 | 1: l.addi r19, r3, 0 // Set r19 = src | ||
46 | /* Jump to byte copy loop if less than two words */ | ||
47 | l.bf 3f | ||
48 | l.or r17, r5, r0 // Set r17 = n | ||
49 | |||
50 | /* Mask out two LSBs to check alignment */ | ||
51 | l.andi r15, r3, 0x3 | ||
52 | |||
53 | /* lsb == 00, jump to word copy loop */ | ||
54 | l.sfeqi r15, 0 | ||
55 | l.bf 2f | ||
56 | l.addi r19, r3, 0 // Set r19 = src | ||
57 | |||
58 | /* lsb == 01,10 or 11 */ | ||
59 | l.sb 0(r3), r13 // *src = c | ||
60 | l.addi r17, r17, -1 // Decrease n | ||
61 | |||
62 | l.sfeqi r15, 3 | ||
63 | l.bf 2f | ||
64 | l.addi r19, r3, 1 // src += 1 | ||
65 | |||
66 | /* lsb == 01 or 10 */ | ||
67 | l.sb 1(r3), r13 // *(src+1) = c | ||
68 | l.addi r17, r17, -1 // Decrease n | ||
69 | |||
70 | l.sfeqi r15, 2 | ||
71 | l.bf 2f | ||
72 | l.addi r19, r3, 2 // src += 2 | ||
73 | |||
74 | /* lsb == 01 */ | ||
75 | l.sb 2(r3), r13 // *(src+2) = c | ||
76 | l.addi r17, r17, -1 // Decrease n | ||
77 | l.addi r19, r3, 3 // src += 3 | ||
78 | |||
79 | /* Word copy loop */ | ||
80 | 2: l.sw 0(r19), r13 // *src = cccc | ||
81 | l.addi r17, r17, -4 // Decrease n | ||
82 | l.sfgeui r17, 4 | ||
83 | l.bf 2b | ||
84 | l.addi r19, r19, 4 // Increase src | ||
85 | |||
86 | /* When n > 0, copy the remaining bytes, otherwise jump to exit */ | ||
87 | l.sfeqi r17, 0 | ||
88 | l.bf 4f | ||
89 | |||
90 | /* Byte copy loop */ | ||
91 | 3: l.addi r17, r17, -1 // Decrease n | ||
92 | l.sb 0(r19), r13 // *src = cccc | ||
93 | l.sfnei r17, 0 | ||
94 | l.bf 3b | ||
95 | l.addi r19, r19, 1 // Increase src | ||
96 | |||
97 | 4: l.jr r9 | ||
98 | l.ori r11, r3, 0 | ||
diff --git a/arch/openrisc/mm/ioremap.c b/arch/openrisc/mm/ioremap.c index 8705a46218f9..2175e4bfd9fc 100644 --- a/arch/openrisc/mm/ioremap.c +++ b/arch/openrisc/mm/ioremap.c | |||
@@ -80,6 +80,7 @@ __ioremap(phys_addr_t addr, unsigned long size, pgprot_t prot) | |||
80 | 80 | ||
81 | return (void __iomem *)(offset + (char *)v); | 81 | return (void __iomem *)(offset + (char *)v); |
82 | } | 82 | } |
83 | EXPORT_SYMBOL(__ioremap); | ||
83 | 84 | ||
84 | void iounmap(void *addr) | 85 | void iounmap(void *addr) |
85 | { | 86 | { |
@@ -106,6 +107,7 @@ void iounmap(void *addr) | |||
106 | 107 | ||
107 | return vfree((void *)(PAGE_MASK & (unsigned long)addr)); | 108 | return vfree((void *)(PAGE_MASK & (unsigned long)addr)); |
108 | } | 109 | } |
110 | EXPORT_SYMBOL(iounmap); | ||
109 | 111 | ||
110 | /** | 112 | /** |
111 | * OK, this one's a bit tricky... ioremap can get called before memory is | 113 | * OK, this one's a bit tricky... ioremap can get called before memory is |
diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h index 9ed8b987185b..3f38eb03649c 100644 --- a/include/asm-generic/atomic.h +++ b/include/asm-generic/atomic.h | |||
@@ -223,6 +223,7 @@ static inline void atomic_dec(atomic_t *v) | |||
223 | #define atomic_xchg(ptr, v) (xchg(&(ptr)->counter, (v))) | 223 | #define atomic_xchg(ptr, v) (xchg(&(ptr)->counter, (v))) |
224 | #define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new))) | 224 | #define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new))) |
225 | 225 | ||
226 | #ifndef __atomic_add_unless | ||
226 | static inline int __atomic_add_unless(atomic_t *v, int a, int u) | 227 | static inline int __atomic_add_unless(atomic_t *v, int a, int u) |
227 | { | 228 | { |
228 | int c, old; | 229 | int c, old; |
@@ -231,5 +232,6 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) | |||
231 | c = old; | 232 | c = old; |
232 | return c; | 233 | return c; |
233 | } | 234 | } |
235 | #endif | ||
234 | 236 | ||
235 | #endif /* __ASM_GENERIC_ATOMIC_H */ | 237 | #endif /* __ASM_GENERIC_ATOMIC_H */ |
diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl index 694a075381b0..3033be701e9a 100755 --- a/scripts/checkstack.pl +++ b/scripts/checkstack.pl | |||
@@ -81,6 +81,9 @@ my (@stack, $re, $dre, $x, $xs, $funcre); | |||
81 | } elsif ($arch eq 'nios2') { | 81 | } elsif ($arch eq 'nios2') { |
82 | #25a8: defffb04 addi sp,sp,-20 | 82 | #25a8: defffb04 addi sp,sp,-20 |
83 | $re = qr/.*addi.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o; | 83 | $re = qr/.*addi.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o; |
84 | } elsif ($arch eq 'openrisc') { | ||
85 | # c000043c: 9c 21 fe f0 l.addi r1,r1,-272 | ||
86 | $re = qr/.*l\.addi.*r1,r1,-(([0-9]{2}|[3-9])[0-9]{2})/o; | ||
84 | } elsif ($arch eq 'parisc' || $arch eq 'parisc64') { | 87 | } elsif ($arch eq 'parisc' || $arch eq 'parisc64') { |
85 | $re = qr/.*ldo ($x{1,8})\(sp\),sp/o; | 88 | $re = qr/.*ldo ($x{1,8})\(sp\),sp/o; |
86 | } elsif ($arch eq 'ppc') { | 89 | } elsif ($arch eq 'ppc') { |