diff options
author | Graf Yang <graf.yang@analog.com> | 2009-01-07 10:14:39 -0500 |
---|---|---|
committer | Bryan Wu <cooloney@kernel.org> | 2009-01-07 10:14:39 -0500 |
commit | 6b3087c64a92a36ae20d33479b4df6d7afc910d4 (patch) | |
tree | 95984fc623658ebf150d0d912a7f6c5a0301a5a9 /arch/blackfin | |
parent | c51b4488cd5bff08ed5690a8f303ff7f0894da2a (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')
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 | ||
22 | static __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 | |||
24 | asmlinkage int __raw_uncached_fetch_asm(const volatile int *ptr); | ||
25 | |||
26 | asmlinkage int __raw_atomic_update_asm(volatile int *ptr, int value); | ||
27 | |||
28 | asmlinkage int __raw_atomic_clear_asm(volatile int *ptr, int value); | ||
29 | |||
30 | asmlinkage int __raw_atomic_set_asm(volatile int *ptr, int value); | ||
31 | |||
32 | asmlinkage int __raw_atomic_xor_asm(volatile int *ptr, int value); | ||
33 | |||
34 | asmlinkage int __raw_atomic_test_asm(const volatile int *ptr, int value); | ||
35 | |||
36 | static inline void atomic_add(int i, atomic_t *v) | ||
37 | { | ||
38 | __raw_atomic_update_asm(&v->counter, i); | ||
39 | } | ||
40 | |||
41 | static inline void atomic_sub(int i, atomic_t *v) | ||
42 | { | ||
43 | __raw_atomic_update_asm(&v->counter, -i); | ||
44 | } | ||
45 | |||
46 | static inline int atomic_add_return(int i, atomic_t *v) | ||
47 | { | ||
48 | return __raw_atomic_update_asm(&v->counter, i); | ||
49 | } | ||
50 | |||
51 | static inline int atomic_sub_return(int i, atomic_t *v) | ||
52 | { | ||
53 | return __raw_atomic_update_asm(&v->counter, -i); | ||
54 | } | ||
55 | |||
56 | static inline void atomic_inc(volatile atomic_t *v) | ||
57 | { | ||
58 | __raw_atomic_update_asm(&v->counter, 1); | ||
59 | } | ||
60 | |||
61 | static inline void atomic_dec(volatile atomic_t *v) | ||
62 | { | ||
63 | __raw_atomic_update_asm(&v->counter, -1); | ||
64 | } | ||
65 | |||
66 | static inline void atomic_clear_mask(int mask, atomic_t *v) | ||
67 | { | ||
68 | __raw_atomic_clear_asm(&v->counter, mask); | ||
69 | } | ||
70 | |||
71 | static inline void atomic_set_mask(int mask, atomic_t *v) | ||
72 | { | ||
73 | __raw_atomic_set_asm(&v->counter, mask); | ||
74 | } | ||
75 | |||
76 | static 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 | |||
91 | static 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 | ||
31 | static __inline__ void atomic_sub(int i, atomic_t * v) | 100 | static 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 | ||
41 | static inline int atomic_add_return(int i, atomic_t * v) | 110 | static 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) | 124 | static inline int atomic_sub_return(int i, atomic_t *v) |
56 | static 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 | ||
69 | static __inline__ void atomic_inc(volatile atomic_t * v) | 137 | static 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))) | 146 | static 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 | |||
91 | static __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 | ||
100 | static __inline__ void atomic_clear_mask(unsigned int mask, atomic_t * v) | 155 | static 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 | ||
109 | static __inline__ void atomic_set_mask(unsigned int mask, atomic_t * v) | 164 | static 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 | ||
50 | extern void bfin_setup_caches(unsigned int cpu); | ||
51 | extern void bfin_setup_cpudata(unsigned int cpu); | ||
52 | |||
50 | extern unsigned long get_cclk(void); | 53 | extern unsigned long get_cclk(void); |
51 | extern unsigned long get_sclk(void); | 54 | extern unsigned long get_sclk(void); |
52 | extern unsigned long sclk_to_usecs(unsigned long sclk); | 55 | extern 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 */ |
60 | extern int init_arch_irq(void); | 63 | extern int init_arch_irq(void); |
61 | extern void bfin_icache_init(void); | ||
62 | extern void bfin_dcache_init(void); | ||
63 | extern void init_exception_vectors(void); | 64 | extern void init_exception_vectors(void); |
64 | extern void program_IAR(void); | 65 | extern 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 | ||
23 | static __inline__ void set_bit(int nr, volatile unsigned long *addr) | 22 | #ifdef CONFIG_SMP |
23 | |||
24 | #include <linux/linkage.h> | ||
25 | |||
26 | asmlinkage int __raw_bit_set_asm(volatile unsigned long *addr, int nr); | ||
27 | |||
28 | asmlinkage int __raw_bit_clear_asm(volatile unsigned long *addr, int nr); | ||
29 | |||
30 | asmlinkage int __raw_bit_toggle_asm(volatile unsigned long *addr, int nr); | ||
31 | |||
32 | asmlinkage int __raw_bit_test_set_asm(volatile unsigned long *addr, int nr); | ||
33 | |||
34 | asmlinkage int __raw_bit_test_clear_asm(volatile unsigned long *addr, int nr); | ||
35 | |||
36 | asmlinkage int __raw_bit_test_toggle_asm(volatile unsigned long *addr, int nr); | ||
37 | |||
38 | asmlinkage int __raw_bit_test_asm(const volatile unsigned long *addr, int nr); | ||
39 | |||
40 | static 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; | 46 | static 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 | ||
36 | static __inline__ void __set_bit(int nr, volatile unsigned long *addr) | 52 | static 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; | 58 | static 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 | /* | 64 | static 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 | ||
52 | static __inline__ void clear_bit(int nr, volatile unsigned long *addr) | 70 | static 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 | |||
76 | static 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 | |||
86 | static 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 | ||
64 | static __inline__ void __clear_bit(int nr, volatile unsigned long *addr) | 98 | static 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 | ||
74 | static __inline__ void change_bit(int nr, volatile unsigned long *addr) | 110 | static 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 | ||
86 | static __inline__ void __change_bit(int nr, volatile unsigned long *addr) | 122 | static 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 | |||
96 | static __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 | ||
112 | static __inline__ int __test_and_set_bit(int nr, volatile unsigned long *addr) | 138 | static 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 | ||
124 | static __inline__ int test_and_clear_bit(int nr, volatile unsigned long *addr) | 154 | static 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 | ||
140 | static __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 | |||
177 | static 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 | |||
187 | static 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 | |||
197 | static 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 | |||
207 | static 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 | ||
152 | static __inline__ int test_and_change_bit(int nr, volatile unsigned long *addr) | 219 | static 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 | ||
167 | static __inline__ int __test_and_change_bit(int nr, | 231 | static 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 | /* | 244 | static inline int __test_bit(int nr, const void *addr) |
181 | * This routine doesn't need to be atomic. | ||
182 | */ | ||
183 | static __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 | |||
189 | static __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 | */ | ||
259 | static 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__ | ||
41 | asmlinkage void __raw_smp_mark_barrier_asm(void); | ||
42 | asmlinkage void __raw_smp_check_barrier_asm(void); | ||
43 | |||
44 | static inline void smp_mark_barrier(void) | ||
45 | { | ||
46 | __raw_smp_mark_barrier_asm(); | ||
47 | } | ||
48 | static inline void smp_check_barrier(void) | ||
49 | { | ||
50 | __raw_smp_check_barrier_asm(); | ||
51 | } | ||
52 | |||
53 | void 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 | |||
35 | extern void blackfin_dcache_flush_range(unsigned long start_address, unsigned long end_address); | 35 | extern void blackfin_dcache_flush_range(unsigned long start_address, unsigned long end_address); |
36 | extern void blackfin_dcache_invalidate_range(unsigned long start_address, unsigned long end_address); | 36 | extern void blackfin_dcache_invalidate_range(unsigned long start_address, unsigned long end_address); |
37 | extern void blackfin_dflush_page(void *page); | 37 | extern void blackfin_dflush_page(void *page); |
38 | extern 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 | |||
47 | static inline void flush_icache_range(unsigned start, unsigned end) | 55 | static 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) \ |
70 | do { memcpy(dst, src, len); \ | 80 | do { 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 | ||
88 | extern unsigned long reserved_mem_dcache_on; | 100 | extern 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 | |||
28 | struct task_struct; | ||
29 | |||
30 | struct 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 | |||
40 | DECLARE_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 | */ | ||
20 | static 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 | */ | ||
39 | static 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 | */ | ||
63 | static 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 | */ | ||
88 | static 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 | |||
16 | static 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 | |||
25 | static 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 | |||
36 | static 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 | |||
46 | static 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 | |||
30 | struct 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 | |||
64 | extern struct blackfin_pda cpu_pda[]; | ||
65 | |||
66 | void 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 */ |
112 | static inline uint32_t __pure bfin_revid(void) | 113 | static inline uint32_t __pure bfin_revid(void) |
@@ -137,7 +138,11 @@ static inline uint32_t __pure bfin_revid(void) | |||
137 | static inline uint16_t __pure bfin_cpuid(void) | 138 | static 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 | ||
143 | static inline uint32_t __pure bfin_dspid(void) | ||
144 | { | ||
145 | return bfin_read_DSPID(); | ||
141 | } | 146 | } |
142 | 147 | ||
143 | static inline uint32_t __pure bfin_compiled_revid(void) | 148 | static 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 | |||
35 | struct corelock_slot { | ||
36 | int lock; | ||
37 | }; | ||
38 | |||
39 | void 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 | 6 | asmlinkage int __raw_spin_is_locked_asm(volatile int *ptr); |
7 | asmlinkage void __raw_spin_lock_asm(volatile int *ptr); | ||
8 | asmlinkage int __raw_spin_trylock_asm(volatile int *ptr); | ||
9 | asmlinkage void __raw_spin_unlock_asm(volatile int *ptr); | ||
10 | asmlinkage void __raw_read_lock_asm(volatile int *ptr); | ||
11 | asmlinkage int __raw_read_trylock_asm(volatile int *ptr); | ||
12 | asmlinkage void __raw_read_unlock_asm(volatile int *ptr); | ||
13 | asmlinkage void __raw_write_lock_asm(volatile int *ptr); | ||
14 | asmlinkage int __raw_write_trylock_asm(volatile int *ptr); | ||
15 | asmlinkage void __raw_write_unlock_asm(volatile int *ptr); | ||
16 | |||
17 | static inline int __raw_spin_is_locked(raw_spinlock_t *lock) | ||
18 | { | ||
19 | return __raw_spin_is_locked_asm(&lock->lock); | ||
20 | } | ||
21 | |||
22 | static 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 | |||
29 | static inline int __raw_spin_trylock(raw_spinlock_t *lock) | ||
30 | { | ||
31 | return __raw_spin_trylock_asm(&lock->lock); | ||
32 | } | ||
33 | |||
34 | static inline void __raw_spin_unlock(raw_spinlock_t *lock) | ||
35 | { | ||
36 | __raw_spin_unlock_asm(&lock->lock); | ||
37 | } | ||
38 | |||
39 | static inline void __raw_spin_unlock_wait(raw_spinlock_t *lock) | ||
40 | { | ||
41 | while (__raw_spin_is_locked(lock)) | ||
42 | cpu_relax(); | ||
43 | } | ||
44 | |||
45 | static inline int __raw_read_can_lock(raw_rwlock_t *rw) | ||
46 | { | ||
47 | return __raw_uncached_fetch_asm(&rw->lock) > 0; | ||
48 | } | ||
49 | |||
50 | static inline int __raw_write_can_lock(raw_rwlock_t *rw) | ||
51 | { | ||
52 | return __raw_uncached_fetch_asm(&rw->lock) == RW_LOCK_BIAS; | ||
53 | } | ||
54 | |||
55 | static inline void __raw_read_lock(raw_rwlock_t *rw) | ||
56 | { | ||
57 | __raw_read_lock_asm(&rw->lock); | ||
58 | } | ||
59 | |||
60 | static inline int __raw_read_trylock(raw_rwlock_t *rw) | ||
61 | { | ||
62 | return __raw_read_trylock_asm(&rw->lock); | ||
63 | } | ||
64 | |||
65 | static inline void __raw_read_unlock(raw_rwlock_t *rw) | ||
66 | { | ||
67 | __raw_read_unlock_asm(&rw->lock); | ||
68 | } | ||
69 | |||
70 | static inline void __raw_write_lock(raw_rwlock_t *rw) | ||
71 | { | ||
72 | __raw_write_lock_asm(&rw->lock); | ||
73 | } | ||
74 | |||
75 | static inline int __raw_write_trylock(raw_rwlock_t *rw) | ||
76 | { | ||
77 | return __raw_write_trylock_asm(&rw->lock); | ||
78 | } | ||
79 | |||
80 | static 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 | |||
10 | typedef struct { | ||
11 | volatile unsigned int lock; | ||
12 | } raw_spinlock_t; | ||
13 | |||
14 | #define __RAW_SPIN_LOCK_UNLOCKED { 0 } | ||
15 | |||
16 | typedef 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 */ | ||
44 | static 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 | |||
45 | extern 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 | ||
68 | extern 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() | 143 | asmlinkage unsigned long __raw_xchg_1_asm(volatile void *ptr, unsigned long value); |
137 | #define smp_rmb() rmb() | 144 | asmlinkage unsigned long __raw_xchg_2_asm(volatile void *ptr, unsigned long value); |
138 | #define smp_wmb() wmb() | 145 | asmlinkage unsigned long __raw_xchg_4_asm(volatile void *ptr, unsigned long value); |
139 | #define smp_read_barrier_depends() read_barrier_depends() | 146 | asmlinkage unsigned long __raw_cmpxchg_1_asm(volatile void *ptr, |
147 | unsigned long new, unsigned long old); | ||
148 | asmlinkage unsigned long __raw_cmpxchg_2_asm(volatile void *ptr, | ||
149 | unsigned long new, unsigned long old); | ||
150 | asmlinkage 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 | |||
163 | static 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 | */ | ||
188 | static 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 | ||
149 | struct __xchg_dummy { | 220 | struct __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 | |||
10 | obj-$(CONFIG_PM) += pm.o dpmc_modes.o | 10 | obj-$(CONFIG_PM) += pm.o dpmc_modes.o |
11 | obj-$(CONFIG_CPU_FREQ) += cpufreq.o | 11 | obj-$(CONFIG_CPU_FREQ) += cpufreq.o |
12 | obj-$(CONFIG_CPU_VOLTAGE) += dpmc.o | 12 | obj-$(CONFIG_CPU_VOLTAGE) += dpmc.o |
13 | obj-$(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; |
99 | ENDPROC(_blackfin_dflush_page) | 99 | ENDPROC(_blackfin_dflush_page) |
100 | |||
101 | /* Invalidate the Entire Data cache by | ||
102 | * clearing DMC[1:0] bits | ||
103 | */ | ||
104 | ENTRY(_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; | ||
135 | ENDPROC(_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) | |||
424 | ENTRY(_exception_to_level5) | 423 | ENTRY(_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); |
549 | 0: | 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; |
577 | 0: | 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; |
594 | 1: | 587 | .Lexecve_failed: |
595 | unlink; | 588 | unlink; |
596 | rts; | 589 | rts; |
597 | ENDPROC(_kernel_execve) | 590 | ENDPROC(_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 |
1540 | END(_sys_call_table) | 1538 | END(_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: | 1549 | ENTRY(_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; |
259 | ENDPROC(_real_start) | 256 | ENDPROC(_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 | */ |
64 | unsigned long irq_flags = 0x1f; | 65 | unsigned long irq_flags = 0x1f; |
65 | EXPORT_SYMBOL(irq_flags); | 66 | EXPORT_SYMBOL(irq_flags); |
67 | #endif | ||
66 | 68 | ||
67 | /* The number of spurious interrupts */ | 69 | /* The number of spurious interrupts */ |
68 | atomic_t num_spurious; | 70 | atomic_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 | ||
899 | void __init init_exception_vectors(void) | 909 | void __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 | |||
48 | struct corelock_slot corelock __attribute__ ((__section__(".l2.bss"))); | ||
49 | |||
50 | void __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 | |||
54 | cpumask_t cpu_possible_map; | ||
55 | EXPORT_SYMBOL(cpu_possible_map); | ||
56 | |||
57 | cpumask_t cpu_online_map; | ||
58 | EXPORT_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 | |||
64 | struct blackfin_flush_data { | ||
65 | unsigned long start; | ||
66 | unsigned long end; | ||
67 | }; | ||
68 | |||
69 | void *secondary_stack; | ||
70 | |||
71 | |||
72 | struct smp_call_struct { | ||
73 | void (*func)(void *info); | ||
74 | void *info; | ||
75 | int wait; | ||
76 | cpumask_t pending; | ||
77 | cpumask_t waitmask; | ||
78 | }; | ||
79 | |||
80 | static struct blackfin_flush_data smp_flush_data; | ||
81 | |||
82 | static DEFINE_SPINLOCK(stop_lock); | ||
83 | |||
84 | struct ipi_message { | ||
85 | struct list_head list; | ||
86 | unsigned long type; | ||
87 | struct smp_call_struct call_struct; | ||
88 | }; | ||
89 | |||
90 | struct ipi_message_queue { | ||
91 | struct list_head head; | ||
92 | spinlock_t lock; | ||
93 | unsigned long count; | ||
94 | }; | ||
95 | |||
96 | static DEFINE_PER_CPU(struct ipi_message_queue, ipi_msg_queue); | ||
97 | |||
98 | static 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 | |||
113 | static 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 | |||
124 | static 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 | |||
140 | static 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 | |||
178 | static 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 | |||
190 | int 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 | } | ||
228 | EXPORT_SYMBOL_GPL(smp_call_function); | ||
229 | |||
230 | int 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 | } | ||
268 | EXPORT_SYMBOL_GPL(smp_call_function_single); | ||
269 | |||
270 | void 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 | |||
293 | void 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 | |||
321 | int __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 | |||
349 | static 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 | |||
384 | void __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 | |||
429 | void __init smp_prepare_boot_cpu(void) | ||
430 | { | ||
431 | } | ||
432 | |||
433 | void __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 | |||
440 | void __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 | |||
455 | void 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 | } | ||
463 | EXPORT_SYMBOL_GPL(smp_icache_flush_range_others); | ||
464 | |||
465 | #ifdef __ARCH_SYNC_CORE_DCACHE | ||
466 | unsigned long barrier_mask __attribute__ ((__section__(".l2.bss"))); | ||
467 | |||
468 | void 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 | } | ||
475 | EXPORT_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 | ||