diff options
Diffstat (limited to 'arch/blackfin/include/asm/entry.h')
| -rw-r--r-- | arch/blackfin/include/asm/entry.h | 128 |
1 files changed, 117 insertions, 11 deletions
diff --git a/arch/blackfin/include/asm/entry.h b/arch/blackfin/include/asm/entry.h index b30a2968e27..4104d5783e2 100644 --- a/arch/blackfin/include/asm/entry.h +++ b/arch/blackfin/include/asm/entry.h @@ -1,3 +1,9 @@ +/* + * Copyright 2004-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + #ifndef __BFIN_ENTRY_H #define __BFIN_ENTRY_H @@ -9,14 +15,6 @@ #define LFLUSH_I_AND_D 0x00000808 #define LSIGTRAP 5 -/* process bits for task_struct.flags */ -#define PF_TRACESYS_OFF 3 -#define PF_TRACESYS_BIT 5 -#define PF_PTRACED_OFF 3 -#define PF_PTRACED_BIT 4 -#define PF_DTRACE_OFF 1 -#define PF_DTRACE_BIT 5 - /* * NOTE! The single-stepping code assumes that all interrupt handlers * start by saving SYSCFG on the stack with their first instruction. @@ -35,21 +33,54 @@ #else # define LOAD_IPIPE_IPEND #endif + +/* + * Workaround for anomalies 05000283 and 05000315 + */ +#if ANOMALY_05000283 || ANOMALY_05000315 +# define ANOMALY_283_315_WORKAROUND(preg, dreg) \ + cc = dreg == dreg; \ + preg.h = HI(CHIPID); \ + preg.l = LO(CHIPID); \ + if cc jump 1f; \ + dreg.l = W[preg]; \ +1: +#else +# define ANOMALY_283_315_WORKAROUND(preg, dreg) +#endif /* ANOMALY_05000283 || ANOMALY_05000315 */ + +#ifndef CONFIG_EXACT_HWERR +/* As a debugging aid - we save IPEND when DEBUG_KERNEL is on, + * otherwise it is a waste of cycles. + */ +# ifndef CONFIG_DEBUG_KERNEL +#define INTERRUPT_ENTRY(N) \ + [--sp] = SYSCFG; \ + [--sp] = P0; /*orig_p0*/ \ + [--sp] = R0; /*orig_r0*/ \ + [--sp] = (R7:0,P5:0); \ + R0 = (N); \ + LOAD_IPIPE_IPEND \ + jump __common_int_entry; +# else /* CONFIG_DEBUG_KERNEL */ #define INTERRUPT_ENTRY(N) \ [--sp] = SYSCFG; \ - \ [--sp] = P0; /*orig_p0*/ \ [--sp] = R0; /*orig_r0*/ \ [--sp] = (R7:0,P5:0); \ + p0.l = lo(IPEND); \ + p0.h = hi(IPEND); \ + r1 = [p0]; \ R0 = (N); \ LOAD_IPIPE_IPEND \ jump __common_int_entry; +# endif /* CONFIG_DEBUG_KERNEL */ /* For timer interrupts, we need to save IPEND, since the user_mode - macro accesses it to determine where to account time. */ + *macro accesses it to determine where to account time. + */ #define TIMER_INTERRUPT_ENTRY(N) \ [--sp] = SYSCFG; \ - \ [--sp] = P0; /*orig_p0*/ \ [--sp] = R0; /*orig_r0*/ \ [--sp] = (R7:0,P5:0); \ @@ -58,6 +89,81 @@ r1 = [p0]; \ R0 = (N); \ jump __common_int_entry; +#else /* CONFIG_EXACT_HWERR is defined */ + +/* if we want hardware error to be exact, we need to do a SSYNC (which forces + * read/writes to complete to the memory controllers), and check to see that + * caused a pending HW error condition. If so, we assume it was caused by user + * space, by setting the same interrupt that we are in (so it goes off again) + * and context restore, and a RTI (without servicing anything). This should + * cause the pending HWERR to fire, and when that is done, this interrupt will + * be re-serviced properly. + * As you can see by the code - we actually need to do two SSYNCS - one to + * make sure the read/writes complete, and another to make sure the hardware + * error is recognized by the core. + * + * The extra nop before the SSYNC is to make sure we work around 05000244, + * since the 283/315 workaround includes a branch to the end + */ +#define INTERRUPT_ENTRY(N) \ + [--sp] = SYSCFG; \ + [--sp] = P0; /*orig_p0*/ \ + [--sp] = R0; /*orig_r0*/ \ + [--sp] = (R7:0,P5:0); \ + R1 = ASTAT; \ + ANOMALY_283_315_WORKAROUND(p0, r0) \ + P0.L = LO(ILAT); \ + P0.H = HI(ILAT); \ + NOP; \ + SSYNC; \ + SSYNC; \ + R0 = [P0]; \ + CC = BITTST(R0, EVT_IVHW_P); \ + IF CC JUMP 1f; \ + ASTAT = R1; \ + p0.l = lo(IPEND); \ + p0.h = hi(IPEND); \ + r1 = [p0]; \ + R0 = (N); \ + LOAD_IPIPE_IPEND \ + jump __common_int_entry; \ +1: ASTAT = R1; \ + RAISE N; \ + (R7:0, P5:0) = [SP++]; \ + SP += 0x8; \ + SYSCFG = [SP++]; \ + CSYNC; \ + RTI; + +#define TIMER_INTERRUPT_ENTRY(N) \ + [--sp] = SYSCFG; \ + [--sp] = P0; /*orig_p0*/ \ + [--sp] = R0; /*orig_r0*/ \ + [--sp] = (R7:0,P5:0); \ + R1 = ASTAT; \ + ANOMALY_283_315_WORKAROUND(p0, r0) \ + P0.L = LO(ILAT); \ + P0.H = HI(ILAT); \ + NOP; \ + SSYNC; \ + SSYNC; \ + R0 = [P0]; \ + CC = BITTST(R0, EVT_IVHW_P); \ + IF CC JUMP 1f; \ + ASTAT = R1; \ + p0.l = lo(IPEND); \ + p0.h = hi(IPEND); \ + r1 = [p0]; \ + R0 = (N); \ + jump __common_int_entry; \ +1: ASTAT = R1; \ + RAISE N; \ + (R7:0, P5:0) = [SP++]; \ + SP += 0x8; \ + SYSCFG = [SP++]; \ + CSYNC; \ + RTI; +#endif /* CONFIG_EXACT_HWERR */ /* This one pushes RETI without using CLI. Interrupts are enabled. */ #define SAVE_CONTEXT_SYSCALL save_context_syscall |
