1 /*
2  * Interrupt handling assembler and defines for Linux/CRIS
3  *
4  * Copyright (c) 2000, 2001, 2002, 2003 Axis Communications AB
5  *
6  */
7 
8 #ifndef _ASM_IRQ_H
9 #define _ASM_IRQ_H
10 
11 /*
12  *	linux/include/asm-cris/irq.h
13  */
14 
15 #include <linux/linkage.h>
16 #include <asm/segment.h>
17 
18 #include <asm/sv_addr_ag.h>
19 
20 #define NR_IRQS 32
21 #define SOME_IRQ_NBR           IO_BITNR(R_VECT_MASK_RD, some)   /* 0 ? */
22 #define NMI_IRQ_NBR            IO_BITNR(R_VECT_MASK_RD, nmi)    /* 1 */
23 #define TIMER0_IRQ_NBR         IO_BITNR(R_VECT_MASK_RD, timer0) /* 2 */
24 #define TIMER1_IRQ_NBR         IO_BITNR(R_VECT_MASK_RD, timer1) /* 3 */
25 /* mio, ata, par0, scsi0 on 4 */
26 /* par1, scsi1 on 5 */
27 #define NETWORK_STATUS_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, network) /* 6 */
28 
29 #define SERIAL_IRQ_NBR         IO_BITNR(R_VECT_MASK_RD, serial) /* 8 */
30 #define PA_IRQ_NBR             IO_BITNR(R_VECT_MASK_RD, pa) /* 11 */
31 /* extdma0 and extdma1 is at irq 12 and 13 and/or same as dma5 and dma6 ? */
32 #define EXTDMA0_IRQ_NBR        IO_BITNR(R_VECT_MASK_RD, ext_dma0)
33 #define EXTDMA1_IRQ_NBR        IO_BITNR(R_VECT_MASK_RD, ext_dma1)
34 
35 #define BUS_FAULT_IRQ_NBR      14
36 #define MULTIPLE_IRQ_NBR       15
37 
38 /* dma0-9 is irq 16..25 */
39 /* 16,17: network */
40 #define DMA0_TX_IRQ_NBR        IO_BITNR(R_VECT_MASK_RD, dma0)
41 #define DMA1_RX_IRQ_NBR        IO_BITNR(R_VECT_MASK_RD, dma1)
42 #define NETWORK_DMA_TX_IRQ_NBR DMA0_TX_IRQ_NBR
43 #define NETWORK_DMA_RX_IRQ_NBR DMA1_RX_IRQ_NBR
44 
45 /* 18,19: dma2 and dma3 shared by par0, scsi0, ser2 and ata */
46 #define DMA2_TX_IRQ_NBR        IO_BITNR(R_VECT_MASK_RD, dma2)
47 #define DMA3_RX_IRQ_NBR        IO_BITNR(R_VECT_MASK_RD, dma3)
48 #define SER2_DMA_TX_IRQ_NBR    DMA2_TX_IRQ_NBR
49 #define SER2_DMA_RX_IRQ_NBR    DMA3_RX_IRQ_NBR
50 
51 /* 20,21: dma4 and dma5 shared by par1, scsi1, ser3 and extdma0 */
52 #define DMA4_TX_IRQ_NBR        IO_BITNR(R_VECT_MASK_RD, dma4)
53 #define DMA5_RX_IRQ_NBR        IO_BITNR(R_VECT_MASK_RD, dma5)
54 #define SER3_DMA_TX_IRQ_NBR    DMA4_TX_IRQ_NBR
55 #define SER3_DMA_RX_IRQ_NBR    DMA5_RX_IRQ_NBR
56 
57 /* 22,23: dma6 and dma7 shared by ser0, extdma1 and mem2mem */
58 #define DMA6_TX_IRQ_NBR        IO_BITNR(R_VECT_MASK_RD, dma6)
59 #define DMA7_RX_IRQ_NBR        IO_BITNR(R_VECT_MASK_RD, dma7)
60 #define SER0_DMA_TX_IRQ_NBR    DMA6_TX_IRQ_NBR
61 #define SER0_DMA_RX_IRQ_NBR    DMA7_RX_IRQ_NBR
62 #define MEM2MEM_DMA_TX_IRQ_NBR DMA6_TX_IRQ_NBR
63 #define MEM2MEM_DMA_RX_IRQ_NBR DMA7_RX_IRQ_NBR
64 
65 /* 24,25: dma8 and dma9 shared by ser1 and usb */
66 #define DMA8_TX_IRQ_NBR        IO_BITNR(R_VECT_MASK_RD, dma8)
67 #define DMA9_RX_IRQ_NBR        IO_BITNR(R_VECT_MASK_RD, dma9)
68 #define SER1_DMA_TX_IRQ_NBR    DMA8_TX_IRQ_NBR
69 #define SER1_DMA_RX_IRQ_NBR    DMA9_RX_IRQ_NBR
70 #define USB_DMA_TX_IRQ_NBR     DMA8_TX_IRQ_NBR
71 #define USB_DMA_RX_IRQ_NBR     DMA9_RX_IRQ_NBR
72 
73 /* usb: controller at irq 31 + uses DMA8 and DMA9 */
74 #define USB_HC_IRQ_NBR         IO_BITNR(R_VECT_MASK_RD, usb)
75 
76 
77 extern void disable_irq(unsigned int);
78 extern void enable_irq(unsigned int);
79 
80 #define disable_irq_nosync      disable_irq
81 #define enable_irq_nosync       enable_irq
82 
83 /* our fine, global, etrax irq vector! the pointer lives in the head.S file. */
84 
85 typedef void (*irqvectptr)(void);
86 
87 struct etrax_interrupt_vector {
88 	irqvectptr v[256];
89 };
90 
91 extern struct etrax_interrupt_vector *etrax_irv;
92 void set_int_vector(int n, irqvectptr addr, irqvectptr saddr);
93 void set_break_vector(int n, irqvectptr addr);
94 
95 #define __STR(x) #x
96 #define STR(x) __STR(x)
97 
98 /* SAVE_ALL saves registers so they match pt_regs */
99 
100 #define SAVE_ALL \
101   "move $irp,[$sp=$sp-16]\n\t" /* push instruction pointer and fake SBFS struct */ \
102   "push $srp\n\t"       /* push subroutine return pointer */ \
103   "push $dccr\n\t"      /* push condition codes */ \
104   "push $mof\n\t"       /* push multiply overflow reg */ \
105   "di\n\t"              /* need to disable irq's at this point */\
106   "subq 14*4,$sp\n\t"   /* make room for r0-r13 */ \
107   "movem $r13,[$sp]\n\t" /* push the r0-r13 registers */ \
108   "push $r10\n\t"       /* push orig_r10 */ \
109   "clear.d [$sp=$sp-4]\n\t"  /* frametype - this is a normal stackframe */
110 
111 /* BLOCK_IRQ and UNBLOCK_IRQ do the same as mask_irq and unmask_irq in irq.c */
112 
113 #define BLOCK_IRQ(mask,nr) \
114   "move.d " #mask ",$r0\n\t" \
115   "move.d $r0,[0xb00000d8]\n\t"
116 
117 #define UNBLOCK_IRQ(mask) \
118   "move.d " #mask ",$r0\n\t" \
119   "move.d $r0,[0xb00000dc]\n\t"
120 
121 #define IRQ_NAME2(nr) nr##_interrupt(void)
122 #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
123 #define sIRQ_NAME(nr) IRQ_NAME2(sIRQ##nr)
124 #define BAD_IRQ_NAME(nr) IRQ_NAME2(bad_IRQ##nr)
125 
126 /* the asm IRQ handler makes sure the causing IRQ is blocked, then it calls
127  * do_IRQ (with irq disabled still). after that it unblocks and jumps to
128  * ret_from_intr (entry.S)
129  *
130  * The reason the IRQ is blocked is to allow an sti() before the handler which
131  * will acknowledge the interrupt is run.
132  */
133 
134 #define BUILD_IRQ(nr,mask) \
135 void IRQ_NAME(nr); \
136 void sIRQ_NAME(nr); \
137 void BAD_IRQ_NAME(nr); \
138 __asm__ ( \
139           ".text\n\t" \
140           "IRQ" #nr "_interrupt:\n\t" \
141 	  SAVE_ALL \
142 	  "sIRQ" #nr "_interrupt:\n\t" /* shortcut for the multiple irq handler */ \
143 	  BLOCK_IRQ(mask,nr) /* this must be done to prevent irq loops when we ei later */ \
144 	  "moveq "#nr",$r10\n\t" \
145 	  "move.d $sp,$r11\n\t" \
146 	  "jsr do_IRQ\n\t" /* irq.c, r10 and r11 are arguments */ \
147 	  UNBLOCK_IRQ(mask) \
148 	  "moveq 0,$r9\n\t" /* make ret_from_intr realise we came from an irq */ \
149 	  "jump ret_from_intr\n\t" \
150           "bad_IRQ" #nr "_interrupt:\n\t" \
151 	  "push $r0\n\t" \
152 	  BLOCK_IRQ(mask,nr) \
153 	  "pop $r0\n\t" \
154           "reti\n\t" \
155           "nop\n");
156 
157 /* This is subtle. The timer interrupt is crucial and it should not be disabled
158  * for too long. However, if it had been a normal interrupt as per BUILD_IRQ,
159  * it would have been BLOCK'ed, and then softirq's are run before we return
160  * here to UNBLOCK. If the softirq's take too much time to run, the timer irq
161  * won't run and the watchdog will kill us.
162  *
163  * Furthermore, if a lot of other irq's occur before we return here, the
164  * multiple_irq handler is run and it prioritizes the timer interrupt. However
165  * if we had BLOCK'ed it here, we would not get the multiple_irq at all.
166  *
167  * The non-blocking here is based on the knowledge that the timer interrupt is
168  * registred as a fast interrupt (SA_INTERRUPT) so that we _know_ there will
169  * not be an sti() before the timer irq handler is run to acknowledge the
170  * interrupt.
171  */
172 
173 #define BUILD_TIMER_IRQ(nr,mask) \
174 void IRQ_NAME(nr); \
175 void sIRQ_NAME(nr); \
176 void BAD_IRQ_NAME(nr); \
177 __asm__ ( \
178           ".text\n\t" \
179           "IRQ" #nr "_interrupt:\n\t" \
180 	  SAVE_ALL \
181 	  "sIRQ" #nr "_interrupt:\n\t" /* shortcut for the multiple irq handler */ \
182 	  "moveq "#nr",$r10\n\t" \
183 	  "move.d $sp,$r11\n\t" \
184 	  "jsr do_IRQ\n\t" /* irq.c, r10 and r11 are arguments */ \
185 	  "moveq 0,$r9\n\t" /* make ret_from_intr realise we came from an irq */ \
186 	  "jump ret_from_intr\n\t" \
187           "bad_IRQ" #nr "_interrupt:\n\t" \
188 	  "push $r0\n\t" \
189 	  BLOCK_IRQ(mask,nr) \
190 	  "pop $r0\n\t" \
191           "reti\n\t" \
192           "nop\n");
193 
194 #endif  /* _ASM_IRQ_H */
195