aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorStuart Menefy <stuart.menefy@st.com>2007-11-30 02:12:36 -0500
committerPaul Mundt <lethal@linux-sh.org>2008-01-27 23:18:58 -0500
commit1efe4ce3ca126da77e450d5a83f7201949d76f62 (patch)
treefbae9902aa4103a9e86d06f841d580f24682e7b3 /arch
parent53ff09422e5e7a6d6198b767c8f494e43ec8e3ae (diff)
sh: GUSA atomic rollback support.
This implements kernel-level atomic rollback built on top of gUSA, as an alternative non-IRQ based atomicity method. This is generally a faster method for platforms that are lacking the LL/SC pairs that SH-4A and later use, and is only supportable on legacy cores. Signed-off-by: Stuart Menefy <stuart.menefy@st.com> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/sh/Kconfig12
-rw-r--r--arch/sh/kernel/cpu/sh3/entry.S24
-rw-r--r--arch/sh/kernel/entry-common.S19
-rw-r--r--arch/sh/kernel/process_32.c19
-rw-r--r--arch/sh/kernel/signal_32.c18
5 files changed, 34 insertions, 58 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
693config GUSA 693config 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
707config 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
707endmenu 717endmenu
708 718
709menu "Boot options" 719menu "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
4302: mov k1, r15 ! SP = r1
4311:
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
178work_resched: 178work_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 !
1961:
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 */