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