diff options
Diffstat (limited to 'arch/blackfin/include/asm/entry.h')
| -rw-r--r-- | arch/blackfin/include/asm/entry.h | 92 | 
1 files changed, 89 insertions, 3 deletions
diff --git a/arch/blackfin/include/asm/entry.h b/arch/blackfin/include/asm/entry.h index b30a2968e27..ec58efc130e 100644 --- a/arch/blackfin/include/asm/entry.h +++ b/arch/blackfin/include/asm/entry.h @@ -35,21 +35,39 @@  #else  # define LOAD_IPIPE_IPEND  #endif + +#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 +76,74 @@      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. + */ +#define INTERRUPT_ENTRY(N)						\ +    SSYNC;								\ +    SSYNC;								\ +    [--sp] = SYSCFG;							\ +    [--sp] = P0;	/*orig_p0*/					\ +    [--sp] = R0;	/*orig_r0*/					\ +    [--sp] = (R7:0,P5:0);						\ +    R1 = ASTAT;								\ +    P0.L = LO(ILAT);							\ +    P0.H = HI(ILAT);							\ +    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)					\ +    SSYNC;								\ +    SSYNC;								\ +    [--sp] = SYSCFG;							\ +    [--sp] = P0;	/*orig_p0*/					\ +    [--sp] = R0;	/*orig_r0*/					\ +    [--sp] = (R7:0,P5:0);						\ +    R1 = ASTAT;								\ +    P0.L = LO(ILAT);							\ +    P0.H = HI(ILAT);							\ +    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  |