diff options
-rw-r--r-- | arch/sh/Kconfig | 12 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh3/entry.S | 24 | ||||
-rw-r--r-- | arch/sh/kernel/entry-common.S | 19 | ||||
-rw-r--r-- | arch/sh/kernel/process_32.c | 19 | ||||
-rw-r--r-- | arch/sh/kernel/signal_32.c | 18 | ||||
-rw-r--r-- | include/asm-sh/atomic-grb.h | 169 | ||||
-rw-r--r-- | include/asm-sh/atomic.h | 10 | ||||
-rw-r--r-- | include/asm-sh/bitops-grb.h | 169 | ||||
-rw-r--r-- | include/asm-sh/bitops-irq.h | 91 | ||||
-rw-r--r-- | include/asm-sh/bitops.h | 91 | ||||
-rw-r--r-- | include/asm-sh/cmpxchg-grb.h | 70 | ||||
-rw-r--r-- | include/asm-sh/cmpxchg-irq.h | 40 | ||||
-rw-r--r-- | include/asm-sh/system.h | 40 |
13 files changed, 591 insertions, 181 deletions
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 2dc3b177193c..f645f8416f1c 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig | |||
@@ -692,7 +692,7 @@ source "kernel/Kconfig.preempt" | |||
692 | 692 | ||
693 | config GUSA | 693 | config GUSA |
694 | def_bool y | 694 | def_bool y |
695 | depends on !SMP | 695 | depends on !SMP && SUPERH32 |
696 | help | 696 | help |
697 | This enables support for gUSA (general UserSpace Atomicity). | 697 | This enables support for gUSA (general UserSpace Atomicity). |
698 | This is the default implementation for both UP and non-ll/sc | 698 | This is the default implementation for both UP and non-ll/sc |
@@ -704,6 +704,16 @@ config GUSA | |||
704 | This should only be disabled for special cases where alternate | 704 | This should only be disabled for special cases where alternate |
705 | atomicity implementations exist. | 705 | atomicity implementations exist. |
706 | 706 | ||
707 | config GUSA_RB | ||
708 | bool "Implement atomic operations by roll-back (gRB) (EXPERIMENTAL)" | ||
709 | depends on GUSA && CPU_SH3 || (CPU_SH4 && !CPU_SH4A) | ||
710 | help | ||
711 | Enabling this option will allow the kernel to implement some | ||
712 | atomic operations using a software implemention of load-locked/ | ||
713 | store-conditional (LLSC). On machines which do not have hardware | ||
714 | LLSC, this should be more efficient than the other alternative of | ||
715 | disabling insterrupts around the atomic sequence. | ||
716 | |||
707 | endmenu | 717 | endmenu |
708 | 718 | ||
709 | menu "Boot options" | 719 | menu "Boot options" |
diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S index 0d12a124055c..4004073f98cd 100644 --- a/arch/sh/kernel/cpu/sh3/entry.S +++ b/arch/sh/kernel/cpu/sh3/entry.S | |||
@@ -13,8 +13,9 @@ | |||
13 | #include <linux/linkage.h> | 13 | #include <linux/linkage.h> |
14 | #include <asm/asm-offsets.h> | 14 | #include <asm/asm-offsets.h> |
15 | #include <asm/thread_info.h> | 15 | #include <asm/thread_info.h> |
16 | #include <asm/cpu/mmu_context.h> | ||
17 | #include <asm/unistd.h> | 16 | #include <asm/unistd.h> |
17 | #include <asm/cpu/mmu_context.h> | ||
18 | #include <asm/page.h> | ||
18 | 19 | ||
19 | ! NOTE: | 20 | ! NOTE: |
20 | ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address | 21 | ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address |
@@ -409,6 +410,27 @@ ENTRY(handle_exception) | |||
409 | ! Using k0, k1 for scratch registers (r0_bank1, r1_bank), | 410 | ! Using k0, k1 for scratch registers (r0_bank1, r1_bank), |
410 | ! save all registers onto stack. | 411 | ! save all registers onto stack. |
411 | ! | 412 | ! |
413 | |||
414 | #ifdef CONFIG_GUSA | ||
415 | ! Check for roll back gRB (User and Kernel) | ||
416 | mov r15, k0 | ||
417 | shll k0 | ||
418 | bf/s 1f | ||
419 | shll k0 | ||
420 | bf/s 1f | ||
421 | stc spc, k1 | ||
422 | stc r0_bank, k0 | ||
423 | cmp/hs k0, k1 ! test k1 (saved PC) >= k0 (saved r0) | ||
424 | bt/s 2f | ||
425 | stc r1_bank, k1 | ||
426 | |||
427 | add #-2, k0 | ||
428 | add r15, k0 | ||
429 | ldc k0, spc ! PC = saved r0 + r15 - 2 | ||
430 | 2: mov k1, r15 ! SP = r1 | ||
431 | 1: | ||
432 | #endif | ||
433 | |||
412 | stc ssr, k0 ! Is it from kernel space? | 434 | stc ssr, k0 ! Is it from kernel space? |
413 | shll k0 ! Check MD bit (bit30) by shifting it into... | 435 | shll k0 ! Check MD bit (bit30) by shifting it into... |
414 | shll k0 ! ...the T bit | 436 | shll k0 ! ...the T bit |
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S index 397ac71d97f1..926b2e7b11c1 100644 --- a/arch/sh/kernel/entry-common.S +++ b/arch/sh/kernel/entry-common.S | |||
@@ -176,25 +176,6 @@ work_notifysig: | |||
176 | jmp @r1 | 176 | jmp @r1 |
177 | lds r0, pr | 177 | lds r0, pr |
178 | work_resched: | 178 | work_resched: |
179 | #if defined(CONFIG_GUSA) && !defined(CONFIG_PREEMPT) | ||
180 | ! gUSA handling | ||
181 | mov.l @(OFF_SP,r15), r0 ! get user space stack pointer | ||
182 | mov r0, r1 | ||
183 | shll r0 | ||
184 | bf/s 1f | ||
185 | shll r0 | ||
186 | bf/s 1f | ||
187 | mov #OFF_PC, r0 | ||
188 | ! SP >= 0xc0000000 : gUSA mark | ||
189 | mov.l @(r0,r15), r2 ! get user space PC (program counter) | ||
190 | mov.l @(OFF_R0,r15), r3 ! end point | ||
191 | cmp/hs r3, r2 ! r2 >= r3? | ||
192 | bt 1f | ||
193 | add r3, r1 ! rewind point #2 | ||
194 | mov.l r1, @(r0,r15) ! reset PC to rewind point #2 | ||
195 | ! | ||
196 | 1: | ||
197 | #endif | ||
198 | mov.l 1f, r1 | 179 | mov.l 1f, r1 |
199 | jsr @r1 ! schedule | 180 | jsr @r1 ! schedule |
200 | nop | 181 | nop |
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index b48324867eee..9ab1926b9d10 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c | |||
@@ -322,25 +322,6 @@ struct task_struct *__switch_to(struct task_struct *prev, | |||
322 | unlazy_fpu(prev, task_pt_regs(prev)); | 322 | unlazy_fpu(prev, task_pt_regs(prev)); |
323 | #endif | 323 | #endif |
324 | 324 | ||
325 | #if defined(CONFIG_GUSA) && defined(CONFIG_PREEMPT) | ||
326 | { | ||
327 | struct pt_regs *regs; | ||
328 | |||
329 | preempt_disable(); | ||
330 | regs = task_pt_regs(prev); | ||
331 | if (user_mode(regs) && regs->regs[15] >= 0xc0000000) { | ||
332 | int offset = (int)regs->regs[15]; | ||
333 | |||
334 | /* Reset stack pointer: clear critical region mark */ | ||
335 | regs->regs[15] = regs->regs[1]; | ||
336 | if (regs->pc < regs->regs[0]) | ||
337 | /* Go to rewind point */ | ||
338 | regs->pc = regs->regs[0] + offset; | ||
339 | } | ||
340 | preempt_enable_no_resched(); | ||
341 | } | ||
342 | #endif | ||
343 | |||
344 | #ifdef CONFIG_MMU | 325 | #ifdef CONFIG_MMU |
345 | /* | 326 | /* |
346 | * Restore the kernel mode register | 327 | * Restore the kernel mode register |
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index ca754fd42437..f6b5fbfe75c4 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c | |||
@@ -507,24 +507,6 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, | |||
507 | ctrl_inw(regs->pc - 4)); | 507 | ctrl_inw(regs->pc - 4)); |
508 | break; | 508 | break; |
509 | } | 509 | } |
510 | #ifdef CONFIG_GUSA | ||
511 | } else { | ||
512 | /* gUSA handling */ | ||
513 | preempt_disable(); | ||
514 | |||
515 | if (regs->regs[15] >= 0xc0000000) { | ||
516 | int offset = (int)regs->regs[15]; | ||
517 | |||
518 | /* Reset stack pointer: clear critical region mark */ | ||
519 | regs->regs[15] = regs->regs[1]; | ||
520 | if (regs->pc < regs->regs[0]) | ||
521 | /* Go to rewind point #1 */ | ||
522 | regs->pc = regs->regs[0] + offset - | ||
523 | instruction_size(ctrl_inw(regs->pc-4)); | ||
524 | } | ||
525 | |||
526 | preempt_enable_no_resched(); | ||
527 | #endif | ||
528 | } | 510 | } |
529 | 511 | ||
530 | /* Set up the stack frame */ | 512 | /* Set up the stack frame */ |
diff --git a/include/asm-sh/atomic-grb.h b/include/asm-sh/atomic-grb.h new file mode 100644 index 000000000000..4c5b7dbfcedb --- /dev/null +++ b/include/asm-sh/atomic-grb.h | |||
@@ -0,0 +1,169 @@ | |||
1 | #ifndef __ASM_SH_ATOMIC_GRB_H | ||
2 | #define __ASM_SH_ATOMIC_GRB_H | ||
3 | |||
4 | static inline void atomic_add(int i, atomic_t *v) | ||
5 | { | ||
6 | int tmp; | ||
7 | |||
8 | __asm__ __volatile__ ( | ||
9 | " .align 2 \n\t" | ||
10 | " mova 1f, r0 \n\t" /* r0 = end point */ | ||
11 | " mov r15, r1 \n\t" /* r1 = saved sp */ | ||
12 | " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ | ||
13 | " mov.l @%1, %0 \n\t" /* load old value */ | ||
14 | " add %2, %0 \n\t" /* add */ | ||
15 | " mov.l %0, @%1 \n\t" /* store new value */ | ||
16 | "1: mov r1, r15 \n\t" /* LOGOUT */ | ||
17 | : "=&r" (tmp), | ||
18 | "+r" (v) | ||
19 | : "r" (i) | ||
20 | : "memory" , "r0", "r1"); | ||
21 | } | ||
22 | |||
23 | static inline void atomic_sub(int i, atomic_t *v) | ||
24 | { | ||
25 | int tmp; | ||
26 | |||
27 | __asm__ __volatile__ ( | ||
28 | " .align 2 \n\t" | ||
29 | " mova 1f, r0 \n\t" /* r0 = end point */ | ||
30 | " mov r15, r1 \n\t" /* r1 = saved sp */ | ||
31 | " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ | ||
32 | " mov.l @%1, %0 \n\t" /* load old value */ | ||
33 | " sub %2, %0 \n\t" /* sub */ | ||
34 | " mov.l %0, @%1 \n\t" /* store new value */ | ||
35 | "1: mov r1, r15 \n\t" /* LOGOUT */ | ||
36 | : "=&r" (tmp), | ||
37 | "+r" (v) | ||
38 | : "r" (i) | ||
39 | : "memory" , "r0", "r1"); | ||
40 | } | ||
41 | |||
42 | static inline int atomic_add_return(int i, atomic_t *v) | ||
43 | { | ||
44 | int tmp; | ||
45 | |||
46 | __asm__ __volatile__ ( | ||
47 | " .align 2 \n\t" | ||
48 | " mova 1f, r0 \n\t" /* r0 = end point */ | ||
49 | " mov r15, r1 \n\t" /* r1 = saved sp */ | ||
50 | " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ | ||
51 | " mov.l @%1, %0 \n\t" /* load old value */ | ||
52 | " add %2, %0 \n\t" /* add */ | ||
53 | " mov.l %0, @%1 \n\t" /* store new value */ | ||
54 | "1: mov r1, r15 \n\t" /* LOGOUT */ | ||
55 | : "=&r" (tmp), | ||
56 | "+r" (v) | ||
57 | : "r" (i) | ||
58 | : "memory" , "r0", "r1"); | ||
59 | |||
60 | return tmp; | ||
61 | } | ||
62 | |||
63 | static inline int atomic_sub_return(int i, atomic_t *v) | ||
64 | { | ||
65 | int tmp; | ||
66 | |||
67 | __asm__ __volatile__ ( | ||
68 | " .align 2 \n\t" | ||
69 | " mova 1f, r0 \n\t" /* r0 = end point */ | ||
70 | " mov r15, r1 \n\t" /* r1 = saved sp */ | ||
71 | " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ | ||
72 | " mov.l @%1, %0 \n\t" /* load old value */ | ||
73 | " sub %2, %0 \n\t" /* sub */ | ||
74 | " mov.l %0, @%1 \n\t" /* store new value */ | ||
75 | "1: mov r1, r15 \n\t" /* LOGOUT */ | ||
76 | : "=&r" (tmp), | ||
77 | "+r" (v) | ||
78 | : "r" (i) | ||
79 | : "memory", "r0", "r1"); | ||
80 | |||
81 | return tmp; | ||
82 | } | ||
83 | |||
84 | static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) | ||
85 | { | ||
86 | int tmp; | ||
87 | unsigned int _mask = ~mask; | ||
88 | |||
89 | __asm__ __volatile__ ( | ||
90 | " .align 2 \n\t" | ||
91 | " mova 1f, r0 \n\t" /* r0 = end point */ | ||
92 | " mov r15, r1 \n\t" /* r1 = saved sp */ | ||
93 | " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ | ||
94 | " mov.l @%1, %0 \n\t" /* load old value */ | ||
95 | " and %2, %0 \n\t" /* add */ | ||
96 | " mov.l %0, @%1 \n\t" /* store new value */ | ||
97 | "1: mov r1, r15 \n\t" /* LOGOUT */ | ||
98 | : "=&r" (tmp), | ||
99 | "+r" (v) | ||
100 | : "r" (_mask) | ||
101 | : "memory" , "r0", "r1"); | ||
102 | } | ||
103 | |||
104 | static inline void atomic_set_mask(unsigned int mask, atomic_t *v) | ||
105 | { | ||
106 | int tmp; | ||
107 | |||
108 | __asm__ __volatile__ ( | ||
109 | " .align 2 \n\t" | ||
110 | " mova 1f, r0 \n\t" /* r0 = end point */ | ||
111 | " mov r15, r1 \n\t" /* r1 = saved sp */ | ||
112 | " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ | ||
113 | " mov.l @%1, %0 \n\t" /* load old value */ | ||
114 | " or %2, %0 \n\t" /* or */ | ||
115 | " mov.l %0, @%1 \n\t" /* store new value */ | ||
116 | "1: mov r1, r15 \n\t" /* LOGOUT */ | ||
117 | : "=&r" (tmp), | ||
118 | "+r" (v) | ||
119 | : "r" (mask) | ||
120 | : "memory" , "r0", "r1"); | ||
121 | } | ||
122 | |||
123 | static inline int atomic_cmpxchg(atomic_t *v, int old, int new) | ||
124 | { | ||
125 | int ret; | ||
126 | |||
127 | __asm__ __volatile__ ( | ||
128 | " .align 2 \n\t" | ||
129 | " mova 1f, r0 \n\t" | ||
130 | " nop \n\t" | ||
131 | " mov r15, r1 \n\t" | ||
132 | " mov #-8, r15 \n\t" | ||
133 | " mov.l @%1, %0 \n\t" | ||
134 | " cmp/eq %2, %0 \n\t" | ||
135 | " bf 1f \n\t" | ||
136 | " mov.l %3, @%1 \n\t" | ||
137 | "1: mov r1, r15 \n\t" | ||
138 | : "=&r" (ret) | ||
139 | : "r" (v), "r" (old), "r" (new) | ||
140 | : "memory" , "r0", "r1" , "t"); | ||
141 | |||
142 | return ret; | ||
143 | } | ||
144 | |||
145 | static inline int atomic_add_unless(atomic_t *v, int a, int u) | ||
146 | { | ||
147 | int ret; | ||
148 | unsigned long tmp; | ||
149 | |||
150 | __asm__ __volatile__ ( | ||
151 | " .align 2 \n\t" | ||
152 | " mova 1f, r0 \n\t" | ||
153 | " nop \n\t" | ||
154 | " mov r15, r1 \n\t" | ||
155 | " mov #-12, r15 \n\t" | ||
156 | " mov.l @%2, %1 \n\t" | ||
157 | " mov %1, %0 \n\t" | ||
158 | " cmp/eq %4, %0 \n\t" | ||
159 | " bt/s 1f \n\t" | ||
160 | " add %3, %1 \n\t" | ||
161 | " mov.l %1, @%2 \n\t" | ||
162 | "1: mov r1, r15 \n\t" | ||
163 | : "=&r" (ret), "=&r" (tmp) | ||
164 | : "r" (v), "r" (a), "r" (u) | ||
165 | : "memory" , "r0", "r1" , "t"); | ||
166 | |||
167 | return ret != u; | ||
168 | } | ||
169 | #endif /* __ASM_SH_ATOMIC_GRB_H */ | ||
diff --git a/include/asm-sh/atomic.h b/include/asm-sh/atomic.h index e12570b9339d..c043ef003028 100644 --- a/include/asm-sh/atomic.h +++ b/include/asm-sh/atomic.h | |||
@@ -17,7 +17,9 @@ typedef struct { volatile int counter; } atomic_t; | |||
17 | #include <linux/compiler.h> | 17 | #include <linux/compiler.h> |
18 | #include <asm/system.h> | 18 | #include <asm/system.h> |
19 | 19 | ||
20 | #ifdef CONFIG_CPU_SH4A | 20 | #if defined(CONFIG_GUSA_RB) |
21 | #include <asm/atomic-grb.h> | ||
22 | #elif defined(CONFIG_CPU_SH4A) | ||
21 | #include <asm/atomic-llsc.h> | 23 | #include <asm/atomic-llsc.h> |
22 | #else | 24 | #else |
23 | #include <asm/atomic-irq.h> | 25 | #include <asm/atomic-irq.h> |
@@ -44,6 +46,7 @@ typedef struct { volatile int counter; } atomic_t; | |||
44 | #define atomic_inc(v) atomic_add(1,(v)) | 46 | #define atomic_inc(v) atomic_add(1,(v)) |
45 | #define atomic_dec(v) atomic_sub(1,(v)) | 47 | #define atomic_dec(v) atomic_sub(1,(v)) |
46 | 48 | ||
49 | #ifndef CONFIG_GUSA_RB | ||
47 | static inline int atomic_cmpxchg(atomic_t *v, int old, int new) | 50 | static inline int atomic_cmpxchg(atomic_t *v, int old, int new) |
48 | { | 51 | { |
49 | int ret; | 52 | int ret; |
@@ -58,8 +61,6 @@ static inline int atomic_cmpxchg(atomic_t *v, int old, int new) | |||
58 | return ret; | 61 | return ret; |
59 | } | 62 | } |
60 | 63 | ||
61 | #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) | ||
62 | |||
63 | static inline int atomic_add_unless(atomic_t *v, int a, int u) | 64 | static inline int atomic_add_unless(atomic_t *v, int a, int u) |
64 | { | 65 | { |
65 | int ret; | 66 | int ret; |
@@ -73,6 +74,9 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u) | |||
73 | 74 | ||
74 | return ret != u; | 75 | return ret != u; |
75 | } | 76 | } |
77 | #endif | ||
78 | |||
79 | #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) | ||
76 | #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) | 80 | #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) |
77 | 81 | ||
78 | /* Atomic operations are already serializing on SH */ | 82 | /* Atomic operations are already serializing on SH */ |
diff --git a/include/asm-sh/bitops-grb.h b/include/asm-sh/bitops-grb.h new file mode 100644 index 000000000000..a5907b94395b --- /dev/null +++ b/include/asm-sh/bitops-grb.h | |||
@@ -0,0 +1,169 @@ | |||
1 | #ifndef __ASM_SH_BITOPS_GRB_H | ||
2 | #define __ASM_SH_BITOPS_GRB_H | ||
3 | |||
4 | static inline void set_bit(int nr, volatile void * addr) | ||
5 | { | ||
6 | int mask; | ||
7 | volatile unsigned int *a = addr; | ||
8 | unsigned long tmp; | ||
9 | |||
10 | a += nr >> 5; | ||
11 | mask = 1 << (nr & 0x1f); | ||
12 | |||
13 | __asm__ __volatile__ ( | ||
14 | " .align 2 \n\t" | ||
15 | " mova 1f, r0 \n\t" /* r0 = end point */ | ||
16 | " mov r15, r1 \n\t" /* r1 = saved sp */ | ||
17 | " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ | ||
18 | " mov.l @%1, %0 \n\t" /* load old value */ | ||
19 | " or %2, %0 \n\t" /* or */ | ||
20 | " mov.l %0, @%1 \n\t" /* store new value */ | ||
21 | "1: mov r1, r15 \n\t" /* LOGOUT */ | ||
22 | : "=&r" (tmp), | ||
23 | "+r" (a) | ||
24 | : "r" (mask) | ||
25 | : "memory" , "r0", "r1"); | ||
26 | } | ||
27 | |||
28 | static inline void clear_bit(int nr, volatile void * addr) | ||
29 | { | ||
30 | int mask; | ||
31 | volatile unsigned int *a = addr; | ||
32 | unsigned long tmp; | ||
33 | |||
34 | a += nr >> 5; | ||
35 | mask = ~(1 << (nr & 0x1f)); | ||
36 | __asm__ __volatile__ ( | ||
37 | " .align 2 \n\t" | ||
38 | " mova 1f, r0 \n\t" /* r0 = end point */ | ||
39 | " mov r15, r1 \n\t" /* r1 = saved sp */ | ||
40 | " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ | ||
41 | " mov.l @%1, %0 \n\t" /* load old value */ | ||
42 | " and %2, %0 \n\t" /* and */ | ||
43 | " mov.l %0, @%1 \n\t" /* store new value */ | ||
44 | "1: mov r1, r15 \n\t" /* LOGOUT */ | ||
45 | : "=&r" (tmp), | ||
46 | "+r" (a) | ||
47 | : "r" (mask) | ||
48 | : "memory" , "r0", "r1"); | ||
49 | } | ||
50 | |||
51 | static inline void change_bit(int nr, volatile void * addr) | ||
52 | { | ||
53 | int mask; | ||
54 | volatile unsigned int *a = addr; | ||
55 | unsigned long tmp; | ||
56 | |||
57 | a += nr >> 5; | ||
58 | mask = 1 << (nr & 0x1f); | ||
59 | __asm__ __volatile__ ( | ||
60 | " .align 2 \n\t" | ||
61 | " mova 1f, r0 \n\t" /* r0 = end point */ | ||
62 | " mov r15, r1 \n\t" /* r1 = saved sp */ | ||
63 | " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ | ||
64 | " mov.l @%1, %0 \n\t" /* load old value */ | ||
65 | " xor %2, %0 \n\t" /* xor */ | ||
66 | " mov.l %0, @%1 \n\t" /* store new value */ | ||
67 | "1: mov r1, r15 \n\t" /* LOGOUT */ | ||
68 | : "=&r" (tmp), | ||
69 | "+r" (a) | ||
70 | : "r" (mask) | ||
71 | : "memory" , "r0", "r1"); | ||
72 | } | ||
73 | |||
74 | static inline int test_and_set_bit(int nr, volatile void * addr) | ||
75 | { | ||
76 | int mask, retval; | ||
77 | volatile unsigned int *a = addr; | ||
78 | unsigned long tmp; | ||
79 | |||
80 | a += nr >> 5; | ||
81 | mask = 1 << (nr & 0x1f); | ||
82 | |||
83 | __asm__ __volatile__ ( | ||
84 | " .align 2 \n\t" | ||
85 | " mova 1f, r0 \n\t" /* r0 = end point */ | ||
86 | " mov r15, r1 \n\t" /* r1 = saved sp */ | ||
87 | " mov #-14, r15 \n\t" /* LOGIN: r15 = size */ | ||
88 | " mov.l @%2, %0 \n\t" /* load old value */ | ||
89 | " mov %0, %1 \n\t" | ||
90 | " tst %1, %3 \n\t" /* T = ((*a & mask) == 0) */ | ||
91 | " mov #-1, %1 \n\t" /* retvat = -1 */ | ||
92 | " negc %1, %1 \n\t" /* retval = (mask & *a) != 0 */ | ||
93 | " or %3, %0 \n\t" | ||
94 | " mov.l %0, @%2 \n\t" /* store new value */ | ||
95 | "1: mov r1, r15 \n\t" /* LOGOUT */ | ||
96 | : "=&r" (tmp), | ||
97 | "=&r" (retval), | ||
98 | "+r" (a) | ||
99 | : "r" (mask) | ||
100 | : "memory" , "r0", "r1" ,"t"); | ||
101 | |||
102 | return retval; | ||
103 | } | ||
104 | |||
105 | static inline int test_and_clear_bit(int nr, volatile void * addr) | ||
106 | { | ||
107 | int mask, retval,not_mask; | ||
108 | volatile unsigned int *a = addr; | ||
109 | unsigned long tmp; | ||
110 | |||
111 | a += nr >> 5; | ||
112 | mask = 1 << (nr & 0x1f); | ||
113 | |||
114 | not_mask = ~mask; | ||
115 | |||
116 | __asm__ __volatile__ ( | ||
117 | " .align 2 \n\t" | ||
118 | " mova 1f, r0 \n\t" /* r0 = end point */ | ||
119 | " mov r15, r1 \n\t" /* r1 = saved sp */ | ||
120 | " mov #-14, r15 \n\t" /* LOGIN */ | ||
121 | " mov.l @%2, %0 \n\t" /* load old value */ | ||
122 | " mov %0, %1 \n\t" /* %1 = *a */ | ||
123 | " tst %1, %3 \n\t" /* T = ((*a & mask) == 0) */ | ||
124 | " mov #-1, %1 \n\t" /* retvat = -1 */ | ||
125 | " negc %1, %1 \n\t" /* retval = (mask & *a) != 0 */ | ||
126 | " and %4, %0 \n\t" | ||
127 | " mov.l %0, @%2 \n\t" /* store new value */ | ||
128 | "1: mov r1, r15 \n\t" /* LOGOUT */ | ||
129 | : "=&r" (tmp), | ||
130 | "=&r" (retval), | ||
131 | "+r" (a) | ||
132 | : "r" (mask), | ||
133 | "r" (not_mask) | ||
134 | : "memory" , "r0", "r1", "t"); | ||
135 | |||
136 | return retval; | ||
137 | } | ||
138 | |||
139 | static inline int test_and_change_bit(int nr, volatile void * addr) | ||
140 | { | ||
141 | int mask, retval; | ||
142 | volatile unsigned int *a = addr; | ||
143 | unsigned long tmp; | ||
144 | |||
145 | a += nr >> 5; | ||
146 | mask = 1 << (nr & 0x1f); | ||
147 | |||
148 | __asm__ __volatile__ ( | ||
149 | " .align 2 \n\t" | ||
150 | " mova 1f, r0 \n\t" /* r0 = end point */ | ||
151 | " mov r15, r1 \n\t" /* r1 = saved sp */ | ||
152 | " mov #-14, r15 \n\t" /* LOGIN */ | ||
153 | " mov.l @%2, %0 \n\t" /* load old value */ | ||
154 | " mov %0, %1 \n\t" /* %1 = *a */ | ||
155 | " tst %1, %3 \n\t" /* T = ((*a & mask) == 0) */ | ||
156 | " mov #-1, %1 \n\t" /* retvat = -1 */ | ||
157 | " negc %1, %1 \n\t" /* retval = (mask & *a) != 0 */ | ||
158 | " xor %3, %0 \n\t" | ||
159 | " mov.l %0, @%2 \n\t" /* store new value */ | ||
160 | "1: mov r1, r15 \n\t" /* LOGOUT */ | ||
161 | : "=&r" (tmp), | ||
162 | "=&r" (retval), | ||
163 | "+r" (a) | ||
164 | : "r" (mask) | ||
165 | : "memory" , "r0", "r1", "t"); | ||
166 | |||
167 | return retval; | ||
168 | } | ||
169 | #endif /* __ASM_SH_BITOPS_GRB_H */ | ||
diff --git a/include/asm-sh/bitops-irq.h b/include/asm-sh/bitops-irq.h new file mode 100644 index 000000000000..653a12750584 --- /dev/null +++ b/include/asm-sh/bitops-irq.h | |||
@@ -0,0 +1,91 @@ | |||
1 | #ifndef __ASM_SH_BITOPS_IRQ_H | ||
2 | #define __ASM_SH_BITOPS_IRQ_H | ||
3 | |||
4 | static inline void set_bit(int nr, volatile void *addr) | ||
5 | { | ||
6 | int mask; | ||
7 | volatile unsigned int *a = addr; | ||
8 | unsigned long flags; | ||
9 | |||
10 | a += nr >> 5; | ||
11 | mask = 1 << (nr & 0x1f); | ||
12 | local_irq_save(flags); | ||
13 | *a |= mask; | ||
14 | local_irq_restore(flags); | ||
15 | } | ||
16 | |||
17 | static inline void clear_bit(int nr, volatile void *addr) | ||
18 | { | ||
19 | int mask; | ||
20 | volatile unsigned int *a = addr; | ||
21 | unsigned long flags; | ||
22 | |||
23 | a += nr >> 5; | ||
24 | mask = 1 << (nr & 0x1f); | ||
25 | local_irq_save(flags); | ||
26 | *a &= ~mask; | ||
27 | local_irq_restore(flags); | ||
28 | } | ||
29 | |||
30 | static inline void change_bit(int nr, volatile void *addr) | ||
31 | { | ||
32 | int mask; | ||
33 | volatile unsigned int *a = addr; | ||
34 | unsigned long flags; | ||
35 | |||
36 | a += nr >> 5; | ||
37 | mask = 1 << (nr & 0x1f); | ||
38 | local_irq_save(flags); | ||
39 | *a ^= mask; | ||
40 | local_irq_restore(flags); | ||
41 | } | ||
42 | |||
43 | static inline int test_and_set_bit(int nr, volatile void *addr) | ||
44 | { | ||
45 | int mask, retval; | ||
46 | volatile unsigned int *a = addr; | ||
47 | unsigned long flags; | ||
48 | |||
49 | a += nr >> 5; | ||
50 | mask = 1 << (nr & 0x1f); | ||
51 | local_irq_save(flags); | ||
52 | retval = (mask & *a) != 0; | ||
53 | *a |= mask; | ||
54 | local_irq_restore(flags); | ||
55 | |||
56 | return retval; | ||
57 | } | ||
58 | |||
59 | static inline int test_and_clear_bit(int nr, volatile void *addr) | ||
60 | { | ||
61 | int mask, retval; | ||
62 | volatile unsigned int *a = addr; | ||
63 | unsigned long flags; | ||
64 | |||
65 | a += nr >> 5; | ||
66 | mask = 1 << (nr & 0x1f); | ||
67 | local_irq_save(flags); | ||
68 | retval = (mask & *a) != 0; | ||
69 | *a &= ~mask; | ||
70 | local_irq_restore(flags); | ||
71 | |||
72 | return retval; | ||
73 | } | ||
74 | |||
75 | static inline int test_and_change_bit(int nr, volatile void *addr) | ||
76 | { | ||
77 | int mask, retval; | ||
78 | volatile unsigned int *a = addr; | ||
79 | unsigned long flags; | ||
80 | |||
81 | a += nr >> 5; | ||
82 | mask = 1 << (nr & 0x1f); | ||
83 | local_irq_save(flags); | ||
84 | retval = (mask & *a) != 0; | ||
85 | *a ^= mask; | ||
86 | local_irq_restore(flags); | ||
87 | |||
88 | return retval; | ||
89 | } | ||
90 | |||
91 | #endif /* __ASM_SH_BITOPS_IRQ_H */ | ||
diff --git a/include/asm-sh/bitops.h b/include/asm-sh/bitops.h index a7bd81a7f064..b6ba5a60dec2 100644 --- a/include/asm-sh/bitops.h +++ b/include/asm-sh/bitops.h | |||
@@ -11,97 +11,18 @@ | |||
11 | /* For __swab32 */ | 11 | /* For __swab32 */ |
12 | #include <asm/byteorder.h> | 12 | #include <asm/byteorder.h> |
13 | 13 | ||
14 | static inline void set_bit(int nr, volatile void * addr) | 14 | #ifdef CONFIG_GUSA_RB |
15 | { | 15 | #include <asm/bitops-grb.h> |
16 | int mask; | 16 | #else |
17 | volatile unsigned int *a = addr; | 17 | #include <asm/bitops-irq.h> |
18 | unsigned long flags; | 18 | #endif |
19 | 19 | ||
20 | a += nr >> 5; | ||
21 | mask = 1 << (nr & 0x1f); | ||
22 | local_irq_save(flags); | ||
23 | *a |= mask; | ||
24 | local_irq_restore(flags); | ||
25 | } | ||
26 | 20 | ||
27 | /* | 21 | /* |
28 | * clear_bit() doesn't provide any barrier for the compiler. | 22 | * clear_bit() doesn't provide any barrier for the compiler. |
29 | */ | 23 | */ |
30 | #define smp_mb__before_clear_bit() barrier() | 24 | #define smp_mb__before_clear_bit() barrier() |
31 | #define smp_mb__after_clear_bit() barrier() | 25 | #define smp_mb__after_clear_bit() barrier() |
32 | static inline void clear_bit(int nr, volatile void * addr) | ||
33 | { | ||
34 | int mask; | ||
35 | volatile unsigned int *a = addr; | ||
36 | unsigned long flags; | ||
37 | |||
38 | a += nr >> 5; | ||
39 | mask = 1 << (nr & 0x1f); | ||
40 | local_irq_save(flags); | ||
41 | *a &= ~mask; | ||
42 | local_irq_restore(flags); | ||
43 | } | ||
44 | |||
45 | static inline void change_bit(int nr, volatile void * addr) | ||
46 | { | ||
47 | int mask; | ||
48 | volatile unsigned int *a = addr; | ||
49 | unsigned long flags; | ||
50 | |||
51 | a += nr >> 5; | ||
52 | mask = 1 << (nr & 0x1f); | ||
53 | local_irq_save(flags); | ||
54 | *a ^= mask; | ||
55 | local_irq_restore(flags); | ||
56 | } | ||
57 | |||
58 | static inline int test_and_set_bit(int nr, volatile void * addr) | ||
59 | { | ||
60 | int mask, retval; | ||
61 | volatile unsigned int *a = addr; | ||
62 | unsigned long flags; | ||
63 | |||
64 | a += nr >> 5; | ||
65 | mask = 1 << (nr & 0x1f); | ||
66 | local_irq_save(flags); | ||
67 | retval = (mask & *a) != 0; | ||
68 | *a |= mask; | ||
69 | local_irq_restore(flags); | ||
70 | |||
71 | return retval; | ||
72 | } | ||
73 | |||
74 | static inline int test_and_clear_bit(int nr, volatile void * addr) | ||
75 | { | ||
76 | int mask, retval; | ||
77 | volatile unsigned int *a = addr; | ||
78 | unsigned long flags; | ||
79 | |||
80 | a += nr >> 5; | ||
81 | mask = 1 << (nr & 0x1f); | ||
82 | local_irq_save(flags); | ||
83 | retval = (mask & *a) != 0; | ||
84 | *a &= ~mask; | ||
85 | local_irq_restore(flags); | ||
86 | |||
87 | return retval; | ||
88 | } | ||
89 | |||
90 | static inline int test_and_change_bit(int nr, volatile void * addr) | ||
91 | { | ||
92 | int mask, retval; | ||
93 | volatile unsigned int *a = addr; | ||
94 | unsigned long flags; | ||
95 | |||
96 | a += nr >> 5; | ||
97 | mask = 1 << (nr & 0x1f); | ||
98 | local_irq_save(flags); | ||
99 | retval = (mask & *a) != 0; | ||
100 | *a ^= mask; | ||
101 | local_irq_restore(flags); | ||
102 | |||
103 | return retval; | ||
104 | } | ||
105 | 26 | ||
106 | #include <asm-generic/bitops/non-atomic.h> | 27 | #include <asm-generic/bitops/non-atomic.h> |
107 | 28 | ||
diff --git a/include/asm-sh/cmpxchg-grb.h b/include/asm-sh/cmpxchg-grb.h new file mode 100644 index 000000000000..e2681abe764f --- /dev/null +++ b/include/asm-sh/cmpxchg-grb.h | |||
@@ -0,0 +1,70 @@ | |||
1 | #ifndef __ASM_SH_CMPXCHG_GRB_H | ||
2 | #define __ASM_SH_CMPXCHG_GRB_H | ||
3 | |||
4 | static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val) | ||
5 | { | ||
6 | unsigned long retval; | ||
7 | |||
8 | __asm__ __volatile__ ( | ||
9 | " .align 2 \n\t" | ||
10 | " mova 1f, r0 \n\t" /* r0 = end point */ | ||
11 | " nop \n\t" | ||
12 | " mov r15, r1 \n\t" /* r1 = saved sp */ | ||
13 | " mov #-4, r15 \n\t" /* LOGIN */ | ||
14 | " mov.l @%1, %0 \n\t" /* load old value */ | ||
15 | " mov.l %2, @%1 \n\t" /* store new value */ | ||
16 | "1: mov r1, r15 \n\t" /* LOGOUT */ | ||
17 | : "=&r" (retval), | ||
18 | "+r" (m) | ||
19 | : "r" (val) | ||
20 | : "memory", "r0", "r1"); | ||
21 | |||
22 | return retval; | ||
23 | } | ||
24 | |||
25 | static inline unsigned long xchg_u8(volatile u8 *m, unsigned long val) | ||
26 | { | ||
27 | unsigned long retval; | ||
28 | |||
29 | __asm__ __volatile__ ( | ||
30 | " .align 2 \n\t" | ||
31 | " mova 1f, r0 \n\t" /* r0 = end point */ | ||
32 | " mov r15, r1 \n\t" /* r1 = saved sp */ | ||
33 | " mov #-6, r15 \n\t" /* LOGIN */ | ||
34 | " mov.b @%1, %0 \n\t" /* load old value */ | ||
35 | " extu.b %0, %0 \n\t" /* extend as unsigned */ | ||
36 | " mov.b %2, @%1 \n\t" /* store new value */ | ||
37 | "1: mov r1, r15 \n\t" /* LOGOUT */ | ||
38 | : "=&r" (retval), | ||
39 | "+r" (m) | ||
40 | : "r" (val) | ||
41 | : "memory" , "r0", "r1"); | ||
42 | |||
43 | return retval; | ||
44 | } | ||
45 | |||
46 | static inline unsigned long __cmpxchg_u32(volatile int *m, unsigned long old, | ||
47 | unsigned long new) | ||
48 | { | ||
49 | unsigned long retval; | ||
50 | |||
51 | __asm__ __volatile__ ( | ||
52 | " .align 2 \n\t" | ||
53 | " mova 1f, r0 \n\t" /* r0 = end point */ | ||
54 | " nop \n\t" | ||
55 | " mov r15, r1 \n\t" /* r1 = saved sp */ | ||
56 | " mov #-8, r15 \n\t" /* LOGIN */ | ||
57 | " mov.l @%1, %0 \n\t" /* load old value */ | ||
58 | " cmp/eq %0, %2 \n\t" | ||
59 | " bf 1f \n\t" /* if not equal */ | ||
60 | " mov.l %2, @%1 \n\t" /* store new value */ | ||
61 | "1: mov r1, r15 \n\t" /* LOGOUT */ | ||
62 | : "=&r" (retval), | ||
63 | "+r" (m) | ||
64 | : "r" (new) | ||
65 | : "memory" , "r0", "r1", "t"); | ||
66 | |||
67 | return retval; | ||
68 | } | ||
69 | |||
70 | #endif /* __ASM_SH_CMPXCHG_GRB_H */ | ||
diff --git a/include/asm-sh/cmpxchg-irq.h b/include/asm-sh/cmpxchg-irq.h new file mode 100644 index 000000000000..43049ec0554b --- /dev/null +++ b/include/asm-sh/cmpxchg-irq.h | |||
@@ -0,0 +1,40 @@ | |||
1 | #ifndef __ASM_SH_CMPXCHG_IRQ_H | ||
2 | #define __ASM_SH_CMPXCHG_IRQ_H | ||
3 | |||
4 | static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val) | ||
5 | { | ||
6 | unsigned long flags, retval; | ||
7 | |||
8 | local_irq_save(flags); | ||
9 | retval = *m; | ||
10 | *m = val; | ||
11 | local_irq_restore(flags); | ||
12 | return retval; | ||
13 | } | ||
14 | |||
15 | static inline unsigned long xchg_u8(volatile u8 *m, unsigned long val) | ||
16 | { | ||
17 | unsigned long flags, retval; | ||
18 | |||
19 | local_irq_save(flags); | ||
20 | retval = *m; | ||
21 | *m = val & 0xff; | ||
22 | local_irq_restore(flags); | ||
23 | return retval; | ||
24 | } | ||
25 | |||
26 | static inline unsigned long __cmpxchg_u32(volatile int *m, unsigned long old, | ||
27 | unsigned long new) | ||
28 | { | ||
29 | __u32 retval; | ||
30 | unsigned long flags; | ||
31 | |||
32 | local_irq_save(flags); | ||
33 | retval = *m; | ||
34 | if (retval == old) | ||
35 | *m = new; | ||
36 | local_irq_restore(flags); /* implies memory barrier */ | ||
37 | return retval; | ||
38 | } | ||
39 | |||
40 | #endif /* __ASM_SH_CMPXCHG_IRQ_H */ | ||
diff --git a/include/asm-sh/system.h b/include/asm-sh/system.h index ad3d2a636130..969f3d4afe2a 100644 --- a/include/asm-sh/system.h +++ b/include/asm-sh/system.h | |||
@@ -68,27 +68,11 @@ | |||
68 | 68 | ||
69 | #define set_mb(var, value) do { (void)xchg(&var, value); } while (0) | 69 | #define set_mb(var, value) do { (void)xchg(&var, value); } while (0) |
70 | 70 | ||
71 | static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val) | 71 | #ifdef CONFIG_GUSA_RB |
72 | { | 72 | #include <asm/cmpxchg-grb.h> |
73 | unsigned long flags, retval; | 73 | #else |
74 | 74 | #include <asm/cmpxchg-irq.h> | |
75 | local_irq_save(flags); | 75 | #endif |
76 | retval = *m; | ||
77 | *m = val; | ||
78 | local_irq_restore(flags); | ||
79 | return retval; | ||
80 | } | ||
81 | |||
82 | static inline unsigned long xchg_u8(volatile u8 *m, unsigned long val) | ||
83 | { | ||
84 | unsigned long flags, retval; | ||
85 | |||
86 | local_irq_save(flags); | ||
87 | retval = *m; | ||
88 | *m = val & 0xff; | ||
89 | local_irq_restore(flags); | ||
90 | return retval; | ||
91 | } | ||
92 | 76 | ||
93 | extern void __xchg_called_with_bad_pointer(void); | 77 | extern void __xchg_called_with_bad_pointer(void); |
94 | 78 | ||
@@ -115,20 +99,6 @@ extern void __xchg_called_with_bad_pointer(void); | |||
115 | #define xchg(ptr,x) \ | 99 | #define xchg(ptr,x) \ |
116 | ((__typeof__(*(ptr)))__xchg((ptr),(unsigned long)(x), sizeof(*(ptr)))) | 100 | ((__typeof__(*(ptr)))__xchg((ptr),(unsigned long)(x), sizeof(*(ptr)))) |
117 | 101 | ||
118 | static inline unsigned long __cmpxchg_u32(volatile int * m, unsigned long old, | ||
119 | unsigned long new) | ||
120 | { | ||
121 | __u32 retval; | ||
122 | unsigned long flags; | ||
123 | |||
124 | local_irq_save(flags); | ||
125 | retval = *m; | ||
126 | if (retval == old) | ||
127 | *m = new; | ||
128 | local_irq_restore(flags); /* implies memory barrier */ | ||
129 | return retval; | ||
130 | } | ||
131 | |||
132 | /* This function doesn't exist, so you'll get a linker error | 102 | /* This function doesn't exist, so you'll get a linker error |
133 | * if something tries to do an invalid cmpxchg(). */ | 103 | * if something tries to do an invalid cmpxchg(). */ |
134 | extern void __cmpxchg_called_with_bad_pointer(void); | 104 | extern void __cmpxchg_called_with_bad_pointer(void); |