aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin
diff options
context:
space:
mode:
authorGraf Yang <graf.yang@analog.com>2009-01-07 10:14:39 -0500
committerBryan Wu <cooloney@kernel.org>2009-01-07 10:14:39 -0500
commit6b3087c64a92a36ae20d33479b4df6d7afc910d4 (patch)
tree95984fc623658ebf150d0d912a7f6c5a0301a5a9 /arch/blackfin
parentc51b4488cd5bff08ed5690a8f303ff7f0894da2a (diff)
Blackfin arch: SMP supporting patchset: Blackfin header files and machine common code
Blackfin dual core BF561 processor can support SMP like features. https://docs.blackfin.uclinux.org/doku.php?id=linux-kernel:smp-like In this patch, we provide SMP extend to Blackfin header files and machine common code Signed-off-by: Graf Yang <graf.yang@analog.com> Signed-off-by: Bryan Wu <cooloney@kernel.org>
Diffstat (limited to 'arch/blackfin')
-rw-r--r--arch/blackfin/include/asm/atomic.h119
-rw-r--r--arch/blackfin/include/asm/bfin-global.h5
-rw-r--r--arch/blackfin/include/asm/bitops.h189
-rw-r--r--arch/blackfin/include/asm/cache.h29
-rw-r--r--arch/blackfin/include/asm/cacheflush.h20
-rw-r--r--arch/blackfin/include/asm/context.S6
-rw-r--r--arch/blackfin/include/asm/cpu.h42
-rw-r--r--arch/blackfin/include/asm/l1layout.h3
-rw-r--r--arch/blackfin/include/asm/mutex-dec.h112
-rw-r--r--arch/blackfin/include/asm/mutex.h63
-rw-r--r--arch/blackfin/include/asm/pda.h70
-rw-r--r--arch/blackfin/include/asm/percpu.h12
-rw-r--r--arch/blackfin/include/asm/processor.h7
-rw-r--r--arch/blackfin/include/asm/rwlock.h6
-rw-r--r--arch/blackfin/include/asm/smp.h42
-rw-r--r--arch/blackfin/include/asm/spinlock.h87
-rw-r--r--arch/blackfin/include/asm/spinlock_types.h22
-rw-r--r--arch/blackfin/include/asm/system.h116
-rw-r--r--arch/blackfin/mach-common/Makefile1
-rw-r--r--arch/blackfin/mach-common/cache.S36
-rw-r--r--arch/blackfin/mach-common/entry.S92
-rw-r--r--arch/blackfin/mach-common/head.S29
-rw-r--r--arch/blackfin/mach-common/ints-priority.c41
-rw-r--r--arch/blackfin/mach-common/smp.c476
-rw-r--r--arch/blackfin/oprofile/common.c2
25 files changed, 1435 insertions, 192 deletions
diff --git a/arch/blackfin/include/asm/atomic.h b/arch/blackfin/include/asm/atomic.h
index 25776c19064b..d76275e5638c 100644
--- a/arch/blackfin/include/asm/atomic.h
+++ b/arch/blackfin/include/asm/atomic.h
@@ -15,11 +15,80 @@
15 */ 15 */
16 16
17#define ATOMIC_INIT(i) { (i) } 17#define ATOMIC_INIT(i) { (i) }
18
19#define atomic_read(v) ((v)->counter)
20#define atomic_set(v, i) (((v)->counter) = i) 18#define atomic_set(v, i) (((v)->counter) = i)
21 19
22static __inline__ void atomic_add(int i, atomic_t * v) 20#ifdef CONFIG_SMP
21
22#define atomic_read(v) __raw_uncached_fetch_asm(&(v)->counter)
23
24asmlinkage int __raw_uncached_fetch_asm(const volatile int *ptr);
25
26asmlinkage int __raw_atomic_update_asm(volatile int *ptr, int value);
27
28asmlinkage int __raw_atomic_clear_asm(volatile int *ptr, int value);
29
30asmlinkage int __raw_atomic_set_asm(volatile int *ptr, int value);
31
32asmlinkage int __raw_atomic_xor_asm(volatile int *ptr, int value);
33
34asmlinkage int __raw_atomic_test_asm(const volatile int *ptr, int value);
35
36static inline void atomic_add(int i, atomic_t *v)
37{
38 __raw_atomic_update_asm(&v->counter, i);
39}
40
41static inline void atomic_sub(int i, atomic_t *v)
42{
43 __raw_atomic_update_asm(&v->counter, -i);
44}
45
46static inline int atomic_add_return(int i, atomic_t *v)
47{
48 return __raw_atomic_update_asm(&v->counter, i);
49}
50
51static inline int atomic_sub_return(int i, atomic_t *v)
52{
53 return __raw_atomic_update_asm(&v->counter, -i);
54}
55
56static inline void atomic_inc(volatile atomic_t *v)
57{
58 __raw_atomic_update_asm(&v->counter, 1);
59}
60
61static inline void atomic_dec(volatile atomic_t *v)
62{
63 __raw_atomic_update_asm(&v->counter, -1);
64}
65
66static inline void atomic_clear_mask(int mask, atomic_t *v)
67{
68 __raw_atomic_clear_asm(&v->counter, mask);
69}
70
71static inline void atomic_set_mask(int mask, atomic_t *v)
72{
73 __raw_atomic_set_asm(&v->counter, mask);
74}
75
76static inline int atomic_test_mask(int mask, atomic_t *v)
77{
78 return __raw_atomic_test_asm(&v->counter, mask);
79}
80
81/* Atomic operations are already serializing */
82#define smp_mb__before_atomic_dec() barrier()
83#define smp_mb__after_atomic_dec() barrier()
84#define smp_mb__before_atomic_inc() barrier()
85#define smp_mb__after_atomic_inc() barrier()
86
87#else /* !CONFIG_SMP */
88
89#define atomic_read(v) ((v)->counter)
90
91static inline void atomic_add(int i, atomic_t *v)
23{ 92{
24 long flags; 93 long flags;
25 94
@@ -28,7 +97,7 @@ static __inline__ void atomic_add(int i, atomic_t * v)
28 local_irq_restore(flags); 97 local_irq_restore(flags);
29} 98}
30 99
31static __inline__ void atomic_sub(int i, atomic_t * v) 100static inline void atomic_sub(int i, atomic_t *v)
32{ 101{
33 long flags; 102 long flags;
34 103
@@ -38,7 +107,7 @@ static __inline__ void atomic_sub(int i, atomic_t * v)
38 107
39} 108}
40 109
41static inline int atomic_add_return(int i, atomic_t * v) 110static inline int atomic_add_return(int i, atomic_t *v)
42{ 111{
43 int __temp = 0; 112 int __temp = 0;
44 long flags; 113 long flags;
@@ -52,8 +121,7 @@ static inline int atomic_add_return(int i, atomic_t * v)
52 return __temp; 121 return __temp;
53} 122}
54 123
55#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) 124static inline int atomic_sub_return(int i, atomic_t *v)
56static inline int atomic_sub_return(int i, atomic_t * v)
57{ 125{
58 int __temp = 0; 126 int __temp = 0;
59 long flags; 127 long flags;
@@ -66,7 +134,7 @@ static inline int atomic_sub_return(int i, atomic_t * v)
66 return __temp; 134 return __temp;
67} 135}
68 136
69static __inline__ void atomic_inc(volatile atomic_t * v) 137static inline void atomic_inc(volatile atomic_t *v)
70{ 138{
71 long flags; 139 long flags;
72 140
@@ -75,20 +143,7 @@ static __inline__ void atomic_inc(volatile atomic_t * v)
75 local_irq_restore(flags); 143 local_irq_restore(flags);
76} 144}
77 145
78#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n))) 146static inline void atomic_dec(volatile atomic_t *v)
79#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
80
81#define atomic_add_unless(v, a, u) \
82({ \
83 int c, old; \
84 c = atomic_read(v); \
85 while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
86 c = old; \
87 c != (u); \
88})
89#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
90
91static __inline__ void atomic_dec(volatile atomic_t * v)
92{ 147{
93 long flags; 148 long flags;
94 149
@@ -97,7 +152,7 @@ static __inline__ void atomic_dec(volatile atomic_t * v)
97 local_irq_restore(flags); 152 local_irq_restore(flags);
98} 153}
99 154
100static __inline__ void atomic_clear_mask(unsigned int mask, atomic_t * v) 155static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
101{ 156{
102 long flags; 157 long flags;
103 158
@@ -106,7 +161,7 @@ static __inline__ void atomic_clear_mask(unsigned int mask, atomic_t * v)
106 local_irq_restore(flags); 161 local_irq_restore(flags);
107} 162}
108 163
109static __inline__ void atomic_set_mask(unsigned int mask, atomic_t * v) 164static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
110{ 165{
111 long flags; 166 long flags;
112 167
@@ -121,9 +176,25 @@ static __inline__ void atomic_set_mask(unsigned int mask, atomic_t * v)
121#define smp_mb__before_atomic_inc() barrier() 176#define smp_mb__before_atomic_inc() barrier()
122#define smp_mb__after_atomic_inc() barrier() 177#define smp_mb__after_atomic_inc() barrier()
123 178
179#endif /* !CONFIG_SMP */
180
181#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0)
124#define atomic_dec_return(v) atomic_sub_return(1,(v)) 182#define atomic_dec_return(v) atomic_sub_return(1,(v))
125#define atomic_inc_return(v) atomic_add_return(1,(v)) 183#define atomic_inc_return(v) atomic_add_return(1,(v))
126 184
185#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
186#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
187
188#define atomic_add_unless(v, a, u) \
189({ \
190 int c, old; \
191 c = atomic_read(v); \
192 while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
193 c = old; \
194 c != (u); \
195})
196#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
197
127/* 198/*
128 * atomic_inc_and_test - increment and test 199 * atomic_inc_and_test - increment and test
129 * @v: pointer of type atomic_t 200 * @v: pointer of type atomic_t
diff --git a/arch/blackfin/include/asm/bfin-global.h b/arch/blackfin/include/asm/bfin-global.h
index 77295666c34b..1dd08058bc90 100644
--- a/arch/blackfin/include/asm/bfin-global.h
+++ b/arch/blackfin/include/asm/bfin-global.h
@@ -47,6 +47,9 @@
47# define DMA_UNCACHED_REGION (0) 47# define DMA_UNCACHED_REGION (0)
48#endif 48#endif
49 49
50extern void bfin_setup_caches(unsigned int cpu);
51extern void bfin_setup_cpudata(unsigned int cpu);
52
50extern unsigned long get_cclk(void); 53extern unsigned long get_cclk(void);
51extern unsigned long get_sclk(void); 54extern unsigned long get_sclk(void);
52extern unsigned long sclk_to_usecs(unsigned long sclk); 55extern unsigned long sclk_to_usecs(unsigned long sclk);
@@ -58,8 +61,6 @@ extern void dump_bfin_trace_buffer(void);
58 61
59/* init functions only */ 62/* init functions only */
60extern int init_arch_irq(void); 63extern int init_arch_irq(void);
61extern void bfin_icache_init(void);
62extern void bfin_dcache_init(void);
63extern void init_exception_vectors(void); 64extern void init_exception_vectors(void);
64extern void program_IAR(void); 65extern void program_IAR(void);
65 66
diff --git a/arch/blackfin/include/asm/bitops.h b/arch/blackfin/include/asm/bitops.h
index c428e4106f89..9964e17232e9 100644
--- a/arch/blackfin/include/asm/bitops.h
+++ b/arch/blackfin/include/asm/bitops.h
@@ -7,7 +7,6 @@
7 7
8#include <linux/compiler.h> 8#include <linux/compiler.h>
9#include <asm/byteorder.h> /* swab32 */ 9#include <asm/byteorder.h> /* swab32 */
10#include <asm/system.h> /* save_flags */
11 10
12#ifdef __KERNEL__ 11#ifdef __KERNEL__
13 12
@@ -20,36 +19,71 @@
20#include <asm-generic/bitops/sched.h> 19#include <asm-generic/bitops/sched.h>
21#include <asm-generic/bitops/ffz.h> 20#include <asm-generic/bitops/ffz.h>
22 21
23static __inline__ void set_bit(int nr, volatile unsigned long *addr) 22#ifdef CONFIG_SMP
23
24#include <linux/linkage.h>
25
26asmlinkage int __raw_bit_set_asm(volatile unsigned long *addr, int nr);
27
28asmlinkage int __raw_bit_clear_asm(volatile unsigned long *addr, int nr);
29
30asmlinkage int __raw_bit_toggle_asm(volatile unsigned long *addr, int nr);
31
32asmlinkage int __raw_bit_test_set_asm(volatile unsigned long *addr, int nr);
33
34asmlinkage int __raw_bit_test_clear_asm(volatile unsigned long *addr, int nr);
35
36asmlinkage int __raw_bit_test_toggle_asm(volatile unsigned long *addr, int nr);
37
38asmlinkage int __raw_bit_test_asm(const volatile unsigned long *addr, int nr);
39
40static inline void set_bit(int nr, volatile unsigned long *addr)
24{ 41{
25 int *a = (int *)addr; 42 volatile unsigned long *a = addr + (nr >> 5);
26 int mask; 43 __raw_bit_set_asm(a, nr & 0x1f);
27 unsigned long flags; 44}
28 45
29 a += nr >> 5; 46static inline void clear_bit(int nr, volatile unsigned long *addr)
30 mask = 1 << (nr & 0x1f); 47{
31 local_irq_save(flags); 48 volatile unsigned long *a = addr + (nr >> 5);
32 *a |= mask; 49 __raw_bit_clear_asm(a, nr & 0x1f);
33 local_irq_restore(flags);
34} 50}
35 51
36static __inline__ void __set_bit(int nr, volatile unsigned long *addr) 52static inline void change_bit(int nr, volatile unsigned long *addr)
37{ 53{
38 int *a = (int *)addr; 54 volatile unsigned long *a = addr + (nr >> 5);
39 int mask; 55 __raw_bit_toggle_asm(a, nr & 0x1f);
56}
40 57
41 a += nr >> 5; 58static inline int test_bit(int nr, const volatile unsigned long *addr)
42 mask = 1 << (nr & 0x1f); 59{
43 *a |= mask; 60 volatile const unsigned long *a = addr + (nr >> 5);
61 return __raw_bit_test_asm(a, nr & 0x1f) != 0;
44} 62}
45 63
46/* 64static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
47 * clear_bit() doesn't provide any barrier for the compiler. 65{
48 */ 66 volatile unsigned long *a = addr + (nr >> 5);
49#define smp_mb__before_clear_bit() barrier() 67 return __raw_bit_test_set_asm(a, nr & 0x1f);
50#define smp_mb__after_clear_bit() barrier() 68}
51 69
52static __inline__ void clear_bit(int nr, volatile unsigned long *addr) 70static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
71{
72 volatile unsigned long *a = addr + (nr >> 5);
73 return __raw_bit_test_clear_asm(a, nr & 0x1f);
74}
75
76static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
77{
78 volatile unsigned long *a = addr + (nr >> 5);
79 return __raw_bit_test_toggle_asm(a, nr & 0x1f);
80}
81
82#else /* !CONFIG_SMP */
83
84#include <asm/system.h> /* save_flags */
85
86static inline void set_bit(int nr, volatile unsigned long *addr)
53{ 87{
54 int *a = (int *)addr; 88 int *a = (int *)addr;
55 int mask; 89 int mask;
@@ -57,21 +91,23 @@ static __inline__ void clear_bit(int nr, volatile unsigned long *addr)
57 a += nr >> 5; 91 a += nr >> 5;
58 mask = 1 << (nr & 0x1f); 92 mask = 1 << (nr & 0x1f);
59 local_irq_save(flags); 93 local_irq_save(flags);
60 *a &= ~mask; 94 *a |= mask;
61 local_irq_restore(flags); 95 local_irq_restore(flags);
62} 96}
63 97
64static __inline__ void __clear_bit(int nr, volatile unsigned long *addr) 98static inline void clear_bit(int nr, volatile unsigned long *addr)
65{ 99{
66 int *a = (int *)addr; 100 int *a = (int *)addr;
67 int mask; 101 int mask;
68 102 unsigned long flags;
69 a += nr >> 5; 103 a += nr >> 5;
70 mask = 1 << (nr & 0x1f); 104 mask = 1 << (nr & 0x1f);
105 local_irq_save(flags);
71 *a &= ~mask; 106 *a &= ~mask;
107 local_irq_restore(flags);
72} 108}
73 109
74static __inline__ void change_bit(int nr, volatile unsigned long *addr) 110static inline void change_bit(int nr, volatile unsigned long *addr)
75{ 111{
76 int mask, flags; 112 int mask, flags;
77 unsigned long *ADDR = (unsigned long *)addr; 113 unsigned long *ADDR = (unsigned long *)addr;
@@ -83,17 +119,7 @@ static __inline__ void change_bit(int nr, volatile unsigned long *addr)
83 local_irq_restore(flags); 119 local_irq_restore(flags);
84} 120}
85 121
86static __inline__ void __change_bit(int nr, volatile unsigned long *addr) 122static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
87{
88 int mask;
89 unsigned long *ADDR = (unsigned long *)addr;
90
91 ADDR += nr >> 5;
92 mask = 1 << (nr & 31);
93 *ADDR ^= mask;
94}
95
96static __inline__ int test_and_set_bit(int nr, void *addr)
97{ 123{
98 int mask, retval; 124 int mask, retval;
99 volatile unsigned int *a = (volatile unsigned int *)addr; 125 volatile unsigned int *a = (volatile unsigned int *)addr;
@@ -109,19 +135,23 @@ static __inline__ int test_and_set_bit(int nr, void *addr)
109 return retval; 135 return retval;
110} 136}
111 137
112static __inline__ int __test_and_set_bit(int nr, volatile unsigned long *addr) 138static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
113{ 139{
114 int mask, retval; 140 int mask, retval;
115 volatile unsigned int *a = (volatile unsigned int *)addr; 141 volatile unsigned int *a = (volatile unsigned int *)addr;
142 unsigned long flags;
116 143
117 a += nr >> 5; 144 a += nr >> 5;
118 mask = 1 << (nr & 0x1f); 145 mask = 1 << (nr & 0x1f);
146 local_irq_save(flags);
119 retval = (mask & *a) != 0; 147 retval = (mask & *a) != 0;
120 *a |= mask; 148 *a &= ~mask;
149 local_irq_restore(flags);
150
121 return retval; 151 return retval;
122} 152}
123 153
124static __inline__ int test_and_clear_bit(int nr, volatile unsigned long *addr) 154static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
125{ 155{
126 int mask, retval; 156 int mask, retval;
127 volatile unsigned int *a = (volatile unsigned int *)addr; 157 volatile unsigned int *a = (volatile unsigned int *)addr;
@@ -131,13 +161,50 @@ static __inline__ int test_and_clear_bit(int nr, volatile unsigned long *addr)
131 mask = 1 << (nr & 0x1f); 161 mask = 1 << (nr & 0x1f);
132 local_irq_save(flags); 162 local_irq_save(flags);
133 retval = (mask & *a) != 0; 163 retval = (mask & *a) != 0;
134 *a &= ~mask; 164 *a ^= mask;
135 local_irq_restore(flags); 165 local_irq_restore(flags);
136
137 return retval; 166 return retval;
138} 167}
139 168
140static __inline__ int __test_and_clear_bit(int nr, volatile unsigned long *addr) 169#endif /* CONFIG_SMP */
170
171/*
172 * clear_bit() doesn't provide any barrier for the compiler.
173 */
174#define smp_mb__before_clear_bit() barrier()
175#define smp_mb__after_clear_bit() barrier()
176
177static inline void __set_bit(int nr, volatile unsigned long *addr)
178{
179 int *a = (int *)addr;
180 int mask;
181
182 a += nr >> 5;
183 mask = 1 << (nr & 0x1f);
184 *a |= mask;
185}
186
187static inline void __clear_bit(int nr, volatile unsigned long *addr)
188{
189 int *a = (int *)addr;
190 int mask;
191
192 a += nr >> 5;
193 mask = 1 << (nr & 0x1f);
194 *a &= ~mask;
195}
196
197static inline void __change_bit(int nr, volatile unsigned long *addr)
198{
199 int mask;
200 unsigned long *ADDR = (unsigned long *)addr;
201
202 ADDR += nr >> 5;
203 mask = 1 << (nr & 31);
204 *ADDR ^= mask;
205}
206
207static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
141{ 208{
142 int mask, retval; 209 int mask, retval;
143 volatile unsigned int *a = (volatile unsigned int *)addr; 210 volatile unsigned int *a = (volatile unsigned int *)addr;
@@ -145,26 +212,23 @@ static __inline__ int __test_and_clear_bit(int nr, volatile unsigned long *addr)
145 a += nr >> 5; 212 a += nr >> 5;
146 mask = 1 << (nr & 0x1f); 213 mask = 1 << (nr & 0x1f);
147 retval = (mask & *a) != 0; 214 retval = (mask & *a) != 0;
148 *a &= ~mask; 215 *a |= mask;
149 return retval; 216 return retval;
150} 217}
151 218
152static __inline__ int test_and_change_bit(int nr, volatile unsigned long *addr) 219static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
153{ 220{
154 int mask, retval; 221 int mask, retval;
155 volatile unsigned int *a = (volatile unsigned int *)addr; 222 volatile unsigned int *a = (volatile unsigned int *)addr;
156 unsigned long flags;
157 223
158 a += nr >> 5; 224 a += nr >> 5;
159 mask = 1 << (nr & 0x1f); 225 mask = 1 << (nr & 0x1f);
160 local_irq_save(flags);
161 retval = (mask & *a) != 0; 226 retval = (mask & *a) != 0;
162 *a ^= mask; 227 *a &= ~mask;
163 local_irq_restore(flags);
164 return retval; 228 return retval;
165} 229}
166 230
167static __inline__ int __test_and_change_bit(int nr, 231static inline int __test_and_change_bit(int nr,
168 volatile unsigned long *addr) 232 volatile unsigned long *addr)
169{ 233{
170 int mask, retval; 234 int mask, retval;
@@ -177,16 +241,7 @@ static __inline__ int __test_and_change_bit(int nr,
177 return retval; 241 return retval;
178} 242}
179 243
180/* 244static inline int __test_bit(int nr, const void *addr)
181 * This routine doesn't need to be atomic.
182 */
183static __inline__ int __constant_test_bit(int nr, const void *addr)
184{
185 return ((1UL << (nr & 31)) &
186 (((const volatile unsigned int *)addr)[nr >> 5])) != 0;
187}
188
189static __inline__ int __test_bit(int nr, const void *addr)
190{ 245{
191 int *a = (int *)addr; 246 int *a = (int *)addr;
192 int mask; 247 int mask;
@@ -196,10 +251,16 @@ static __inline__ int __test_bit(int nr, const void *addr)
196 return ((mask & *a) != 0); 251 return ((mask & *a) != 0);
197} 252}
198 253
199#define test_bit(nr,addr) \ 254#ifndef CONFIG_SMP
200(__builtin_constant_p(nr) ? \ 255/*
201 __constant_test_bit((nr),(addr)) : \ 256 * This routine doesn't need irq save and restore ops in UP
202 __test_bit((nr),(addr))) 257 * context.
258 */
259static inline int test_bit(int nr, const void *addr)
260{
261 return __test_bit(nr, addr);
262}
263#endif
203 264
204#include <asm-generic/bitops/find.h> 265#include <asm-generic/bitops/find.h>
205#include <asm-generic/bitops/hweight.h> 266#include <asm-generic/bitops/hweight.h>
diff --git a/arch/blackfin/include/asm/cache.h b/arch/blackfin/include/asm/cache.h
index 023d72133b5a..86637814cf25 100644
--- a/arch/blackfin/include/asm/cache.h
+++ b/arch/blackfin/include/asm/cache.h
@@ -12,6 +12,11 @@
12#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) 12#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
13#define SMP_CACHE_BYTES L1_CACHE_BYTES 13#define SMP_CACHE_BYTES L1_CACHE_BYTES
14 14
15#ifdef CONFIG_SMP
16#define __cacheline_aligned
17#else
18#define ____cacheline_aligned
19
15/* 20/*
16 * Put cacheline_aliged data to L1 data memory 21 * Put cacheline_aliged data to L1 data memory
17 */ 22 */
@@ -21,9 +26,33 @@
21 __section__(".data_l1.cacheline_aligned"))) 26 __section__(".data_l1.cacheline_aligned")))
22#endif 27#endif
23 28
29#endif
30
24/* 31/*
25 * largest L1 which this arch supports 32 * largest L1 which this arch supports
26 */ 33 */
27#define L1_CACHE_SHIFT_MAX 5 34#define L1_CACHE_SHIFT_MAX 5
28 35
36#if defined(CONFIG_SMP) && \
37 !defined(CONFIG_BFIN_CACHE_COHERENT) && \
38 defined(CONFIG_BFIN_DCACHE)
39#define __ARCH_SYNC_CORE_DCACHE
40#ifndef __ASSEMBLY__
41asmlinkage void __raw_smp_mark_barrier_asm(void);
42asmlinkage void __raw_smp_check_barrier_asm(void);
43
44static inline void smp_mark_barrier(void)
45{
46 __raw_smp_mark_barrier_asm();
47}
48static inline void smp_check_barrier(void)
49{
50 __raw_smp_check_barrier_asm();
51}
52
53void resync_core_dcache(void);
54#endif
55#endif
56
57
29#endif 58#endif
diff --git a/arch/blackfin/include/asm/cacheflush.h b/arch/blackfin/include/asm/cacheflush.h
index 4403415583fa..1b040f5b4feb 100644
--- a/arch/blackfin/include/asm/cacheflush.h
+++ b/arch/blackfin/include/asm/cacheflush.h
@@ -35,6 +35,7 @@ extern void blackfin_icache_flush_range(unsigned long start_address, unsigned lo
35extern void blackfin_dcache_flush_range(unsigned long start_address, unsigned long end_address); 35extern void blackfin_dcache_flush_range(unsigned long start_address, unsigned long end_address);
36extern void blackfin_dcache_invalidate_range(unsigned long start_address, unsigned long end_address); 36extern void blackfin_dcache_invalidate_range(unsigned long start_address, unsigned long end_address);
37extern void blackfin_dflush_page(void *page); 37extern void blackfin_dflush_page(void *page);
38extern void blackfin_invalidate_entire_dcache(void);
38 39
39#define flush_dcache_mmap_lock(mapping) do { } while (0) 40#define flush_dcache_mmap_lock(mapping) do { } while (0)
40#define flush_dcache_mmap_unlock(mapping) do { } while (0) 41#define flush_dcache_mmap_unlock(mapping) do { } while (0)
@@ -44,12 +45,20 @@ extern void blackfin_dflush_page(void *page);
44#define flush_cache_vmap(start, end) do { } while (0) 45#define flush_cache_vmap(start, end) do { } while (0)
45#define flush_cache_vunmap(start, end) do { } while (0) 46#define flush_cache_vunmap(start, end) do { } while (0)
46 47
48#ifdef CONFIG_SMP
49#define flush_icache_range_others(start, end) \
50 smp_icache_flush_range_others((start), (end))
51#else
52#define flush_icache_range_others(start, end) do { } while (0)
53#endif
54
47static inline void flush_icache_range(unsigned start, unsigned end) 55static inline void flush_icache_range(unsigned start, unsigned end)
48{ 56{
49#if defined(CONFIG_BFIN_DCACHE) && defined(CONFIG_BFIN_ICACHE) 57#if defined(CONFIG_BFIN_DCACHE) && defined(CONFIG_BFIN_ICACHE)
50 58
51# if defined(CONFIG_BFIN_WT) 59# if defined(CONFIG_BFIN_WT)
52 blackfin_icache_flush_range((start), (end)); 60 blackfin_icache_flush_range((start), (end));
61 flush_icache_range_others(start, end);
53# else 62# else
54 blackfin_icache_dcache_flush_range((start), (end)); 63 blackfin_icache_dcache_flush_range((start), (end));
55# endif 64# endif
@@ -58,6 +67,7 @@ static inline void flush_icache_range(unsigned start, unsigned end)
58 67
59# if defined(CONFIG_BFIN_ICACHE) 68# if defined(CONFIG_BFIN_ICACHE)
60 blackfin_icache_flush_range((start), (end)); 69 blackfin_icache_flush_range((start), (end));
70 flush_icache_range_others(start, end);
61# endif 71# endif
62# if defined(CONFIG_BFIN_DCACHE) 72# if defined(CONFIG_BFIN_DCACHE)
63 blackfin_dcache_flush_range((start), (end)); 73 blackfin_dcache_flush_range((start), (end));
@@ -66,10 +76,12 @@ static inline void flush_icache_range(unsigned start, unsigned end)
66#endif 76#endif
67} 77}
68 78
69#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ 79#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
70do { memcpy(dst, src, len); \ 80do { memcpy(dst, src, len); \
71 flush_icache_range ((unsigned) (dst), (unsigned) (dst) + (len)); \ 81 flush_icache_range((unsigned) (dst), (unsigned) (dst) + (len)); \
82 flush_icache_range_others((unsigned long) (dst), (unsigned long) (dst) + (len));\
72} while (0) 83} while (0)
84
73#define copy_from_user_page(vma, page, vaddr, dst, src, len) memcpy(dst, src, len) 85#define copy_from_user_page(vma, page, vaddr, dst, src, len) memcpy(dst, src, len)
74 86
75#if defined(CONFIG_BFIN_DCACHE) 87#if defined(CONFIG_BFIN_DCACHE)
@@ -82,7 +94,7 @@ do { memcpy(dst, src, len); \
82# define flush_dcache_page(page) blackfin_dflush_page(page_address(page)) 94# define flush_dcache_page(page) blackfin_dflush_page(page_address(page))
83#else 95#else
84# define flush_dcache_range(start,end) do { } while (0) 96# define flush_dcache_range(start,end) do { } while (0)
85# define flush_dcache_page(page) do { } while (0) 97# define flush_dcache_page(page) do { } while (0)
86#endif 98#endif
87 99
88extern unsigned long reserved_mem_dcache_on; 100extern unsigned long reserved_mem_dcache_on;
diff --git a/arch/blackfin/include/asm/context.S b/arch/blackfin/include/asm/context.S
index c0e630edfb9a..40d20b4a9b1f 100644
--- a/arch/blackfin/include/asm/context.S
+++ b/arch/blackfin/include/asm/context.S
@@ -303,9 +303,14 @@
303 RETI = [sp++]; 303 RETI = [sp++];
304 RETS = [sp++]; 304 RETS = [sp++];
305 305
306#ifdef CONFIG_SMP
307 GET_PDA(p0, r0);
308 r0 = [p0 + PDA_IRQFLAGS];
309#else
306 p0.h = _irq_flags; 310 p0.h = _irq_flags;
307 p0.l = _irq_flags; 311 p0.l = _irq_flags;
308 r0 = [p0]; 312 r0 = [p0];
313#endif
309 sti r0; 314 sti r0;
310 315
311 sp += 4; /* Skip Reserved */ 316 sp += 4; /* Skip Reserved */
@@ -352,4 +357,3 @@
352 SYSCFG = [sp++]; 357 SYSCFG = [sp++];
353 csync; 358 csync;
354.endm 359.endm
355
diff --git a/arch/blackfin/include/asm/cpu.h b/arch/blackfin/include/asm/cpu.h
new file mode 100644
index 000000000000..9b7aefe7eb2d
--- /dev/null
+++ b/arch/blackfin/include/asm/cpu.h
@@ -0,0 +1,42 @@
1/*
2 * File: arch/blackfin/include/asm/cpu.h.
3 * Author: Philippe Gerum <rpm@xenomai.org>
4 *
5 * Copyright 2007 Analog Devices Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see the file COPYING, or write
19 * to the Free Software Foundation, Inc.,
20 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#ifndef __ASM_BLACKFIN_CPU_H
24#define __ASM_BLACKFIN_CPU_H
25
26#include <linux/percpu.h>
27
28struct task_struct;
29
30struct blackfin_cpudata {
31 struct cpu cpu;
32 struct task_struct *idle;
33 unsigned long cclk;
34 unsigned int imemctl;
35 unsigned int dmemctl;
36 unsigned long loops_per_jiffy;
37 unsigned long dcache_invld_count;
38};
39
40DECLARE_PER_CPU(struct blackfin_cpudata, cpu_data);
41
42#endif
diff --git a/arch/blackfin/include/asm/l1layout.h b/arch/blackfin/include/asm/l1layout.h
index c13ded777828..06bb37f6c788 100644
--- a/arch/blackfin/include/asm/l1layout.h
+++ b/arch/blackfin/include/asm/l1layout.h
@@ -24,7 +24,8 @@ struct l1_scratch_task_info
24}; 24};
25 25
26/* A pointer to the structure in memory. */ 26/* A pointer to the structure in memory. */
27#define L1_SCRATCH_TASK_INFO ((struct l1_scratch_task_info *)L1_SCRATCH_START) 27#define L1_SCRATCH_TASK_INFO ((struct l1_scratch_task_info *)\
28 get_l1_scratch_start())
28 29
29#endif 30#endif
30 31
diff --git a/arch/blackfin/include/asm/mutex-dec.h b/arch/blackfin/include/asm/mutex-dec.h
new file mode 100644
index 000000000000..0134151656af
--- /dev/null
+++ b/arch/blackfin/include/asm/mutex-dec.h
@@ -0,0 +1,112 @@
1/*
2 * include/asm-generic/mutex-dec.h
3 *
4 * Generic implementation of the mutex fastpath, based on atomic
5 * decrement/increment.
6 */
7#ifndef _ASM_GENERIC_MUTEX_DEC_H
8#define _ASM_GENERIC_MUTEX_DEC_H
9
10/**
11 * __mutex_fastpath_lock - try to take the lock by moving the count
12 * from 1 to a 0 value
13 * @count: pointer of type atomic_t
14 * @fail_fn: function to call if the original value was not 1
15 *
16 * Change the count from 1 to a value lower than 1, and call <fail_fn> if
17 * it wasn't 1 originally. This function MUST leave the value lower than
18 * 1 even when the "1" assertion wasn't true.
19 */
20static inline void
21__mutex_fastpath_lock(atomic_t *count, fastcall void (*fail_fn)(atomic_t *))
22{
23 if (unlikely(atomic_dec_return(count) < 0))
24 fail_fn(count);
25 else
26 smp_mb();
27}
28
29/**
30 * __mutex_fastpath_lock_retval - try to take the lock by moving the count
31 * from 1 to a 0 value
32 * @count: pointer of type atomic_t
33 * @fail_fn: function to call if the original value was not 1
34 *
35 * Change the count from 1 to a value lower than 1, and call <fail_fn> if
36 * it wasn't 1 originally. This function returns 0 if the fastpath succeeds,
37 * or anything the slow path function returns.
38 */
39static inline int
40__mutex_fastpath_lock_retval(atomic_t *count, fastcall int (*fail_fn)(atomic_t *))
41{
42 if (unlikely(atomic_dec_return(count) < 0))
43 return fail_fn(count);
44 else {
45 smp_mb();
46 return 0;
47 }
48}
49
50/**
51 * __mutex_fastpath_unlock - try to promote the count from 0 to 1
52 * @count: pointer of type atomic_t
53 * @fail_fn: function to call if the original value was not 0
54 *
55 * Try to promote the count from 0 to 1. If it wasn't 0, call <fail_fn>.
56 * In the failure case, this function is allowed to either set the value to
57 * 1, or to set it to a value lower than 1.
58 *
59 * If the implementation sets it to a value of lower than 1, then the
60 * __mutex_slowpath_needs_to_unlock() macro needs to return 1, it needs
61 * to return 0 otherwise.
62 */
63static inline void
64__mutex_fastpath_unlock(atomic_t *count, fastcall void (*fail_fn)(atomic_t *))
65{
66 smp_mb();
67 if (unlikely(atomic_inc_return(count) <= 0))
68 fail_fn(count);
69}
70
71#define __mutex_slowpath_needs_to_unlock() 1
72
73/**
74 * __mutex_fastpath_trylock - try to acquire the mutex, without waiting
75 *
76 * @count: pointer of type atomic_t
77 * @fail_fn: fallback function
78 *
79 * Change the count from 1 to a value lower than 1, and return 0 (failure)
80 * if it wasn't 1 originally, or return 1 (success) otherwise. This function
81 * MUST leave the value lower than 1 even when the "1" assertion wasn't true.
82 * Additionally, if the value was < 0 originally, this function must not leave
83 * it to 0 on failure.
84 *
85 * If the architecture has no effective trylock variant, it should call the
86 * <fail_fn> spinlock-based trylock variant unconditionally.
87 */
88static inline int
89__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *))
90{
91 /*
92 * We have two variants here. The cmpxchg based one is the best one
93 * because it never induce a false contention state. It is included
94 * here because architectures using the inc/dec algorithms over the
95 * xchg ones are much more likely to support cmpxchg natively.
96 *
97 * If not we fall back to the spinlock based variant - that is
98 * just as efficient (and simpler) as a 'destructive' probing of
99 * the mutex state would be.
100 */
101#ifdef __HAVE_ARCH_CMPXCHG
102 if (likely(atomic_cmpxchg(count, 1, 0) == 1)) {
103 smp_mb();
104 return 1;
105 }
106 return 0;
107#else
108 return fail_fn(count);
109#endif
110}
111
112#endif
diff --git a/arch/blackfin/include/asm/mutex.h b/arch/blackfin/include/asm/mutex.h
index 458c1f7fbc18..5d399256bf06 100644
--- a/arch/blackfin/include/asm/mutex.h
+++ b/arch/blackfin/include/asm/mutex.h
@@ -6,4 +6,67 @@
6 * implementation. (see asm-generic/mutex-xchg.h for details) 6 * implementation. (see asm-generic/mutex-xchg.h for details)
7 */ 7 */
8 8
9#ifndef _ASM_MUTEX_H
10#define _ASM_MUTEX_H
11
12#ifndef CONFIG_SMP
9#include <asm-generic/mutex-dec.h> 13#include <asm-generic/mutex-dec.h>
14#else
15
16static inline void
17__mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
18{
19 if (unlikely(atomic_dec_return(count) < 0))
20 fail_fn(count);
21 else
22 smp_mb();
23}
24
25static inline int
26__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
27{
28 if (unlikely(atomic_dec_return(count) < 0))
29 return fail_fn(count);
30 else {
31 smp_mb();
32 return 0;
33 }
34}
35
36static inline void
37__mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *))
38{
39 smp_mb();
40 if (unlikely(atomic_inc_return(count) <= 0))
41 fail_fn(count);
42}
43
44#define __mutex_slowpath_needs_to_unlock() 1
45
46static inline int
47__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *))
48{
49 /*
50 * We have two variants here. The cmpxchg based one is the best one
51 * because it never induce a false contention state. It is included
52 * here because architectures using the inc/dec algorithms over the
53 * xchg ones are much more likely to support cmpxchg natively.
54 *
55 * If not we fall back to the spinlock based variant - that is
56 * just as efficient (and simpler) as a 'destructive' probing of
57 * the mutex state would be.
58 */
59#ifdef __HAVE_ARCH_CMPXCHG
60 if (likely(atomic_cmpxchg(count, 1, 0) == 1)) {
61 smp_mb();
62 return 1;
63 }
64 return 0;
65#else
66 return fail_fn(count);
67#endif
68}
69
70#endif
71
72#endif
diff --git a/arch/blackfin/include/asm/pda.h b/arch/blackfin/include/asm/pda.h
new file mode 100644
index 000000000000..a24d130c30f0
--- /dev/null
+++ b/arch/blackfin/include/asm/pda.h
@@ -0,0 +1,70 @@
1/*
2 * File: arch/blackfin/include/asm/pda.h
3 * Author: Philippe Gerum <rpm@xenomai.org>
4 *
5 * Copyright 2007 Analog Devices Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see the file COPYING, or write
19 * to the Free Software Foundation, Inc.,
20 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#ifndef _ASM_BLACKFIN_PDA_H
24#define _ASM_BLACKFIN_PDA_H
25
26#include <asm/mem_map.h>
27
28#ifndef __ASSEMBLY__
29
30struct blackfin_pda { /* Per-processor Data Area */
31 struct blackfin_pda *next;
32
33 unsigned long syscfg;
34#ifdef CONFIG_SMP
35 unsigned long imask; /* Current IMASK value */
36#endif
37
38 unsigned long *ipdt; /* Start of switchable I-CPLB table */
39 unsigned long *ipdt_swapcount; /* Number of swaps in ipdt */
40 unsigned long *dpdt; /* Start of switchable D-CPLB table */
41 unsigned long *dpdt_swapcount; /* Number of swaps in dpdt */
42
43 /*
44 * Single instructions can have multiple faults, which
45 * need to be handled by traps.c, in irq5. We store
46 * the exception cause to ensure we don't miss a
47 * double fault condition
48 */
49 unsigned long ex_iptr;
50 unsigned long ex_optr;
51 unsigned long ex_buf[4];
52 unsigned long ex_imask; /* Saved imask from exception */
53 unsigned long *ex_stack; /* Exception stack space */
54
55#ifdef ANOMALY_05000261
56 unsigned long last_cplb_fault_retx;
57#endif
58 unsigned long dcplb_fault_addr;
59 unsigned long icplb_fault_addr;
60 unsigned long retx;
61 unsigned long seqstat;
62};
63
64extern struct blackfin_pda cpu_pda[];
65
66void reserve_pda(void);
67
68#endif /* __ASSEMBLY__ */
69
70#endif /* _ASM_BLACKFIN_PDA_H */
diff --git a/arch/blackfin/include/asm/percpu.h b/arch/blackfin/include/asm/percpu.h
index 78dd61f6b39f..797c0c165069 100644
--- a/arch/blackfin/include/asm/percpu.h
+++ b/arch/blackfin/include/asm/percpu.h
@@ -3,4 +3,14 @@
3 3
4#include <asm-generic/percpu.h> 4#include <asm-generic/percpu.h>
5 5
6#endif /* __ARCH_BLACKFIN_PERCPU__ */ 6#ifdef CONFIG_MODULES
7#define PERCPU_MODULE_RESERVE 8192
8#else
9#define PERCPU_MODULE_RESERVE 0
10#endif
11
12#define PERCPU_ENOUGH_ROOM \
13 (ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES) + \
14 PERCPU_MODULE_RESERVE)
15
16#endif /* __ARCH_BLACKFIN_PERCPU__ */
diff --git a/arch/blackfin/include/asm/processor.h b/arch/blackfin/include/asm/processor.h
index e3e9b41fa8db..30703c75030c 100644
--- a/arch/blackfin/include/asm/processor.h
+++ b/arch/blackfin/include/asm/processor.h
@@ -106,7 +106,8 @@ unsigned long get_wchan(struct task_struct *p);
106 eip; }) 106 eip; })
107#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp) 107#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp)
108 108
109#define cpu_relax() barrier() 109#define cpu_relax() smp_mb()
110
110 111
111/* Get the Silicon Revision of the chip */ 112/* Get the Silicon Revision of the chip */
112static inline uint32_t __pure bfin_revid(void) 113static inline uint32_t __pure bfin_revid(void)
@@ -137,7 +138,11 @@ static inline uint32_t __pure bfin_revid(void)
137static inline uint16_t __pure bfin_cpuid(void) 138static inline uint16_t __pure bfin_cpuid(void)
138{ 139{
139 return (bfin_read_CHIPID() & CHIPID_FAMILY) >> 12; 140 return (bfin_read_CHIPID() & CHIPID_FAMILY) >> 12;
141}
140 142
143static inline uint32_t __pure bfin_dspid(void)
144{
145 return bfin_read_DSPID();
141} 146}
142 147
143static inline uint32_t __pure bfin_compiled_revid(void) 148static inline uint32_t __pure bfin_compiled_revid(void)
diff --git a/arch/blackfin/include/asm/rwlock.h b/arch/blackfin/include/asm/rwlock.h
new file mode 100644
index 000000000000..4a724b378971
--- /dev/null
+++ b/arch/blackfin/include/asm/rwlock.h
@@ -0,0 +1,6 @@
1#ifndef _ASM_BLACKFIN_RWLOCK_H
2#define _ASM_BLACKFIN_RWLOCK_H
3
4#define RW_LOCK_BIAS 0x01000000
5
6#endif
diff --git a/arch/blackfin/include/asm/smp.h b/arch/blackfin/include/asm/smp.h
new file mode 100644
index 000000000000..233cb8c3cfb7
--- /dev/null
+++ b/arch/blackfin/include/asm/smp.h
@@ -0,0 +1,42 @@
1/*
2 * File: arch/blackfin/include/asm/smp.h
3 * Author: Philippe Gerum <rpm@xenomai.org>
4 *
5 * Copyright 2007 Analog Devices Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see the file COPYING, or write
19 * to the Free Software Foundation, Inc.,
20 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#ifndef __ASM_BLACKFIN_SMP_H
24#define __ASM_BLACKFIN_SMP_H
25
26#include <linux/kernel.h>
27#include <linux/threads.h>
28#include <linux/cpumask.h>
29#include <linux/cache.h>
30#include <asm/blackfin.h>
31#include <mach/smp.h>
32
33#define raw_smp_processor_id() blackfin_core_id()
34
35struct corelock_slot {
36 int lock;
37};
38
39void smp_icache_flush_range_others(unsigned long start,
40 unsigned long end);
41
42#endif /* !__ASM_BLACKFIN_SMP_H */
diff --git a/arch/blackfin/include/asm/spinlock.h b/arch/blackfin/include/asm/spinlock.h
index 64e908a50646..0249ac319476 100644
--- a/arch/blackfin/include/asm/spinlock.h
+++ b/arch/blackfin/include/asm/spinlock.h
@@ -1,6 +1,89 @@
1#ifndef __BFIN_SPINLOCK_H 1#ifndef __BFIN_SPINLOCK_H
2#define __BFIN_SPINLOCK_H 2#define __BFIN_SPINLOCK_H
3 3
4#error blackfin architecture does not support SMP spin lock yet 4#include <asm/atomic.h>
5 5
6#endif 6asmlinkage int __raw_spin_is_locked_asm(volatile int *ptr);
7asmlinkage void __raw_spin_lock_asm(volatile int *ptr);
8asmlinkage int __raw_spin_trylock_asm(volatile int *ptr);
9asmlinkage void __raw_spin_unlock_asm(volatile int *ptr);
10asmlinkage void __raw_read_lock_asm(volatile int *ptr);
11asmlinkage int __raw_read_trylock_asm(volatile int *ptr);
12asmlinkage void __raw_read_unlock_asm(volatile int *ptr);
13asmlinkage void __raw_write_lock_asm(volatile int *ptr);
14asmlinkage int __raw_write_trylock_asm(volatile int *ptr);
15asmlinkage void __raw_write_unlock_asm(volatile int *ptr);
16
17static inline int __raw_spin_is_locked(raw_spinlock_t *lock)
18{
19 return __raw_spin_is_locked_asm(&lock->lock);
20}
21
22static inline void __raw_spin_lock(raw_spinlock_t *lock)
23{
24 __raw_spin_lock_asm(&lock->lock);
25}
26
27#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
28
29static inline int __raw_spin_trylock(raw_spinlock_t *lock)
30{
31 return __raw_spin_trylock_asm(&lock->lock);
32}
33
34static inline void __raw_spin_unlock(raw_spinlock_t *lock)
35{
36 __raw_spin_unlock_asm(&lock->lock);
37}
38
39static inline void __raw_spin_unlock_wait(raw_spinlock_t *lock)
40{
41 while (__raw_spin_is_locked(lock))
42 cpu_relax();
43}
44
45static inline int __raw_read_can_lock(raw_rwlock_t *rw)
46{
47 return __raw_uncached_fetch_asm(&rw->lock) > 0;
48}
49
50static inline int __raw_write_can_lock(raw_rwlock_t *rw)
51{
52 return __raw_uncached_fetch_asm(&rw->lock) == RW_LOCK_BIAS;
53}
54
55static inline void __raw_read_lock(raw_rwlock_t *rw)
56{
57 __raw_read_lock_asm(&rw->lock);
58}
59
60static inline int __raw_read_trylock(raw_rwlock_t *rw)
61{
62 return __raw_read_trylock_asm(&rw->lock);
63}
64
65static inline void __raw_read_unlock(raw_rwlock_t *rw)
66{
67 __raw_read_unlock_asm(&rw->lock);
68}
69
70static inline void __raw_write_lock(raw_rwlock_t *rw)
71{
72 __raw_write_lock_asm(&rw->lock);
73}
74
75static inline int __raw_write_trylock(raw_rwlock_t *rw)
76{
77 return __raw_write_trylock_asm(&rw->lock);
78}
79
80static inline void __raw_write_unlock(raw_rwlock_t *rw)
81{
82 __raw_write_unlock_asm(&rw->lock);
83}
84
85#define _raw_spin_relax(lock) cpu_relax()
86#define _raw_read_relax(lock) cpu_relax()
87#define _raw_write_relax(lock) cpu_relax()
88
89#endif /* !__BFIN_SPINLOCK_H */
diff --git a/arch/blackfin/include/asm/spinlock_types.h b/arch/blackfin/include/asm/spinlock_types.h
new file mode 100644
index 000000000000..b1e3c4c7b382
--- /dev/null
+++ b/arch/blackfin/include/asm/spinlock_types.h
@@ -0,0 +1,22 @@
1#ifndef __ASM_SPINLOCK_TYPES_H
2#define __ASM_SPINLOCK_TYPES_H
3
4#ifndef __LINUX_SPINLOCK_TYPES_H
5# error "please don't include this file directly"
6#endif
7
8#include <asm/rwlock.h>
9
10typedef struct {
11 volatile unsigned int lock;
12} raw_spinlock_t;
13
14#define __RAW_SPIN_LOCK_UNLOCKED { 0 }
15
16typedef struct {
17 volatile unsigned int lock;
18} raw_rwlock_t;
19
20#define __RAW_RW_LOCK_UNLOCKED { RW_LOCK_BIAS }
21
22#endif
diff --git a/arch/blackfin/include/asm/system.h b/arch/blackfin/include/asm/system.h
index 8f1627d8bf09..6b368faf30c3 100644
--- a/arch/blackfin/include/asm/system.h
+++ b/arch/blackfin/include/asm/system.h
@@ -37,20 +37,16 @@
37#include <linux/linkage.h> 37#include <linux/linkage.h>
38#include <linux/compiler.h> 38#include <linux/compiler.h>
39#include <mach/anomaly.h> 39#include <mach/anomaly.h>
40#include <asm/pda.h>
41#include <asm/processor.h>
42
43/* Forward decl needed due to cdef inter dependencies */
44static inline uint32_t __pure bfin_dspid(void);
45#define blackfin_core_id() (bfin_dspid() & 0xff)
40 46
41/* 47/*
42 * Interrupt configuring macros. 48 * Interrupt configuring macros.
43 */ 49 */
44
45extern unsigned long irq_flags;
46
47#define local_irq_enable() \
48 __asm__ __volatile__( \
49 "sti %0;" \
50 : \
51 : "d" (irq_flags) \
52 )
53
54#define local_irq_disable() \ 50#define local_irq_disable() \
55 do { \ 51 do { \
56 int __tmp_dummy; \ 52 int __tmp_dummy; \
@@ -66,6 +62,18 @@ extern unsigned long irq_flags;
66# define NOP_PAD_ANOMALY_05000244 62# define NOP_PAD_ANOMALY_05000244
67#endif 63#endif
68 64
65#ifdef CONFIG_SMP
66# define irq_flags cpu_pda[blackfin_core_id()].imask
67#else
68extern unsigned long irq_flags;
69#endif
70
71#define local_irq_enable() \
72 __asm__ __volatile__( \
73 "sti %0;" \
74 : \
75 : "d" (irq_flags) \
76 )
69#define idle_with_irq_disabled() \ 77#define idle_with_irq_disabled() \
70 __asm__ __volatile__( \ 78 __asm__ __volatile__( \
71 NOP_PAD_ANOMALY_05000244 \ 79 NOP_PAD_ANOMALY_05000244 \
@@ -129,22 +137,85 @@ extern unsigned long irq_flags;
129#define rmb() asm volatile ("" : : :"memory") 137#define rmb() asm volatile ("" : : :"memory")
130#define wmb() asm volatile ("" : : :"memory") 138#define wmb() asm volatile ("" : : :"memory")
131#define set_mb(var, value) do { (void) xchg(&var, value); } while (0) 139#define set_mb(var, value) do { (void) xchg(&var, value); } while (0)
132
133#define read_barrier_depends() do { } while(0) 140#define read_barrier_depends() do { } while(0)
134 141
135#ifdef CONFIG_SMP 142#ifdef CONFIG_SMP
136#define smp_mb() mb() 143asmlinkage unsigned long __raw_xchg_1_asm(volatile void *ptr, unsigned long value);
137#define smp_rmb() rmb() 144asmlinkage unsigned long __raw_xchg_2_asm(volatile void *ptr, unsigned long value);
138#define smp_wmb() wmb() 145asmlinkage unsigned long __raw_xchg_4_asm(volatile void *ptr, unsigned long value);
139#define smp_read_barrier_depends() read_barrier_depends() 146asmlinkage unsigned long __raw_cmpxchg_1_asm(volatile void *ptr,
147 unsigned long new, unsigned long old);
148asmlinkage unsigned long __raw_cmpxchg_2_asm(volatile void *ptr,
149 unsigned long new, unsigned long old);
150asmlinkage unsigned long __raw_cmpxchg_4_asm(volatile void *ptr,
151 unsigned long new, unsigned long old);
152
153#ifdef __ARCH_SYNC_CORE_DCACHE
154# define smp_mb() do { barrier(); smp_check_barrier(); smp_mark_barrier(); } while (0)
155# define smp_rmb() do { barrier(); smp_check_barrier(); } while (0)
156# define smp_wmb() do { barrier(); smp_mark_barrier(); } while (0)
140#else 157#else
158# define smp_mb() barrier()
159# define smp_rmb() barrier()
160# define smp_wmb() barrier()
161#endif
162
163static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
164 int size)
165{
166 unsigned long tmp;
167
168 switch (size) {
169 case 1:
170 tmp = __raw_xchg_1_asm(ptr, x);
171 break;
172 case 2:
173 tmp = __raw_xchg_2_asm(ptr, x);
174 break;
175 case 4:
176 tmp = __raw_xchg_4_asm(ptr, x);
177 break;
178 }
179
180 return tmp;
181}
182
183/*
184 * Atomic compare and exchange. Compare OLD with MEM, if identical,
185 * store NEW in MEM. Return the initial value in MEM. Success is
186 * indicated by comparing RETURN with OLD.
187 */
188static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
189 unsigned long new, int size)
190{
191 unsigned long tmp;
192
193 switch (size) {
194 case 1:
195 tmp = __raw_cmpxchg_1_asm(ptr, new, old);
196 break;
197 case 2:
198 tmp = __raw_cmpxchg_2_asm(ptr, new, old);
199 break;
200 case 4:
201 tmp = __raw_cmpxchg_4_asm(ptr, new, old);
202 break;
203 }
204
205 return tmp;
206}
207#define cmpxchg(ptr, o, n) \
208 ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), \
209 (unsigned long)(n), sizeof(*(ptr))))
210
211#define smp_read_barrier_depends() smp_check_barrier()
212
213#else /* !CONFIG_SMP */
214
141#define smp_mb() barrier() 215#define smp_mb() barrier()
142#define smp_rmb() barrier() 216#define smp_rmb() barrier()
143#define smp_wmb() barrier() 217#define smp_wmb() barrier()
144#define smp_read_barrier_depends() do { } while(0) 218#define smp_read_barrier_depends() do { } while(0)
145#endif
146
147#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
148 219
149struct __xchg_dummy { 220struct __xchg_dummy {
150 unsigned long a[100]; 221 unsigned long a[100];
@@ -194,9 +265,12 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
194 (unsigned long)(n), sizeof(*(ptr)))) 265 (unsigned long)(n), sizeof(*(ptr))))
195#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n)) 266#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
196 267
197#ifndef CONFIG_SMP
198#include <asm-generic/cmpxchg.h> 268#include <asm-generic/cmpxchg.h>
199#endif 269
270#endif /* !CONFIG_SMP */
271
272#define xchg(ptr, x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
273#define tas(ptr) ((void)xchg((ptr), 1))
200 274
201#define prepare_to_switch() do { } while(0) 275#define prepare_to_switch() do { } while(0)
202 276
@@ -218,4 +292,4 @@ do { \
218 (last) = resume (prev, next); \ 292 (last) = resume (prev, next); \
219} while (0) 293} while (0)
220 294
221#endif /* _BLACKFIN_SYSTEM_H */ 295#endif /* _BLACKFIN_SYSTEM_H */
diff --git a/arch/blackfin/mach-common/Makefile b/arch/blackfin/mach-common/Makefile
index e6ed57c56d4b..9388b4ab7349 100644
--- a/arch/blackfin/mach-common/Makefile
+++ b/arch/blackfin/mach-common/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_BFIN_ICACHE_LOCK) += lock.o
10obj-$(CONFIG_PM) += pm.o dpmc_modes.o 10obj-$(CONFIG_PM) += pm.o dpmc_modes.o
11obj-$(CONFIG_CPU_FREQ) += cpufreq.o 11obj-$(CONFIG_CPU_FREQ) += cpufreq.o
12obj-$(CONFIG_CPU_VOLTAGE) += dpmc.o 12obj-$(CONFIG_CPU_VOLTAGE) += dpmc.o
13obj-$(CONFIG_SMP) += smp.o
diff --git a/arch/blackfin/mach-common/cache.S b/arch/blackfin/mach-common/cache.S
index 3c98dacbf289..118751287437 100644
--- a/arch/blackfin/mach-common/cache.S
+++ b/arch/blackfin/mach-common/cache.S
@@ -97,3 +97,39 @@ ENTRY(_blackfin_dflush_page)
97 P1 = 1 << (PAGE_SHIFT - L1_CACHE_SHIFT); 97 P1 = 1 << (PAGE_SHIFT - L1_CACHE_SHIFT);
98 jump .Ldfr; 98 jump .Ldfr;
99ENDPROC(_blackfin_dflush_page) 99ENDPROC(_blackfin_dflush_page)
100
101/* Invalidate the Entire Data cache by
102 * clearing DMC[1:0] bits
103 */
104ENTRY(_blackfin_invalidate_entire_dcache)
105 [--SP] = ( R7:5);
106
107 P0.L = LO(DMEM_CONTROL);
108 P0.H = HI(DMEM_CONTROL);
109 R7 = [P0];
110 R5 = R7; /* Save DMEM_CNTR */
111
112 /* Clear the DMC[1:0] bits, All valid bits in the data
113 * cache are set to the invalid state
114 */
115 BITCLR(R7,DMC0_P);
116 BITCLR(R7,DMC1_P);
117 CLI R6;
118 SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
119 .align 8;
120 [P0] = R7;
121 SSYNC;
122 STI R6;
123
124 /* Configures the data cache again */
125
126 CLI R6;
127 SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
128 .align 8;
129 [P0] = R5;
130 SSYNC;
131 STI R6;
132
133 ( R7:5) = [SP++];
134 RTS;
135ENDPROC(_blackfin_invalidate_entire_dcache)
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
index c6ae8442fc4e..5531f49c84e6 100644
--- a/arch/blackfin/mach-common/entry.S
+++ b/arch/blackfin/mach-common/entry.S
@@ -36,6 +36,7 @@
36#include <linux/init.h> 36#include <linux/init.h>
37#include <linux/linkage.h> 37#include <linux/linkage.h>
38#include <linux/unistd.h> 38#include <linux/unistd.h>
39#include <linux/threads.h>
39#include <asm/blackfin.h> 40#include <asm/blackfin.h>
40#include <asm/errno.h> 41#include <asm/errno.h>
41#include <asm/fixed_code.h> 42#include <asm/fixed_code.h>
@@ -75,11 +76,11 @@ ENTRY(_ex_workaround_261)
75 * handle it. 76 * handle it.
76 */ 77 */
77 P4 = R7; /* Store EXCAUSE */ 78 P4 = R7; /* Store EXCAUSE */
78 p5.l = _last_cplb_fault_retx; 79
79 p5.h = _last_cplb_fault_retx; 80 GET_PDA(p5, r7);
80 r7 = [p5]; 81 r7 = [p5 + PDA_LFRETX];
81 r6 = retx; 82 r6 = retx;
82 [p5] = r6; 83 [p5 + PDA_LFRETX] = r6;
83 cc = r6 == r7; 84 cc = r6 == r7;
84 if !cc jump _bfin_return_from_exception; 85 if !cc jump _bfin_return_from_exception;
85 /* fall through */ 86 /* fall through */
@@ -324,7 +325,9 @@ ENTRY(_ex_trap_c)
324 [p4] = p5; 325 [p4] = p5;
325 csync; 326 csync;
326 327
328 GET_PDA(p5, r6);
327#ifndef CONFIG_DEBUG_DOUBLEFAULT 329#ifndef CONFIG_DEBUG_DOUBLEFAULT
330
328 /* 331 /*
329 * Save these registers, as they are only valid in exception context 332 * Save these registers, as they are only valid in exception context
330 * (where we are now - as soon as we defer to IRQ5, they can change) 333 * (where we are now - as soon as we defer to IRQ5, they can change)
@@ -335,29 +338,25 @@ ENTRY(_ex_trap_c)
335 p4.l = lo(DCPLB_FAULT_ADDR); 338 p4.l = lo(DCPLB_FAULT_ADDR);
336 p4.h = hi(DCPLB_FAULT_ADDR); 339 p4.h = hi(DCPLB_FAULT_ADDR);
337 r7 = [p4]; 340 r7 = [p4];
338 p5.h = _saved_dcplb_fault_addr; 341 [p5 + PDA_DCPLB] = r7;
339 p5.l = _saved_dcplb_fault_addr;
340 [p5] = r7;
341 342
342 r7 = [p4 + (ICPLB_FAULT_ADDR - DCPLB_FAULT_ADDR)]; 343 p4.l = lo(ICPLB_FAULT_ADDR);
343 p5.h = _saved_icplb_fault_addr; 344 p4.h = hi(ICPLB_FAULT_ADDR);
344 p5.l = _saved_icplb_fault_addr; 345 r6 = [p4];
345 [p5] = r7; 346 [p5 + PDA_ICPLB] = r6;
346 347
347 r6 = retx; 348 r6 = retx;
348 p4.l = _saved_retx; 349 [p5 + PDA_RETX] = r6;
349 p4.h = _saved_retx;
350 [p4] = r6;
351#endif 350#endif
352 r6 = SYSCFG; 351 r6 = SYSCFG;
353 [p4 + 4] = r6; 352 [p5 + PDA_SYSCFG] = r6;
354 BITCLR(r6, 0); 353 BITCLR(r6, 0);
355 SYSCFG = r6; 354 SYSCFG = r6;
356 355
357 /* Disable all interrupts, but make sure level 5 is enabled so 356 /* Disable all interrupts, but make sure level 5 is enabled so
358 * we can switch to that level. Save the old mask. */ 357 * we can switch to that level. Save the old mask. */
359 cli r6; 358 cli r6;
360 [p4 + 8] = r6; 359 [p5 + PDA_EXIMASK] = r6;
361 360
362 p4.l = lo(SAFE_USER_INSTRUCTION); 361 p4.l = lo(SAFE_USER_INSTRUCTION);
363 p4.h = hi(SAFE_USER_INSTRUCTION); 362 p4.h = hi(SAFE_USER_INSTRUCTION);
@@ -424,17 +423,16 @@ ENDPROC(_double_fault)
424ENTRY(_exception_to_level5) 423ENTRY(_exception_to_level5)
425 SAVE_ALL_SYS 424 SAVE_ALL_SYS
426 425
427 p4.l = _saved_retx; 426 GET_PDA(p4, r7); /* Fetch current PDA */
428 p4.h = _saved_retx; 427 r6 = [p4 + PDA_RETX];
429 r6 = [p4];
430 [sp + PT_PC] = r6; 428 [sp + PT_PC] = r6;
431 429
432 r6 = [p4 + 4]; 430 r6 = [p4 + PDA_SYSCFG];
433 [sp + PT_SYSCFG] = r6; 431 [sp + PT_SYSCFG] = r6;
434 432
435 /* Restore interrupt mask. We haven't pushed RETI, so this 433 /* Restore interrupt mask. We haven't pushed RETI, so this
436 * doesn't enable interrupts until we return from this handler. */ 434 * doesn't enable interrupts until we return from this handler. */
437 r6 = [p4 + 8]; 435 r6 = [p4 + PDA_EXIMASK];
438 sti r6; 436 sti r6;
439 437
440 /* Restore the hardware error vector. */ 438 /* Restore the hardware error vector. */
@@ -478,8 +476,8 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/
478 * scratch register (for want of a better option). 476 * scratch register (for want of a better option).
479 */ 477 */
480 EX_SCRATCH_REG = sp; 478 EX_SCRATCH_REG = sp;
481 sp.l = _exception_stack_top; 479 GET_PDA_SAFE(sp);
482 sp.h = _exception_stack_top; 480 sp = [sp + PDA_EXSTACK]
483 /* Try to deal with syscalls quickly. */ 481 /* Try to deal with syscalls quickly. */
484 [--sp] = ASTAT; 482 [--sp] = ASTAT;
485 [--sp] = (R7:6,P5:4); 483 [--sp] = (R7:6,P5:4);
@@ -501,27 +499,22 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/
501 * but they are not very interesting, so don't save them 499 * but they are not very interesting, so don't save them
502 */ 500 */
503 501
502 GET_PDA(p5, r7);
504 p4.l = lo(DCPLB_FAULT_ADDR); 503 p4.l = lo(DCPLB_FAULT_ADDR);
505 p4.h = hi(DCPLB_FAULT_ADDR); 504 p4.h = hi(DCPLB_FAULT_ADDR);
506 r7 = [p4]; 505 r7 = [p4];
507 p5.h = _saved_dcplb_fault_addr; 506 [p5 + PDA_DCPLB] = r7;
508 p5.l = _saved_dcplb_fault_addr;
509 [p5] = r7;
510 507
511 r7 = [p4 + (ICPLB_FAULT_ADDR - DCPLB_FAULT_ADDR)]; 508 p4.l = lo(ICPLB_FAULT_ADDR);
512 p5.h = _saved_icplb_fault_addr; 509 p4.h = hi(ICPLB_FAULT_ADDR);
513 p5.l = _saved_icplb_fault_addr; 510 r7 = [p4];
514 [p5] = r7; 511 [p5 + PDA_ICPLB] = r7;
515 512
516 p4.l = _saved_retx;
517 p4.h = _saved_retx;
518 r6 = retx; 513 r6 = retx;
519 [p4] = r6; 514 [p5 + PDA_RETX] = r6;
520 515
521 r7 = SEQSTAT; /* reason code is in bit 5:0 */ 516 r7 = SEQSTAT; /* reason code is in bit 5:0 */
522 p4.l = _saved_seqstat; 517 [p5 + PDA_SEQSTAT] = r7;
523 p4.h = _saved_seqstat;
524 [p4] = r7;
525#else 518#else
526 r7 = SEQSTAT; /* reason code is in bit 5:0 */ 519 r7 = SEQSTAT; /* reason code is in bit 5:0 */
527#endif 520#endif
@@ -546,11 +539,11 @@ ENTRY(_kernel_execve)
546 p0 = sp; 539 p0 = sp;
547 r3 = SIZEOF_PTREGS / 4; 540 r3 = SIZEOF_PTREGS / 4;
548 r4 = 0(x); 541 r4 = 0(x);
5490: 542.Lclear_regs:
550 [p0++] = r4; 543 [p0++] = r4;
551 r3 += -1; 544 r3 += -1;
552 cc = r3 == 0; 545 cc = r3 == 0;
553 if !cc jump 0b (bp); 546 if !cc jump .Lclear_regs (bp);
554 547
555 p0 = sp; 548 p0 = sp;
556 sp += -16; 549 sp += -16;
@@ -558,7 +551,7 @@ ENTRY(_kernel_execve)
558 call _do_execve; 551 call _do_execve;
559 SP += 16; 552 SP += 16;
560 cc = r0 == 0; 553 cc = r0 == 0;
561 if ! cc jump 1f; 554 if ! cc jump .Lexecve_failed;
562 /* Success. Copy our temporary pt_regs to the top of the kernel 555 /* Success. Copy our temporary pt_regs to the top of the kernel
563 * stack and do a normal exception return. 556 * stack and do a normal exception return.
564 */ 557 */
@@ -574,12 +567,12 @@ ENTRY(_kernel_execve)
574 p0 = fp; 567 p0 = fp;
575 r4 = [p0--]; 568 r4 = [p0--];
576 r3 = SIZEOF_PTREGS / 4; 569 r3 = SIZEOF_PTREGS / 4;
5770: 570.Lcopy_regs:
578 r4 = [p0--]; 571 r4 = [p0--];
579 [p1--] = r4; 572 [p1--] = r4;
580 r3 += -1; 573 r3 += -1;
581 cc = r3 == 0; 574 cc = r3 == 0;
582 if ! cc jump 0b (bp); 575 if ! cc jump .Lcopy_regs (bp);
583 576
584 r0 = (KERNEL_STACK_SIZE - SIZEOF_PTREGS) (z); 577 r0 = (KERNEL_STACK_SIZE - SIZEOF_PTREGS) (z);
585 p1 = r0; 578 p1 = r0;
@@ -591,7 +584,7 @@ ENTRY(_kernel_execve)
591 584
592 RESTORE_CONTEXT; 585 RESTORE_CONTEXT;
593 rti; 586 rti;
5941: 587.Lexecve_failed:
595 unlink; 588 unlink;
596 rts; 589 rts;
597ENDPROC(_kernel_execve) 590ENDPROC(_kernel_execve)
@@ -925,9 +918,14 @@ _schedule_and_signal_from_int:
925 p1 = rets; 918 p1 = rets;
926 [sp + PT_RESERVED] = p1; 919 [sp + PT_RESERVED] = p1;
927 920
921#ifdef CONFIG_SMP
922 GET_PDA(p0, r0); /* Fetch current PDA (can't migrate to other CPU here) */
923 r0 = [p0 + PDA_IRQFLAGS];
924#else
928 p0.l = _irq_flags; 925 p0.l = _irq_flags;
929 p0.h = _irq_flags; 926 p0.h = _irq_flags;
930 r0 = [p0]; 927 r0 = [p0];
928#endif
931 sti r0; 929 sti r0;
932 930
933 r0 = sp; 931 r0 = sp;
@@ -1539,12 +1537,6 @@ ENTRY(_sys_call_table)
1539 .endr 1537 .endr
1540END(_sys_call_table) 1538END(_sys_call_table)
1541 1539
1542#if ANOMALY_05000261
1543/* Used by the assembly entry point to work around an anomaly. */
1544_last_cplb_fault_retx:
1545 .long 0;
1546#endif
1547
1548#ifdef CONFIG_EXCEPTION_L1_SCRATCH 1540#ifdef CONFIG_EXCEPTION_L1_SCRATCH
1549/* .section .l1.bss.scratch */ 1541/* .section .l1.bss.scratch */
1550.set _exception_stack_top, L1_SCRATCH_START + L1_SCRATCH_LENGTH 1542.set _exception_stack_top, L1_SCRATCH_START + L1_SCRATCH_LENGTH
@@ -1554,8 +1546,8 @@ _last_cplb_fault_retx:
1554#else 1546#else
1555.bss 1547.bss
1556#endif 1548#endif
1557_exception_stack: 1549ENTRY(_exception_stack)
1558 .rept 1024 1550 .rept 1024 * NR_CPUS
1559 .long 0 1551 .long 0
1560 .endr 1552 .endr
1561_exception_stack_top: 1553_exception_stack_top:
diff --git a/arch/blackfin/mach-common/head.S b/arch/blackfin/mach-common/head.S
index c1dcaebbd3a9..a621ae444810 100644
--- a/arch/blackfin/mach-common/head.S
+++ b/arch/blackfin/mach-common/head.S
@@ -13,6 +13,7 @@
13#include <asm/blackfin.h> 13#include <asm/blackfin.h>
14#include <asm/thread_info.h> 14#include <asm/thread_info.h>
15#include <asm/trace.h> 15#include <asm/trace.h>
16#include <asm/asm-offsets.h>
16 17
17__INIT 18__INIT
18 19
@@ -111,33 +112,26 @@ ENTRY(__start)
111 * This happens here, since L1 gets clobbered 112 * This happens here, since L1 gets clobbered
112 * below 113 * below
113 */ 114 */
114 p0.l = _saved_retx; 115 GET_PDA(p0, r0);
115 p0.h = _saved_retx; 116 r7 = [p0 + PDA_RETX];
116 p1.l = _init_saved_retx; 117 p1.l = _init_saved_retx;
117 p1.h = _init_saved_retx; 118 p1.h = _init_saved_retx;
118 r0 = [p0]; 119 [p1] = r7;
119 [p1] = r0;
120 120
121 p0.l = _saved_dcplb_fault_addr; 121 r7 = [p0 + PDA_DCPLB];
122 p0.h = _saved_dcplb_fault_addr;
123 p1.l = _init_saved_dcplb_fault_addr; 122 p1.l = _init_saved_dcplb_fault_addr;
124 p1.h = _init_saved_dcplb_fault_addr; 123 p1.h = _init_saved_dcplb_fault_addr;
125 r0 = [p0]; 124 [p1] = r7;
126 [p1] = r0;
127 125
128 p0.l = _saved_icplb_fault_addr; 126 r7 = [p0 + PDA_ICPLB];
129 p0.h = _saved_icplb_fault_addr;
130 p1.l = _init_saved_icplb_fault_addr; 127 p1.l = _init_saved_icplb_fault_addr;
131 p1.h = _init_saved_icplb_fault_addr; 128 p1.h = _init_saved_icplb_fault_addr;
132 r0 = [p0]; 129 [p1] = r7;
133 [p1] = r0;
134 130
135 p0.l = _saved_seqstat; 131 r7 = [p0 + PDA_SEQSTAT];
136 p0.h = _saved_seqstat;
137 p1.l = _init_saved_seqstat; 132 p1.l = _init_saved_seqstat;
138 p1.h = _init_saved_seqstat; 133 p1.h = _init_saved_seqstat;
139 r0 = [p0]; 134 [p1] = r7;
140 [p1] = r0;
141#endif 135#endif
142 136
143 /* Initialize stack pointer */ 137 /* Initialize stack pointer */
@@ -255,6 +249,9 @@ ENTRY(_real_start)
255 sp = sp + p1; 249 sp = sp + p1;
256 usp = sp; 250 usp = sp;
257 fp = sp; 251 fp = sp;
252 sp += -12;
253 call _init_pda
254 sp += 12;
258 jump.l _start_kernel; 255 jump.l _start_kernel;
259ENDPROC(_real_start) 256ENDPROC(_real_start)
260 257
diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c
index d45d0c59fac7..eb8dfcfc3544 100644
--- a/arch/blackfin/mach-common/ints-priority.c
+++ b/arch/blackfin/mach-common/ints-priority.c
@@ -55,6 +55,7 @@
55 * - 55 * -
56 */ 56 */
57 57
58#ifndef CONFIG_SMP
58/* Initialize this to an actual value to force it into the .data 59/* Initialize this to an actual value to force it into the .data
59 * section so that we know it is properly initialized at entry into 60 * section so that we know it is properly initialized at entry into
60 * the kernel but before bss is initialized to zero (which is where 61 * the kernel but before bss is initialized to zero (which is where
@@ -63,6 +64,7 @@
63 */ 64 */
64unsigned long irq_flags = 0x1f; 65unsigned long irq_flags = 0x1f;
65EXPORT_SYMBOL(irq_flags); 66EXPORT_SYMBOL(irq_flags);
67#endif
66 68
67/* The number of spurious interrupts */ 69/* The number of spurious interrupts */
68atomic_t num_spurious; 70atomic_t num_spurious;
@@ -163,6 +165,10 @@ static void bfin_internal_mask_irq(unsigned int irq)
163 mask_bit = SIC_SYSIRQ(irq) % 32; 165 mask_bit = SIC_SYSIRQ(irq) % 32;
164 bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) & 166 bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) &
165 ~(1 << mask_bit)); 167 ~(1 << mask_bit));
168#ifdef CONFIG_SMP
169 bfin_write_SICB_IMASK(mask_bank, bfin_read_SICB_IMASK(mask_bank) &
170 ~(1 << mask_bit));
171#endif
166#endif 172#endif
167} 173}
168 174
@@ -177,6 +183,10 @@ static void bfin_internal_unmask_irq(unsigned int irq)
177 mask_bit = SIC_SYSIRQ(irq) % 32; 183 mask_bit = SIC_SYSIRQ(irq) % 32;
178 bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) | 184 bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) |
179 (1 << mask_bit)); 185 (1 << mask_bit));
186#ifdef CONFIG_SMP
187 bfin_write_SICB_IMASK(mask_bank, bfin_read_SICB_IMASK(mask_bank) |
188 (1 << mask_bit));
189#endif
180#endif 190#endif
181} 191}
182 192
@@ -896,7 +906,7 @@ static struct irq_chip bfin_gpio_irqchip = {
896#endif 906#endif
897}; 907};
898 908
899void __init init_exception_vectors(void) 909void __cpuinit init_exception_vectors(void)
900{ 910{
901 /* cannot program in software: 911 /* cannot program in software:
902 * evt0 - emulation (jtag) 912 * evt0 - emulation (jtag)
@@ -935,6 +945,10 @@ int __init init_arch_irq(void)
935# ifdef CONFIG_BF54x 945# ifdef CONFIG_BF54x
936 bfin_write_SIC_IMASK2(SIC_UNMASK_ALL); 946 bfin_write_SIC_IMASK2(SIC_UNMASK_ALL);
937# endif 947# endif
948# ifdef CONFIG_SMP
949 bfin_write_SICB_IMASK0(SIC_UNMASK_ALL);
950 bfin_write_SICB_IMASK1(SIC_UNMASK_ALL);
951# endif
938#else 952#else
939 bfin_write_SIC_IMASK(SIC_UNMASK_ALL); 953 bfin_write_SIC_IMASK(SIC_UNMASK_ALL);
940#endif 954#endif
@@ -995,6 +1009,17 @@ int __init init_arch_irq(void)
995 1009
996 break; 1010 break;
997#endif 1011#endif
1012#ifdef CONFIG_TICK_SOURCE_SYSTMR0
1013 case IRQ_TIMER0:
1014 set_irq_handler(irq, handle_percpu_irq);
1015 break;
1016#endif
1017#ifdef CONFIG_SMP
1018 case IRQ_SUPPLE_0:
1019 case IRQ_SUPPLE_1:
1020 set_irq_handler(irq, handle_percpu_irq);
1021 break;
1022#endif
998 default: 1023 default:
999 set_irq_handler(irq, handle_simple_irq); 1024 set_irq_handler(irq, handle_simple_irq);
1000 break; 1025 break;
@@ -1029,7 +1054,7 @@ int __init init_arch_irq(void)
1029 search_IAR(); 1054 search_IAR();
1030 1055
1031 /* Enable interrupts IVG7-15 */ 1056 /* Enable interrupts IVG7-15 */
1032 irq_flags = irq_flags | IMASK_IVG15 | 1057 irq_flags |= IMASK_IVG15 |
1033 IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 | 1058 IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
1034 IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW; 1059 IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;
1035 1060
@@ -1070,8 +1095,16 @@ void do_irq(int vec, struct pt_regs *fp)
1070 || defined(BF538_FAMILY) || defined(CONFIG_BF51x) 1095 || defined(BF538_FAMILY) || defined(CONFIG_BF51x)
1071 unsigned long sic_status[3]; 1096 unsigned long sic_status[3];
1072 1097
1073 sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0(); 1098 if (smp_processor_id()) {
1074 sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1(); 1099#ifdef CONFIG_SMP
1100 /* This will be optimized out in UP mode. */
1101 sic_status[0] = bfin_read_SICB_ISR0() & bfin_read_SICB_IMASK0();
1102 sic_status[1] = bfin_read_SICB_ISR1() & bfin_read_SICB_IMASK1();
1103#endif
1104 } else {
1105 sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
1106 sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
1107 }
1075#ifdef CONFIG_BF54x 1108#ifdef CONFIG_BF54x
1076 sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2(); 1109 sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
1077#endif 1110#endif
diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c
new file mode 100644
index 000000000000..7aeecedd3147
--- /dev/null
+++ b/arch/blackfin/mach-common/smp.c
@@ -0,0 +1,476 @@
1/*
2 * File: arch/blackfin/kernel/smp.c
3 * Author: Philippe Gerum <rpm@xenomai.org>
4 * IPI management based on arch/arm/kernel/smp.c.
5 *
6 * Copyright 2007 Analog Devices Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see the file COPYING, or write
20 * to the Free Software Foundation, Inc.,
21 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#include <linux/module.h>
25#include <linux/delay.h>
26#include <linux/init.h>
27#include <linux/spinlock.h>
28#include <linux/sched.h>
29#include <linux/interrupt.h>
30#include <linux/cache.h>
31#include <linux/profile.h>
32#include <linux/errno.h>
33#include <linux/mm.h>
34#include <linux/cpu.h>
35#include <linux/smp.h>
36#include <linux/seq_file.h>
37#include <linux/irq.h>
38#include <asm/atomic.h>
39#include <asm/cacheflush.h>
40#include <asm/mmu_context.h>
41#include <asm/pgtable.h>
42#include <asm/pgalloc.h>
43#include <asm/processor.h>
44#include <asm/ptrace.h>
45#include <asm/cpu.h>
46#include <linux/err.h>
47
48struct corelock_slot corelock __attribute__ ((__section__(".l2.bss")));
49
50void __cpuinitdata *init_retx_coreb, *init_saved_retx_coreb,
51 *init_saved_seqstat_coreb, *init_saved_icplb_fault_addr_coreb,
52 *init_saved_dcplb_fault_addr_coreb;
53
54cpumask_t cpu_possible_map;
55EXPORT_SYMBOL(cpu_possible_map);
56
57cpumask_t cpu_online_map;
58EXPORT_SYMBOL(cpu_online_map);
59
60#define BFIN_IPI_RESCHEDULE 0
61#define BFIN_IPI_CALL_FUNC 1
62#define BFIN_IPI_CPU_STOP 2
63
64struct blackfin_flush_data {
65 unsigned long start;
66 unsigned long end;
67};
68
69void *secondary_stack;
70
71
72struct smp_call_struct {
73 void (*func)(void *info);
74 void *info;
75 int wait;
76 cpumask_t pending;
77 cpumask_t waitmask;
78};
79
80static struct blackfin_flush_data smp_flush_data;
81
82static DEFINE_SPINLOCK(stop_lock);
83
84struct ipi_message {
85 struct list_head list;
86 unsigned long type;
87 struct smp_call_struct call_struct;
88};
89
90struct ipi_message_queue {
91 struct list_head head;
92 spinlock_t lock;
93 unsigned long count;
94};
95
96static DEFINE_PER_CPU(struct ipi_message_queue, ipi_msg_queue);
97
98static void ipi_cpu_stop(unsigned int cpu)
99{
100 spin_lock(&stop_lock);
101 printk(KERN_CRIT "CPU%u: stopping\n", cpu);
102 dump_stack();
103 spin_unlock(&stop_lock);
104
105 cpu_clear(cpu, cpu_online_map);
106
107 local_irq_disable();
108
109 while (1)
110 SSYNC();
111}
112
113static void ipi_flush_icache(void *info)
114{
115 struct blackfin_flush_data *fdata = info;
116
117 /* Invalidate the memory holding the bounds of the flushed region. */
118 blackfin_dcache_invalidate_range((unsigned long)fdata,
119 (unsigned long)fdata + sizeof(*fdata));
120
121 blackfin_icache_flush_range(fdata->start, fdata->end);
122}
123
124static void ipi_call_function(unsigned int cpu, struct ipi_message *msg)
125{
126 int wait;
127 void (*func)(void *info);
128 void *info;
129 func = msg->call_struct.func;
130 info = msg->call_struct.info;
131 wait = msg->call_struct.wait;
132 cpu_clear(cpu, msg->call_struct.pending);
133 func(info);
134 if (wait)
135 cpu_clear(cpu, msg->call_struct.waitmask);
136 else
137 kfree(msg);
138}
139
140static irqreturn_t ipi_handler(int irq, void *dev_instance)
141{
142 struct ipi_message *msg, *mg;
143 struct ipi_message_queue *msg_queue;
144 unsigned int cpu = smp_processor_id();
145
146 platform_clear_ipi(cpu);
147
148 msg_queue = &__get_cpu_var(ipi_msg_queue);
149 msg_queue->count++;
150
151 spin_lock(&msg_queue->lock);
152 list_for_each_entry_safe(msg, mg, &msg_queue->head, list) {
153 list_del(&msg->list);
154 switch (msg->type) {
155 case BFIN_IPI_RESCHEDULE:
156 /* That's the easiest one; leave it to
157 * return_from_int. */
158 kfree(msg);
159 break;
160 case BFIN_IPI_CALL_FUNC:
161 ipi_call_function(cpu, msg);
162 break;
163 case BFIN_IPI_CPU_STOP:
164 ipi_cpu_stop(cpu);
165 kfree(msg);
166 break;
167 default:
168 printk(KERN_CRIT "CPU%u: Unknown IPI message \
169 0x%lx\n", cpu, msg->type);
170 kfree(msg);
171 break;
172 }
173 }
174 spin_unlock(&msg_queue->lock);
175 return IRQ_HANDLED;
176}
177
178static void ipi_queue_init(void)
179{
180 unsigned int cpu;
181 struct ipi_message_queue *msg_queue;
182 for_each_possible_cpu(cpu) {
183 msg_queue = &per_cpu(ipi_msg_queue, cpu);
184 INIT_LIST_HEAD(&msg_queue->head);
185 spin_lock_init(&msg_queue->lock);
186 msg_queue->count = 0;
187 }
188}
189
190int smp_call_function(void (*func)(void *info), void *info, int wait)
191{
192 unsigned int cpu;
193 cpumask_t callmap;
194 unsigned long flags;
195 struct ipi_message_queue *msg_queue;
196 struct ipi_message *msg;
197
198 callmap = cpu_online_map;
199 cpu_clear(smp_processor_id(), callmap);
200 if (cpus_empty(callmap))
201 return 0;
202
203 msg = kmalloc(sizeof(*msg), GFP_ATOMIC);
204 INIT_LIST_HEAD(&msg->list);
205 msg->call_struct.func = func;
206 msg->call_struct.info = info;
207 msg->call_struct.wait = wait;
208 msg->call_struct.pending = callmap;
209 msg->call_struct.waitmask = callmap;
210 msg->type = BFIN_IPI_CALL_FUNC;
211
212 for_each_cpu_mask(cpu, callmap) {
213 msg_queue = &per_cpu(ipi_msg_queue, cpu);
214 spin_lock_irqsave(&msg_queue->lock, flags);
215 list_add(&msg->list, &msg_queue->head);
216 spin_unlock_irqrestore(&msg_queue->lock, flags);
217 platform_send_ipi_cpu(cpu);
218 }
219 if (wait) {
220 while (!cpus_empty(msg->call_struct.waitmask))
221 blackfin_dcache_invalidate_range(
222 (unsigned long)(&msg->call_struct.waitmask),
223 (unsigned long)(&msg->call_struct.waitmask));
224 kfree(msg);
225 }
226 return 0;
227}
228EXPORT_SYMBOL_GPL(smp_call_function);
229
230int smp_call_function_single(int cpuid, void (*func) (void *info), void *info,
231 int wait)
232{
233 unsigned int cpu = cpuid;
234 cpumask_t callmap;
235 unsigned long flags;
236 struct ipi_message_queue *msg_queue;
237 struct ipi_message *msg;
238
239 if (cpu_is_offline(cpu))
240 return 0;
241 cpus_clear(callmap);
242 cpu_set(cpu, callmap);
243
244 msg = kmalloc(sizeof(*msg), GFP_ATOMIC);
245 INIT_LIST_HEAD(&msg->list);
246 msg->call_struct.func = func;
247 msg->call_struct.info = info;
248 msg->call_struct.wait = wait;
249 msg->call_struct.pending = callmap;
250 msg->call_struct.waitmask = callmap;
251 msg->type = BFIN_IPI_CALL_FUNC;
252
253 msg_queue = &per_cpu(ipi_msg_queue, cpu);
254 spin_lock_irqsave(&msg_queue->lock, flags);
255 list_add(&msg->list, &msg_queue->head);
256 spin_unlock_irqrestore(&msg_queue->lock, flags);
257 platform_send_ipi_cpu(cpu);
258
259 if (wait) {
260 while (!cpus_empty(msg->call_struct.waitmask))
261 blackfin_dcache_invalidate_range(
262 (unsigned long)(&msg->call_struct.waitmask),
263 (unsigned long)(&msg->call_struct.waitmask));
264 kfree(msg);
265 }
266 return 0;
267}
268EXPORT_SYMBOL_GPL(smp_call_function_single);
269
270void smp_send_reschedule(int cpu)
271{
272 unsigned long flags;
273 struct ipi_message_queue *msg_queue;
274 struct ipi_message *msg;
275
276 if (cpu_is_offline(cpu))
277 return;
278
279 msg = kmalloc(sizeof(*msg), GFP_ATOMIC);
280 memset(msg, 0, sizeof(msg));
281 INIT_LIST_HEAD(&msg->list);
282 msg->type = BFIN_IPI_RESCHEDULE;
283
284 msg_queue = &per_cpu(ipi_msg_queue, cpu);
285 spin_lock_irqsave(&msg_queue->lock, flags);
286 list_add(&msg->list, &msg_queue->head);
287 spin_unlock_irqrestore(&msg_queue->lock, flags);
288 platform_send_ipi_cpu(cpu);
289
290 return;
291}
292
293void smp_send_stop(void)
294{
295 unsigned int cpu;
296 cpumask_t callmap;
297 unsigned long flags;
298 struct ipi_message_queue *msg_queue;
299 struct ipi_message *msg;
300
301 callmap = cpu_online_map;
302 cpu_clear(smp_processor_id(), callmap);
303 if (cpus_empty(callmap))
304 return;
305
306 msg = kmalloc(sizeof(*msg), GFP_ATOMIC);
307 memset(msg, 0, sizeof(msg));
308 INIT_LIST_HEAD(&msg->list);
309 msg->type = BFIN_IPI_CPU_STOP;
310
311 for_each_cpu_mask(cpu, callmap) {
312 msg_queue = &per_cpu(ipi_msg_queue, cpu);
313 spin_lock_irqsave(&msg_queue->lock, flags);
314 list_add(&msg->list, &msg_queue->head);
315 spin_unlock_irqrestore(&msg_queue->lock, flags);
316 platform_send_ipi_cpu(cpu);
317 }
318 return;
319}
320
321int __cpuinit __cpu_up(unsigned int cpu)
322{
323 struct task_struct *idle;
324 int ret;
325
326 idle = fork_idle(cpu);
327 if (IS_ERR(idle)) {
328 printk(KERN_ERR "CPU%u: fork() failed\n", cpu);
329 return PTR_ERR(idle);
330 }
331
332 secondary_stack = task_stack_page(idle) + THREAD_SIZE;
333 smp_wmb();
334
335 ret = platform_boot_secondary(cpu, idle);
336
337 if (ret) {
338 cpu_clear(cpu, cpu_present_map);
339 printk(KERN_CRIT "CPU%u: processor failed to boot (%d)\n", cpu, ret);
340 free_task(idle);
341 } else
342 cpu_set(cpu, cpu_online_map);
343
344 secondary_stack = NULL;
345
346 return ret;
347}
348
349static void __cpuinit setup_secondary(unsigned int cpu)
350{
351#ifndef CONFIG_TICK_SOURCE_SYSTMR0
352 struct irq_desc *timer_desc;
353#endif
354 unsigned long ilat;
355
356 bfin_write_IMASK(0);
357 CSYNC();
358 ilat = bfin_read_ILAT();
359 CSYNC();
360 bfin_write_ILAT(ilat);
361 CSYNC();
362
363 /* Reserve the PDA space for the secondary CPU. */
364 reserve_pda();
365
366 /* Enable interrupt levels IVG7-15. IARs have been already
367 * programmed by the boot CPU. */
368 irq_flags |= IMASK_IVG15 |
369 IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
370 IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;
371
372#ifdef CONFIG_TICK_SOURCE_SYSTMR0
373 /* Power down the core timer, just to play safe. */
374 bfin_write_TCNTL(0);
375
376 /* system timer0 has been setup by CoreA. */
377#else
378 timer_desc = irq_desc + IRQ_CORETMR;
379 setup_core_timer();
380 timer_desc->chip->enable(IRQ_CORETMR);
381#endif
382}
383
384void __cpuinit secondary_start_kernel(void)
385{
386 unsigned int cpu = smp_processor_id();
387 struct mm_struct *mm = &init_mm;
388
389 if (_bfin_swrst & SWRST_DBL_FAULT_B) {
390 printk(KERN_EMERG "CoreB Recovering from DOUBLE FAULT event\n");
391#ifdef CONFIG_DEBUG_DOUBLEFAULT
392 printk(KERN_EMERG " While handling exception (EXCAUSE = 0x%x) at %pF\n",
393 (int)init_saved_seqstat_coreb & SEQSTAT_EXCAUSE, init_saved_retx_coreb);
394 printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %pF\n", init_saved_dcplb_fault_addr_coreb);
395 printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %pF\n", init_saved_icplb_fault_addr_coreb);
396#endif
397 printk(KERN_NOTICE " The instruction at %pF caused a double exception\n",
398 init_retx_coreb);
399 }
400
401 /*
402 * We want the D-cache to be enabled early, in case the atomic
403 * support code emulates cache coherence (see
404 * __ARCH_SYNC_CORE_DCACHE).
405 */
406 init_exception_vectors();
407
408 bfin_setup_caches(cpu);
409
410 local_irq_disable();
411
412 /* Attach the new idle task to the global mm. */
413 atomic_inc(&mm->mm_users);
414 atomic_inc(&mm->mm_count);
415 current->active_mm = mm;
416 BUG_ON(current->mm); /* Can't be, but better be safe than sorry. */
417
418 preempt_disable();
419
420 setup_secondary(cpu);
421
422 local_irq_enable();
423
424 platform_secondary_init(cpu);
425
426 cpu_idle();
427}
428
429void __init smp_prepare_boot_cpu(void)
430{
431}
432
433void __init smp_prepare_cpus(unsigned int max_cpus)
434{
435 platform_prepare_cpus(max_cpus);
436 ipi_queue_init();
437 platform_request_ipi(&ipi_handler);
438}
439
440void __init smp_cpus_done(unsigned int max_cpus)
441{
442 unsigned long bogosum = 0;
443 unsigned int cpu;
444
445 for_each_online_cpu(cpu)
446 bogosum += per_cpu(cpu_data, cpu).loops_per_jiffy;
447
448 printk(KERN_INFO "SMP: Total of %d processors activated "
449 "(%lu.%02lu BogoMIPS).\n",
450 num_online_cpus(),
451 bogosum / (500000/HZ),
452 (bogosum / (5000/HZ)) % 100);
453}
454
455void smp_icache_flush_range_others(unsigned long start, unsigned long end)
456{
457 smp_flush_data.start = start;
458 smp_flush_data.end = end;
459
460 if (smp_call_function(&ipi_flush_icache, &smp_flush_data, 1))
461 printk(KERN_WARNING "SMP: failed to run I-cache flush request on other CPUs\n");
462}
463EXPORT_SYMBOL_GPL(smp_icache_flush_range_others);
464
465#ifdef __ARCH_SYNC_CORE_DCACHE
466unsigned long barrier_mask __attribute__ ((__section__(".l2.bss")));
467
468void resync_core_dcache(void)
469{
470 unsigned int cpu = get_cpu();
471 blackfin_invalidate_entire_dcache();
472 ++per_cpu(cpu_data, cpu).dcache_invld_count;
473 put_cpu();
474}
475EXPORT_SYMBOL(resync_core_dcache);
476#endif
diff --git a/arch/blackfin/oprofile/common.c b/arch/blackfin/oprofile/common.c
index 0f6d303a8891..f34795a2e481 100644
--- a/arch/blackfin/oprofile/common.c
+++ b/arch/blackfin/oprofile/common.c
@@ -130,7 +130,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
130 130
131 mutex_init(&pfmon_lock); 131 mutex_init(&pfmon_lock);
132 132
133 dspid = bfin_read_DSPID(); 133 dspid = bfin_dspid();
134 134
135 printk(KERN_INFO "Oprofile got the cpu id is 0x%x. \n", dspid); 135 printk(KERN_INFO "Oprofile got the cpu id is 0x%x. \n", dspid);
136 136