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