X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=arch%2Fblackfin%2Fmach-common%2Finterrupt.S;h=c754ff74bd5d8800fb4709c8d24a162b8b5e7095;hb=7a7967dc1b606f8c88e33bbec773bf82b4a52e6e;hp=14ef800a564d811a58335b782b0c0e3baa3251c0;hpb=1aafd9091226a02b481298315f959f777294684e;p=safe%2Fjmp%2Flinux-2.6 diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S index 14ef800..c754ff7 100644 --- a/arch/blackfin/mach-common/interrupt.S +++ b/arch/blackfin/mach-common/interrupt.S @@ -29,14 +29,17 @@ */ #include -#include -#include +#include #include #include #include #include +#include +#include -#include +#include + +.extern _ret_from_exception #ifdef CONFIG_I_ENTRY_L1 .section .l1.text @@ -46,30 +49,6 @@ .align 4 /* just in case */ -/* - * initial interrupt handlers - */ - -#ifndef CONFIG_KGDB - /* interrupt routine for emulation - 0 */ - /* Currently used only if GDB stub is not in - invalid */ - /* gdb-stub set the evt itself */ - /* save registers for post-mortem only */ -ENTRY(_evt_emulation) - SAVE_ALL_SYS -#ifdef CONFIG_FRAME_POINTER - fp = 0; -#endif - r0 = IRQ_EMU; - r1 = sp; - SP += -12; - call _irq_panic; - SP += 12; - /* - GDB stub fills this in by itself (if defined) */ - rte; -ENDPROC(_evt_emulation) -#endif - /* Common interrupt entry code. First we do CLI, then push * RETI, to keep interrupts disabled, but to allow this state to be changed * by local_bh_enable. @@ -142,16 +121,23 @@ __common_int_entry: #if ANOMALY_05000283 || ANOMALY_05000315 cc = r7 == r7; - p5.h = 0xffc0; - p5.l = 0x0014; + p5.h = HI(CHIPID); + p5.l = LO(CHIPID); if cc jump 1f; r7.l = W[p5]; 1: #endif r1 = sp; SP += -12; +#ifdef CONFIG_IPIPE + call ___ipipe_grab_irq + SP += 12; + cc = r0 == 0; + if cc jump .Lcommon_restore_context; +#else /* CONFIG_IPIPE */ call _do_irq; SP += 12; +#endif /* CONFIG_IPIPE */ call _return_from_int; .Lcommon_restore_context: RESTORE_CONTEXT @@ -159,69 +145,89 @@ __common_int_entry: /* interrupt routine for ivhw - 5 */ ENTRY(_evt_ivhw) - SAVE_CONTEXT + /* In case a single action kicks off multiple memory transactions, (like + * a cache line fetch, - this can cause multiple hardware errors, let's + * catch them all. First - make sure all the actions are complete, and + * the core sees the hardware errors. + */ + SSYNC; + SSYNC; + + SAVE_ALL_SYS #ifdef CONFIG_FRAME_POINTER fp = 0; #endif -#if ANOMALY_05000283 + +#if ANOMALY_05000283 || ANOMALY_05000315 cc = r7 == r7; - p5.h = 0xffc0; - p5.l = 0x0014; + p5.h = HI(CHIPID); + p5.l = LO(CHIPID); if cc jump 1f; r7.l = W[p5]; 1: #endif - trace_buffer_stop(p0, r0); - - r0 = IRQ_HWERR; - r1 = sp; - -#ifdef CONFIG_HARDWARE_PM - r7 = SEQSTAT; - r7 = r7 >>> 0xe; - r6 = 0x1F; - r7 = r7 & r6; - r5 = 0x12; - cc = r7 == r5; - if cc jump .Lcall_do_ovf; /* deal with performance counter overflow */ -#endif + /* Handle all stacked hardware errors + * To make sure we don't hang forever, only do it 10 times + */ + R0 = 0; + R2 = 10; +1: + P0.L = LO(ILAT); + P0.H = HI(ILAT); + R1 = [P0]; + CC = BITTST(R1, EVT_IVHW_P); + IF ! CC JUMP 2f; + /* OK a hardware error is pending - clear it */ + R1 = EVT_IVHW_P; + [P0] = R1; + R0 += 1; + CC = R1 == R2; + if CC JUMP 2f; + JUMP 1b; +2: + # We are going to dump something out, so make sure we print IPEND properly + p2.l = lo(IPEND); + p2.h = hi(IPEND); + r0 = [p2]; + [sp + PT_IPEND] = r0; - SP += -12; - call _irq_panic; - SP += 12; - rti; -#ifdef CONFIG_HARDWARE_PM -.Lcall_do_ovf: + /* set the EXCAUSE to HWERR for trap_c */ + r0 = [sp + PT_SEQSTAT]; + R1.L = LO(VEC_HWERR); + R1.H = HI(VEC_HWERR); + R0 = R0 | R1; + [sp + PT_SEQSTAT] = R0; + r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */ SP += -12; - call _pm_overflow; + call _trap_c; SP += 12; - jump .Lcommon_restore_context; +#ifdef EBIU_ERRMST + /* make sure EBIU_ERRMST is clear */ + p0.l = LO(EBIU_ERRMST); + p0.h = HI(EBIU_ERRMST); + r0.l = (CORE_ERROR | CORE_MERROR); + w[p0] = r0.l; #endif -/* interrupt routine for evt2 - 2. This is NMI. */ -ENTRY(_evt_evt2) - SAVE_CONTEXT -#ifdef CONFIG_FRAME_POINTER - fp = 0; -#endif -#if ANOMALY_05000283 - cc = r7 == r7; - p5.h = 0xffc0; - p5.l = 0x0014; - if cc jump 1f; - r7.l = W[p5]; -1: -#endif - r0 = IRQ_NMI; - r1 = sp; - SP += -12; - call _asm_do_IRQ; - SP += 12; - RESTORE_CONTEXT + call _ret_from_exception; + +.Lcommon_restore_all_sys: + RESTORE_ALL_SYS + rti; +ENDPROC(_evt_ivhw) + +/* Interrupt routine for evt2 (NMI). + * We don't actually use this, so just return. + * For inner circle type details, please see: + * http://docs.blackfin.uclinux.org/doku.php?id=linux-kernel:nmi + */ +ENTRY(_evt_nmi) +.weak _evt_nmi rtn; +ENDPROC(_evt_nmi) /* interrupt routine for core timer - 6 */ ENTRY(_evt_timer) @@ -253,3 +259,61 @@ ENTRY(_evt_system_call) call _system_call; jump .Lcommon_restore_context; ENDPROC(_evt_system_call) + +#ifdef CONFIG_IPIPE +/* + * __ipipe_call_irqtail: lowers the current priority level to EVT15 + * before running a user-defined routine, then raises the priority + * level to EVT14 to prepare the caller for a normal interrupt + * return through RTI. + * + * We currently use this facility in two occasions: + * + * - to branch to __ipipe_irq_tail_hook as requested by a high + * priority domain after the pipeline delivered an interrupt, + * e.g. such as Xenomai, in order to start its rescheduling + * procedure, since we may not switch tasks when IRQ levels are + * nested on the Blackfin, so we have to fake an interrupt return + * so that we may reschedule immediately. + * + * - to branch to sync_root_irqs, in order to play any interrupt + * pending for the root domain (i.e. the Linux kernel). This lowers + * the core priority level enough so that Linux IRQ handlers may + * never delay interrupts handled by high priority domains; we defer + * those handlers until this point instead. This is a substitute + * to using a threaded interrupt model for the Linux kernel. + * + * r0: address of user-defined routine + * context: caller must have preempted EVT15, hw interrupts must be off. + */ +ENTRY(___ipipe_call_irqtail) + p0 = r0; + r0.l = 1f; + r0.h = 1f; + reti = r0; + rti; +1: + [--sp] = rets; + [--sp] = ( r7:4, p5:3 ); + sp += -12; + call (p0); + sp += 12; + ( r7:4, p5:3 ) = [sp++]; + rets = [sp++]; + +#ifdef CONFIG_DEBUG_HWERR + /* enable irq14 & hwerr interrupt, until we transition to _evt_evt14 */ + r0 = (EVT_IVG14 | EVT_IVHW | \ + EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU); +#else + /* Only enable irq14 interrupt, until we transition to _evt_evt14 */ + r0 = (EVT_IVG14 | \ + EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU); +#endif + sti r0; + raise 14; /* Branches to _evt_evt14 */ +2: + jump 2b; /* Likely paranoid. */ +ENDPROC(___ipipe_call_irqtail) + +#endif /* CONFIG_IPIPE */