/* SPDX-License-Identifier: GPL-2.0 */1/*2* Copyright (C) 1995, 1996, 1997 Paul M. Antoine and Harald Koerfgen3* Copyright (C) 2000, 2001, 2002, 2003, 2005 Maciej W. Rozycki4*5* Written by Ralf Baechle and Andreas Busse, modified for DECstation6* support by Paul Antoine and Harald Koerfgen.7*8* completely rewritten:9* Copyright (C) 1998 Harald Koerfgen10*11* Rewritten extensively for controller-driven IRQ support12* by Maciej W. Rozycki.13*/1415#include <asm/addrspace.h>16#include <asm/asm.h>17#include <asm/mipsregs.h>18#include <asm/regdef.h>19#include <asm/stackframe.h>2021#include <asm/dec/interrupts.h>22#include <asm/dec/ioasic_addrs.h>23#include <asm/dec/ioasic_ints.h>24#include <asm/dec/kn01.h>25#include <asm/dec/kn02.h>26#include <asm/dec/kn02xa.h>27#include <asm/dec/kn03.h>2829#define KN02_CSR_BASE CKSEG1ADDR(KN02_SLOT_BASE + KN02_CSR)30#define KN02XA_IOASIC_BASE CKSEG1ADDR(KN02XA_SLOT_BASE + IOASIC_IOCTL)31#define KN03_IOASIC_BASE CKSEG1ADDR(KN03_SLOT_BASE + IOASIC_IOCTL)3233.text34.set noreorder35/*36* plat_irq_dispatch: Interrupt handler for DECstations37*38* We follow the model in the Indy interrupt code by David Miller, where he39* says: a lot of complication here is taken away because:40*41* 1) We handle one interrupt and return, sitting in a loop42* and moving across all the pending IRQ bits in the cause43* register is _NOT_ the answer, the common case is one44* pending IRQ so optimize in that direction.45*46* 2) We need not check against bits in the status register47* IRQ mask, that would make this routine slow as hell.48*49* 3) Linux only thinks in terms of all IRQs on or all IRQs50* off, nothing in between like BSD spl() brain-damage.51*52* Furthermore, the IRQs on the DECstations look basically (barring53* software IRQs which we don't use at all) like...54*55* DS2100/3100's, aka kn01, aka Pmax:56*57* MIPS IRQ Source58* -------- ------59* 0 Software (ignored)60* 1 Software (ignored)61* 2 SCSI62* 3 Lance Ethernet63* 4 DZ11 serial64* 5 RTC65* 6 Memory Controller & Video66* 7 FPU67*68* DS5000/200, aka kn02, aka 3max:69*70* MIPS IRQ Source71* -------- ------72* 0 Software (ignored)73* 1 Software (ignored)74* 2 TurboChannel75* 3 RTC76* 4 Reserved77* 5 Memory Controller78* 6 Reserved79* 7 FPU80*81* DS5000/1xx's, aka kn02ba, aka 3min:82*83* MIPS IRQ Source84* -------- ------85* 0 Software (ignored)86* 1 Software (ignored)87* 2 TurboChannel Slot 088* 3 TurboChannel Slot 189* 4 TurboChannel Slot 290* 5 TurboChannel Slot 3 (ASIC)91* 6 Halt button92* 7 FPU/R4k timer93*94* DS5000/2x's, aka kn02ca, aka maxine:95*96* MIPS IRQ Source97* -------- ------98* 0 Software (ignored)99* 1 Software (ignored)100* 2 Periodic Interrupt (100usec)101* 3 RTC102* 4 I/O write timeout103* 5 TurboChannel (ASIC)104* 6 Halt Keycode from Access.Bus keyboard (CTRL-ALT-ENTER)105* 7 FPU/R4k timer106*107* DS5000/2xx's, aka kn03, aka 3maxplus:108*109* MIPS IRQ Source110* -------- ------111* 0 Software (ignored)112* 1 Software (ignored)113* 2 System Board (ASIC)114* 3 RTC115* 4 Reserved116* 5 Memory117* 6 Halt Button118* 7 FPU/R4k timer119*120* We handle the IRQ according to _our_ priority (see setup.c),121* then we just return. If multiple IRQs are pending then we will122* just take another exception, big deal.123*/124.align 5125NESTED(plat_irq_dispatch, PT_SIZE, ra)126.set noreorder127128/*129* Get pending Interrupts130*/131mfc0 t0,CP0_CAUSE # get pending interrupts132mfc0 t1,CP0_STATUS133#if defined(CONFIG_32BIT) && defined(CONFIG_MIPS_FP_SUPPORT)134lw t2,cpu_fpu_mask135#endif136andi t0,ST0_IM # CAUSE.CE may be non-zero!137and t0,t1 # isolate allowed ones138139beqz t0,spurious140141#if defined(CONFIG_32BIT) && defined(CONFIG_MIPS_FP_SUPPORT)142and t2,t0143bnez t2,fpu # handle FPU immediately144#endif145146/*147* Find irq with highest priority148*/149# open coded PTR_LA t1, cpu_mask_nr_tbl150#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)151# open coded la t1, cpu_mask_nr_tbl152lui t1, %hi(cpu_mask_nr_tbl)153addiu t1, %lo(cpu_mask_nr_tbl)154#else155#error GCC `-msym32' option required for 64-bit DECstation builds156#endif1571: lw t2,(t1)158nop159and t2,t0160beqz t2,1b161addu t1,2*PTRSIZE # delay slot162163/*164* Do the low-level stuff165*/166lw a0,(-PTRSIZE)(t1)167nop168bgez a0,handle_it # irq_nr >= 0?169# irq_nr < 0: it is an address170nop171jr a0172# a trick to save a branch:173lui t2,(KN03_IOASIC_BASE>>16)&0xffff174# upper part of IOASIC Address175176/*177* Handle "IRQ Controller" Interrupts178* Masked Interrupts are still visible and have to be masked "by hand".179*/180FEXPORT(kn02_io_int) # 3max181lui t0,(KN02_CSR_BASE>>16)&0xffff182# get interrupt status and mask183lw t0,(t0)184nop185andi t1,t0,KN02_IRQ_ALL186b 1f187srl t0,16 # shift interrupt mask188189FEXPORT(kn02xa_io_int) # 3min/maxine190lui t2,(KN02XA_IOASIC_BASE>>16)&0xffff191# upper part of IOASIC Address192193FEXPORT(kn03_io_int) # 3max+ (t2 loaded earlier)194lw t0,IO_REG_SIR(t2) # get status: IOASIC sir195lw t1,IO_REG_SIMR(t2) # get mask: IOASIC simr196nop1971981: and t0,t1 # mask out allowed ones199200beqz t0,spurious201202/*203* Find irq with highest priority204*/205# open coded PTR_LA t1,asic_mask_nr_tbl206#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)207# open coded la t1, asic_mask_nr_tbl208lui t1, %hi(asic_mask_nr_tbl)209addiu t1, %lo(asic_mask_nr_tbl)210#else211#error GCC `-msym32' option required for 64-bit DECstation builds212#endif2132: lw t2,(t1)214nop215and t2,t0216beq zero,t2,2b217addu t1,2*PTRSIZE # delay slot218219/*220* Do the low-level stuff221*/222lw a0,%lo(-PTRSIZE)(t1)223nop224bgez a0,handle_it # irq_nr >= 0?225# irq_nr < 0: it is an address226nop227jr a0228nop # delay slot229230/*231* Dispatch low-priority interrupts. We reconsider all status232* bits again, which looks like a lose, but it makes the code233* simple and O(log n), so it gets compensated.234*/235FEXPORT(cpu_all_int) # HALT, timers, software junk236li a0,DEC_CPU_IRQ_BASE237srl t0,CAUSEB_IP238li t1,CAUSEF_IP>>CAUSEB_IP # mask239b 1f240li t2,4 # nr of bits / 2241242FEXPORT(kn02_all_int) # impossible ?243li a0,KN02_IRQ_BASE244li t1,KN02_IRQ_ALL # mask245b 1f246li t2,4 # nr of bits / 2247248FEXPORT(asic_all_int) # various I/O ASIC junk249li a0,IO_IRQ_BASE250li t1,IO_IRQ_ALL # mask251b 1f252li t2,8 # nr of bits / 2253254/*255* Dispatch DMA interrupts -- O(log n).256*/257FEXPORT(asic_dma_int) # I/O ASIC DMA events258li a0,IO_IRQ_BASE+IO_INR_DMA259srl t0,IO_INR_DMA260li t1,IO_IRQ_DMA>>IO_INR_DMA # mask261li t2,8 # nr of bits / 2262263/*264* Find irq with highest priority.265* Highest irq number takes precedence.266*/2671: srlv t3,t1,t22682: xor t1,t3269and t3,t0,t1270beqz t3,3f271nop272move t0,t3273addu a0,t22743: srl t2,1275bnez t2,2b276srlv t3,t1,t2277278handle_it:279j dec_irq_dispatch280nop281282#if defined(CONFIG_32BIT) && defined(CONFIG_MIPS_FP_SUPPORT)283fpu:284lw t0,fpu_kstat_irq285nop286lw t1,(t0)287nop288addu t1,1289j handle_fpe_int290sw t1,(t0)291#endif292293spurious:294j spurious_interrupt295nop296END(plat_irq_dispatch)297298/*299* Generic unimplemented interrupt routines -- cpu_mask_nr_tbl300* and asic_mask_nr_tbl are initialized to point all interrupts here.301* The tables are then filled in by machine-specific initialisation302* in dec_setup().303*/304FEXPORT(dec_intr_unimplemented)305move a1,t0 # cheats way of printing an arg!306ASM_PANIC("Unimplemented cpu interrupt! CP0_CAUSE: 0x%08x");307308FEXPORT(asic_intr_unimplemented)309move a1,t0 # cheats way of printing an arg!310ASM_PANIC("Unimplemented asic interrupt! ASIC ISR: 0x%08x");311312313