/*1* Copyright (C) 1995, 1996, 1997 Paul M. Antoine and Harald Koerfgen2* Copyright (C) 2000, 2001, 2002, 2003, 2005 Maciej W. Rozycki3*4* Written by Ralf Baechle and Andreas Busse, modified for DECstation5* support by Paul Antoine and Harald Koerfgen.6*7* completly rewritten:8* Copyright (C) 1998 Harald Koerfgen9*10* Rewritten extensively for controller-driven IRQ support11* by Maciej W. Rozycki.12*/1314#include <asm/addrspace.h>15#include <asm/asm.h>16#include <asm/mipsregs.h>17#include <asm/regdef.h>18#include <asm/stackframe.h>1920#include <asm/dec/interrupts.h>21#include <asm/dec/ioasic_addrs.h>22#include <asm/dec/ioasic_ints.h>23#include <asm/dec/kn01.h>24#include <asm/dec/kn02.h>25#include <asm/dec/kn02xa.h>26#include <asm/dec/kn03.h>2728#define KN02_CSR_BASE CKSEG1ADDR(KN02_SLOT_BASE + KN02_CSR)29#define KN02XA_IOASIC_BASE CKSEG1ADDR(KN02XA_SLOT_BASE + IOASIC_IOCTL)30#define KN03_IOASIC_BASE CKSEG1ADDR(KN03_SLOT_BASE + IOASIC_IOCTL)3132.text33.set noreorder34/*35* plat_irq_dispatch: Interrupt handler for DECstations36*37* We follow the model in the Indy interrupt code by David Miller, where he38* says: a lot of complication here is taken away because:39*40* 1) We handle one interrupt and return, sitting in a loop41* and moving across all the pending IRQ bits in the cause42* register is _NOT_ the answer, the common case is one43* pending IRQ so optimize in that direction.44*45* 2) We need not check against bits in the status register46* IRQ mask, that would make this routine slow as hell.47*48* 3) Linux only thinks in terms of all IRQs on or all IRQs49* off, nothing in between like BSD spl() brain-damage.50*51* Furthermore, the IRQs on the DECstations look basically (barring52* software IRQs which we don't use at all) like...53*54* DS2100/3100's, aka kn01, aka Pmax:55*56* MIPS IRQ Source57* -------- ------58* 0 Software (ignored)59* 1 Software (ignored)60* 2 SCSI61* 3 Lance Ethernet62* 4 DZ11 serial63* 5 RTC64* 6 Memory Controller & Video65* 7 FPU66*67* DS5000/200, aka kn02, aka 3max:68*69* MIPS IRQ Source70* -------- ------71* 0 Software (ignored)72* 1 Software (ignored)73* 2 TurboChannel74* 3 RTC75* 4 Reserved76* 5 Memory Controller77* 6 Reserved78* 7 FPU79*80* DS5000/1xx's, aka kn02ba, aka 3min:81*82* MIPS IRQ Source83* -------- ------84* 0 Software (ignored)85* 1 Software (ignored)86* 2 TurboChannel Slot 087* 3 TurboChannel Slot 188* 4 TurboChannel Slot 289* 5 TurboChannel Slot 3 (ASIC)90* 6 Halt button91* 7 FPU/R4k timer92*93* DS5000/2x's, aka kn02ca, aka maxine:94*95* MIPS IRQ Source96* -------- ------97* 0 Software (ignored)98* 1 Software (ignored)99* 2 Periodic Interrupt (100usec)100* 3 RTC101* 4 I/O write timeout102* 5 TurboChannel (ASIC)103* 6 Halt Keycode from Access.Bus keyboard (CTRL-ALT-ENTER)104* 7 FPU/R4k timer105*106* DS5000/2xx's, aka kn03, aka 3maxplus:107*108* MIPS IRQ Source109* -------- ------110* 0 Software (ignored)111* 1 Software (ignored)112* 2 System Board (ASIC)113* 3 RTC114* 4 Reserved115* 5 Memory116* 6 Halt Button117* 7 FPU/R4k timer118*119* We handle the IRQ according to _our_ priority (see setup.c),120* then we just return. If multiple IRQs are pending then we will121* just take another exception, big deal.122*/123.align 5124NESTED(plat_irq_dispatch, PT_SIZE, ra)125.set noreorder126127/*128* Get pending Interrupts129*/130mfc0 t0,CP0_CAUSE # get pending interrupts131mfc0 t1,CP0_STATUS132#ifdef CONFIG_32BIT133lw t2,cpu_fpu_mask134#endif135andi t0,ST0_IM # CAUSE.CE may be non-zero!136and t0,t1 # isolate allowed ones137138beqz t0,spurious139140#ifdef CONFIG_32BIT141and t2,t0142bnez t2,fpu # handle FPU immediately143#endif144145/*146* Find irq with highest priority147*/148PTR_LA t1,cpu_mask_nr_tbl1491: lw t2,(t1)150nop151and t2,t0152beqz t2,1b153addu t1,2*PTRSIZE # delay slot154155/*156* Do the low-level stuff157*/158lw a0,(-PTRSIZE)(t1)159nop160bgez a0,handle_it # irq_nr >= 0?161# irq_nr < 0: it is an address162nop163jr a0164# a trick to save a branch:165lui t2,(KN03_IOASIC_BASE>>16)&0xffff166# upper part of IOASIC Address167168/*169* Handle "IRQ Controller" Interrupts170* Masked Interrupts are still visible and have to be masked "by hand".171*/172FEXPORT(kn02_io_int) # 3max173lui t0,(KN02_CSR_BASE>>16)&0xffff174# get interrupt status and mask175lw t0,(t0)176nop177andi t1,t0,KN02_IRQ_ALL178b 1f179srl t0,16 # shift interrupt mask180181FEXPORT(kn02xa_io_int) # 3min/maxine182lui t2,(KN02XA_IOASIC_BASE>>16)&0xffff183# upper part of IOASIC Address184185FEXPORT(kn03_io_int) # 3max+ (t2 loaded earlier)186lw t0,IO_REG_SIR(t2) # get status: IOASIC sir187lw t1,IO_REG_SIMR(t2) # get mask: IOASIC simr188nop1891901: and t0,t1 # mask out allowed ones191192beqz t0,spurious193194/*195* Find irq with highest priority196*/197PTR_LA t1,asic_mask_nr_tbl1982: lw t2,(t1)199nop200and t2,t0201beq zero,t2,2b202addu t1,2*PTRSIZE # delay slot203204/*205* Do the low-level stuff206*/207lw a0,%lo(-PTRSIZE)(t1)208nop209bgez a0,handle_it # irq_nr >= 0?210# irq_nr < 0: it is an address211nop212jr a0213nop # delay slot214215/*216* Dispatch low-priority interrupts. We reconsider all status217* bits again, which looks like a lose, but it makes the code218* simple and O(log n), so it gets compensated.219*/220FEXPORT(cpu_all_int) # HALT, timers, software junk221li a0,DEC_CPU_IRQ_BASE222srl t0,CAUSEB_IP223li t1,CAUSEF_IP>>CAUSEB_IP # mask224b 1f225li t2,4 # nr of bits / 2226227FEXPORT(kn02_all_int) # impossible ?228li a0,KN02_IRQ_BASE229li t1,KN02_IRQ_ALL # mask230b 1f231li t2,4 # nr of bits / 2232233FEXPORT(asic_all_int) # various I/O ASIC junk234li a0,IO_IRQ_BASE235li t1,IO_IRQ_ALL # mask236b 1f237li t2,8 # nr of bits / 2238239/*240* Dispatch DMA interrupts -- O(log n).241*/242FEXPORT(asic_dma_int) # I/O ASIC DMA events243li a0,IO_IRQ_BASE+IO_INR_DMA244srl t0,IO_INR_DMA245li t1,IO_IRQ_DMA>>IO_INR_DMA # mask246li t2,8 # nr of bits / 2247248/*249* Find irq with highest priority.250* Highest irq number takes precedence.251*/2521: srlv t3,t1,t22532: xor t1,t3254and t3,t0,t1255beqz t3,3f256nop257move t0,t3258addu a0,t22593: srl t2,1260bnez t2,2b261srlv t3,t1,t2262263handle_it:264j dec_irq_dispatch265nop266267#ifdef CONFIG_32BIT268fpu:269j handle_fpe_int270nop271#endif272273spurious:274j spurious_interrupt275nop276END(plat_irq_dispatch)277278/*279* Generic unimplemented interrupt routines -- cpu_mask_nr_tbl280* and asic_mask_nr_tbl are initialized to point all interrupts here.281* The tables are then filled in by machine-specific initialisation282* in dec_setup().283*/284FEXPORT(dec_intr_unimplemented)285move a1,t0 # cheats way of printing an arg!286PANIC("Unimplemented cpu interrupt! CP0_CAUSE: 0x%08x");287288FEXPORT(asic_intr_unimplemented)289move a1,t0 # cheats way of printing an arg!290PANIC("Unimplemented asic interrupt! ASIC ISR: 0x%08x");291292293