| Robin Getz | 96f1050 | 2009-09-24 14:11:24 +0000 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright 2004-2009 Analog Devices Inc. | 
 | 3 |  * | 
 | 4 |  * Licensed under the GPL-2 or later. | 
 | 5 |  */ | 
 | 6 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 7 | #ifndef __BFIN_ENTRY_H | 
 | 8 | #define __BFIN_ENTRY_H | 
 | 9 |  | 
 | 10 | #include <asm/setup.h> | 
 | 11 | #include <asm/page.h> | 
 | 12 |  | 
 | 13 | #ifdef __ASSEMBLY__ | 
 | 14 |  | 
 | 15 | #define	LFLUSH_I_AND_D	0x00000808 | 
 | 16 | #define	LSIGTRAP	5 | 
 | 17 |  | 
| Bernd Schmidt | 0893f12 | 2008-05-07 11:41:26 +0800 | [diff] [blame] | 18 | /* | 
 | 19 |  * NOTE!  The single-stepping code assumes that all interrupt handlers | 
 | 20 |  * start by saving SYSCFG on the stack with their first instruction. | 
 | 21 |  */ | 
 | 22 |  | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 23 | /* This one is used for exceptions, emulation, and NMI.  It doesn't push | 
 | 24 |    RETI and doesn't do cli.  */ | 
 | 25 | #define SAVE_ALL_SYS		save_context_no_interrupts | 
 | 26 | /* This is used for all normal interrupts.  It saves a minimum of registers | 
 | 27 |    to the stack, loads the IRQ number, and jumps to common code.  */ | 
| Yi Li | 6a01f23 | 2009-01-07 23:14:39 +0800 | [diff] [blame] | 28 | #ifdef CONFIG_IPIPE | 
 | 29 | # define LOAD_IPIPE_IPEND \ | 
 | 30 | 	P0.l = lo(IPEND); \ | 
 | 31 | 	P0.h = hi(IPEND); \ | 
 | 32 | 	R1 = [P0]; | 
 | 33 | #else | 
 | 34 | # define LOAD_IPIPE_IPEND | 
 | 35 | #endif | 
| Robin Getz | b9a3899 | 2009-05-18 18:33:26 +0000 | [diff] [blame] | 36 |  | 
| Robin Getz | dedfd5d | 2009-08-26 15:54:10 +0000 | [diff] [blame] | 37 | /* | 
 | 38 |  * Workaround for anomalies 05000283 and 05000315 | 
 | 39 |  */ | 
 | 40 | #if ANOMALY_05000283 || ANOMALY_05000315 | 
 | 41 | # define ANOMALY_283_315_WORKAROUND(preg, dreg)		\ | 
 | 42 | 	cc = dreg == dreg;				\ | 
 | 43 | 	preg.h = HI(CHIPID);				\ | 
 | 44 | 	preg.l = LO(CHIPID);				\ | 
 | 45 | 	if cc jump 1f;					\ | 
 | 46 | 	dreg.l = W[preg];				\ | 
 | 47 | 1: | 
 | 48 | #else | 
 | 49 | # define ANOMALY_283_315_WORKAROUND(preg, dreg) | 
 | 50 | #endif /* ANOMALY_05000283 || ANOMALY_05000315 */ | 
 | 51 |  | 
| Robin Getz | b9a3899 | 2009-05-18 18:33:26 +0000 | [diff] [blame] | 52 | #ifndef CONFIG_EXACT_HWERR | 
 | 53 | /* As a debugging aid - we save IPEND when DEBUG_KERNEL is on, | 
 | 54 |  * otherwise it is a waste of cycles. | 
 | 55 |  */ | 
 | 56 | # ifndef CONFIG_DEBUG_KERNEL | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 57 | #define INTERRUPT_ENTRY(N)						\ | 
 | 58 |     [--sp] = SYSCFG;							\ | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 59 |     [--sp] = P0;	/*orig_p0*/					\ | 
 | 60 |     [--sp] = R0;	/*orig_r0*/					\ | 
 | 61 |     [--sp] = (R7:0,P5:0);						\ | 
 | 62 |     R0 = (N);								\ | 
