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