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>
This commit is contained in:

committed by
Paul Mundt

parent
53ff09422e
commit
1efe4ce3ca
@@ -13,8 +13,9 @@
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/cpu/mmu_context.h>
|
||||
#include <asm/unistd.h>
|
||||
#include <asm/cpu/mmu_context.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
! NOTE:
|
||||
! 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)
|
||||
! Using k0, k1 for scratch registers (r0_bank1, r1_bank),
|
||||
! save all registers onto stack.
|
||||
!
|
||||
|
||||
#ifdef CONFIG_GUSA
|
||||
! Check for roll back gRB (User and Kernel)
|
||||
mov r15, k0
|
||||
shll k0
|
||||
bf/s 1f
|
||||
shll k0
|
||||
bf/s 1f
|
||||
stc spc, k1
|
||||
stc r0_bank, k0
|
||||
cmp/hs k0, k1 ! test k1 (saved PC) >= k0 (saved r0)
|
||||
bt/s 2f
|
||||
stc r1_bank, k1
|
||||
|
||||
add #-2, k0
|
||||
add r15, k0
|
||||
ldc k0, spc ! PC = saved r0 + r15 - 2
|
||||
2: mov k1, r15 ! SP = r1
|
||||
1:
|
||||
#endif
|
||||
|
||||
stc ssr, k0 ! Is it from kernel space?
|
||||
shll k0 ! Check MD bit (bit30) by shifting it into...
|
||||
shll k0 ! ...the T bit
|
||||
|
@@ -176,25 +176,6 @@ work_notifysig:
|
||||
jmp @r1
|
||||
lds r0, pr
|
||||
work_resched:
|
||||
#if defined(CONFIG_GUSA) && !defined(CONFIG_PREEMPT)
|
||||
! gUSA handling
|
||||
mov.l @(OFF_SP,r15), r0 ! get user space stack pointer
|
||||
mov r0, r1
|
||||
shll r0
|
||||
bf/s 1f
|
||||
shll r0
|
||||
bf/s 1f
|
||||
mov #OFF_PC, r0
|
||||
! SP >= 0xc0000000 : gUSA mark
|
||||
mov.l @(r0,r15), r2 ! get user space PC (program counter)
|
||||
mov.l @(OFF_R0,r15), r3 ! end point
|
||||
cmp/hs r3, r2 ! r2 >= r3?
|
||||
bt 1f
|
||||
add r3, r1 ! rewind point #2
|
||||
mov.l r1, @(r0,r15) ! reset PC to rewind point #2
|
||||
!
|
||||
1:
|
||||
#endif
|
||||
mov.l 1f, r1
|
||||
jsr @r1 ! schedule
|
||||
nop
|
||||
|
@@ -322,25 +322,6 @@ struct task_struct *__switch_to(struct task_struct *prev,
|
||||
unlazy_fpu(prev, task_pt_regs(prev));
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_GUSA) && defined(CONFIG_PREEMPT)
|
||||
{
|
||||
struct pt_regs *regs;
|
||||
|
||||
preempt_disable();
|
||||
regs = task_pt_regs(prev);
|
||||
if (user_mode(regs) && regs->regs[15] >= 0xc0000000) {
|
||||
int offset = (int)regs->regs[15];
|
||||
|
||||
/* Reset stack pointer: clear critical region mark */
|
||||
regs->regs[15] = regs->regs[1];
|
||||
if (regs->pc < regs->regs[0])
|
||||
/* Go to rewind point */
|
||||
regs->pc = regs->regs[0] + offset;
|
||||
}
|
||||
preempt_enable_no_resched();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
/*
|
||||
* Restore the kernel mode register
|
||||
|
@@ -507,24 +507,6 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
|
||||
ctrl_inw(regs->pc - 4));
|
||||
break;
|
||||
}
|
||||
#ifdef CONFIG_GUSA
|
||||
} else {
|
||||
/* gUSA handling */
|
||||
preempt_disable();
|
||||
|
||||
if (regs->regs[15] >= 0xc0000000) {
|
||||
int offset = (int)regs->regs[15];
|
||||
|
||||
/* Reset stack pointer: clear critical region mark */
|
||||
regs->regs[15] = regs->regs[1];
|
||||
if (regs->pc < regs->regs[0])
|
||||
/* Go to rewind point #1 */
|
||||
regs->pc = regs->regs[0] + offset -
|
||||
instruction_size(ctrl_inw(regs->pc-4));
|
||||
}
|
||||
|
||||
preempt_enable_no_resched();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Set up the stack frame */
|
||||
|
Reference in New Issue
Block a user