| Yi Li | 6a01f23 | 2009-01-07 23:14:39 +0800 | [diff] [blame] | 63 |     LOAD_IPIPE_IPEND							\ | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 64 |     jump __common_int_entry; | 
| Robin Getz | b9a3899 | 2009-05-18 18:33:26 +0000 | [diff] [blame] | 65 | # else /* CONFIG_DEBUG_KERNEL */ | 
 | 66 | #define INTERRUPT_ENTRY(N)						\ | 
 | 67 |     [--sp] = SYSCFG;							\ | 
 | 68 |     [--sp] = P0;	/*orig_p0*/					\ | 
 | 69 |     [--sp] = R0;	/*orig_r0*/					\ | 
 | 70 |     [--sp] = (R7:0,P5:0);						\ | 
 | 71 |     p0.l = lo(IPEND);							\ | 
 | 72 |     p0.h = hi(IPEND);							\ | 
 | 73 |     r1 = [p0];								\ | 
 | 74 |     R0 = (N);								\ | 
 | 75 |     LOAD_IPIPE_IPEND							\ | 
 | 76 |     jump __common_int_entry; | 
 | 77 | # endif /* CONFIG_DEBUG_KERNEL */ | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 78 |  | 
 | 79 | /* For timer interrupts, we need to save IPEND, since the user_mode | 
| Robin Getz | b9a3899 | 2009-05-18 18:33:26 +0000 | [diff] [blame] | 80 |  *macro accesses it to determine where to account time. | 
 | 81 |  */ | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 82 | #define TIMER_INTERRUPT_ENTRY(N)					\ | 
 | 83 |     [--sp] = SYSCFG;							\ | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 84 |     [--sp] = P0;	/*orig_p0*/					\ | 
 | 85 |     [--sp] = R0;	/*orig_r0*/					\ | 
 | 86 |     [--sp] = (R7:0,P5:0);						\ | 
 | 87 |     p0.l = lo(IPEND);							\ | 
 | 88 |     p0.h = hi(IPEND);							\ | 
 | 89 |     r1 = [p0];								\ | 
 | 90 |     R0 = (N);								\ | 
 | 91 |     jump __common_int_entry; | 
| Robin Getz | b9a3899 | 2009-05-18 18:33:26 +0000 | [diff] [blame] | 92 | #else /* CONFIG_EXACT_HWERR is defined */ | 
 | 93 |  | 
 | 94 | /* if we want hardware error to be exact, we need to do a SSYNC (which forces | 
 | 95 |  * read/writes to complete to the memory controllers), and check to see that | 
 | 96 |  * caused a pending HW error condition. If so, we assume it was caused by user | 
 | 97 |  * space, by setting the same interrupt that we are in (so it goes off again) | 
 | 98 |  * and context restore, and a RTI (without servicing anything). This should | 
 | 99 |  * cause the pending HWERR to fire, and when that is done, this interrupt will | 
 | 100 |  * be re-serviced properly. | 
 | 101 |  * As you can see by the code - we actually need to do two SSYNCS - one to | 
 | 102 |  * make sure the read/writes complete, and another to make sure the hardware | 
 | 103 |  * error is recognized by the core. | 
| Robin Getz | dedfd5d | 2009-08-26 15:54:10 +0000 | [diff] [blame] | 104 |  * | 
 | 105 |  * The extra nop before the SSYNC is to make sure we work around 05000244, | 
 | 106 |  * since the 283/315 workaround includes a branch to the end | 
| Robin Getz | b9a3899 | 2009-05-18 18:33:26 +0000 | [diff] [blame] | 107 |  */ | 
 | 108 | #define INTERRUPT_ENTRY(N)						\ | 
| Robin Getz | b9a3899 | 2009-05-18 18:33:26 +0000 | [diff] [blame] | 109 |     [--sp] = SYSCFG;							\ | 
 | 110 |     [--sp] = P0;	/*orig_p0*/					\ | 
 | 111 |     [--sp] = R0;	/*orig_r0*/					\ | 
 | 112 |     [--sp] = (R7:0,P5:0);						\ | 
 | 113 |     R1 = ASTAT;								\ | 
| Robin Getz | dedfd5d | 2009-08-26 15:54:10 +0000 | [diff] [blame] | 114 |     ANOMALY_283_315_WORKAROUND(p0, r0)					\ | 
| Robin Getz | b9a3899 | 2009-05-18 18:33:26 +0000 | [diff] [blame] | 115 |     P0.L = LO(ILAT);							\ | 
 | 116 |     P0.H = HI(ILAT);							\ | 
| Robin Getz | dedfd5d | 2009-08-26 15:54:10 +0000 | [diff] [blame] | 117 |     NOP;								\ | 
 | 118 |     SSYNC;								\ | 
 | 119 |     SSYNC;								\ | 
| Robin Getz | b9a3899 | 2009-05-18 18:33:26 +0000 | [diff] [blame] | 120 |     R0 = [P0];								\ | 
 | 121 |     CC = BITTST(R0, EVT_IVHW_P);					\ | 
 | 122 |     IF CC JUMP 1f;							\ | 
 | 123 |     ASTAT = R1;								\ | 
 | 124 |     p0.l = lo(IPEND);							\ | 
 | 125 |     p0.h = hi(IPEND);							\ | 
 | 126 |     r1 = [p0];								\ | 
 | 127 |     R0 = (N);								\ | 
 | 128 |     LOAD_IPIPE_IPEND							\ | 
 | 129 |     jump __common_int_entry;						\ | 
 | 130 | 1:  ASTAT = R1;								\ | 
 | 131 |     RAISE N;								\ | 
 | 132 |     (R7:0, P5:0) = [SP++];						\ | 
 | 133 |     SP += 0x8;								\ | 
 | 134 |     SYSCFG = [SP++];							\ | 
 | 135 |     CSYNC;								\ | 
 | 136 |     RTI; | 
 | 137 |  | 
 | 138 | #define TIMER_INTERRUPT_ENTRY(N)					\ | 
| Robin Getz | b9a3899 | 2009-05-18 18:33:26 +0000 | [diff] [blame] | 139 |     [--sp] = SYSCFG;							\ | 
 | 140 |     [--sp] = P0;	/*orig_p0*/					\ | 
 | 141 |     [--sp] = R0;	/*orig_r0*/					\ | 
 | 142 |     [--sp] = (R7:0,P5:0);						\ | 
 | 143 |     R1 = ASTAT;								\ | 
| Robin Getz | dedfd5d | 2009-08-26 15:54:10 +0000 | [diff] [blame] | 144 |     ANOMALY_283_315_WORKAROUND(p0, r0)					\ | 
| Robin Getz | b9a3899 | 2009-05-18 18:33:26 +0000 | [diff] [blame] | 145 |     P0.L = LO(ILAT);							\ | 
 | 146 |     P0.H = HI(ILAT);							\ | 
| Robin Getz | dedfd5d | 2009-08-26 15:54:10 +0000 | [diff] [blame] | 147 |     NOP;								\ | 
 | 148 |     SSYNC;								\ | 
 | 149 |     SSYNC;								\ | 
| Robin Getz | b9a3899 | 2009-05-18 18:33:26 +0000 | [diff] [blame] | 150 |     R0 = [P0];								\ | 
 | 151 |     CC = BITTST(R0, EVT_IVHW_P);					\ | 
 | 152 |     IF CC JUMP 1f;							\ | 
 | 153 |     ASTAT = R1;								\ | 
 | 154 |     p0.l = lo(IPEND);							\ | 
 | 155 |     p0.h = hi(IPEND);							\ | 
 | 156 |     r1 = [p0];								\ | 
 | 157 |     R0 = (N);								\ | 
 | 158 |     jump __common_int_entry;						\ | 
 | 159 | 1:  ASTAT = R1;								\ | 
 | 160 |     RAISE N;								\ | 
 | 161 |     (R7:0, P5:0) = [SP++];						\ | 
 | 162 |     SP += 0x8;								\ | 
 | 163 |     SYSCFG = [SP++];							\ | 
 | 164 |     CSYNC;								\ | 
 | 165 |     RTI; | 
 | 166 | #endif	/* CONFIG_EXACT_HWERR */ | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 167 |  | 
 | 168 | /* This one pushes RETI without using CLI.  Interrupts are enabled.  */ | 
 | 169 | #define SAVE_CONTEXT_SYSCALL	save_context_syscall | 
 | 170 | #define SAVE_CONTEXT		save_context_with_interrupts | 
| Bernd Schmidt | dbdf20d | 2009-01-07 23:14:38 +0800 | [diff] [blame] | 171 | #define SAVE_CONTEXT_CPLB	save_context_cplb | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 172 |  | 
 | 173 | #define RESTORE_ALL_SYS		restore_context_no_interrupts | 
 | 174 | #define RESTORE_CONTEXT		restore_context_with_interrupts | 
| Bernd Schmidt | dbdf20d | 2009-01-07 23:14:38 +0800 | [diff] [blame] | 175 | #define RESTORE_CONTEXT_CPLB	restore_context_cplb | 
| Bryan Wu | 1394f03 | 2007-05-06 14:50:22 -0700 | [diff] [blame] | 176 |  | 
 | 177 | #endif				/* __ASSEMBLY__ */ | 
 | 178 | #endif				/* __BFIN_ENTRY_H */ |