linux/arch/mips/dec/int-handler.S
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2/*
   3 * Copyright (C) 1995, 1996, 1997 Paul M. Antoine and Harald Koerfgen
   4 * Copyright (C) 2000, 2001, 2002, 2003, 2005  Maciej W. Rozycki
   5 *
   6 * Written by Ralf Baechle and Andreas Busse, modified for DECstation
   7 * support by Paul Antoine and Harald Koerfgen.
   8 *
   9 * completely rewritten:
  10 * Copyright (C) 1998 Harald Koerfgen
  11 *
  12 * Rewritten extensively for controller-driven IRQ support
  13 * by Maciej W. Rozycki.
  14 */
  15
  16#include <asm/addrspace.h>
  17#include <asm/asm.h>
  18#include <asm/mipsregs.h>
  19#include <asm/regdef.h>
  20#include <asm/stackframe.h>
  21
  22#include <asm/dec/interrupts.h>
  23#include <asm/dec/ioasic_addrs.h>
  24#include <asm/dec/ioasic_ints.h>
  25#include <asm/dec/kn01.h>
  26#include <asm/dec/kn02.h>
  27#include <asm/dec/kn02xa.h>
  28#include <asm/dec/kn03.h>
  29
  30#define KN02_CSR_BASE           CKSEG1ADDR(KN02_SLOT_BASE + KN02_CSR)
  31#define KN02XA_IOASIC_BASE      CKSEG1ADDR(KN02XA_SLOT_BASE + IOASIC_IOCTL)
  32#define KN03_IOASIC_BASE        CKSEG1ADDR(KN03_SLOT_BASE + IOASIC_IOCTL)
  33
  34                .text
  35                .set    noreorder
  36/*
  37 * plat_irq_dispatch: Interrupt handler for DECstations
  38 *
  39 * We follow the model in the Indy interrupt code by David Miller, where he
  40 * says: a lot of complication here is taken away because:
  41 *
  42 * 1) We handle one interrupt and return, sitting in a loop
  43 *    and moving across all the pending IRQ bits in the cause
  44 *    register is _NOT_ the answer, the common case is one
  45 *    pending IRQ so optimize in that direction.
  46 *
  47 * 2) We need not check against bits in the status register
  48 *    IRQ mask, that would make this routine slow as hell.
  49 *
  50 * 3) Linux only thinks in terms of all IRQs on or all IRQs
  51 *    off, nothing in between like BSD spl() brain-damage.
  52 *
  53 * Furthermore, the IRQs on the DECstations look basically (barring
  54 * software IRQs which we don't use at all) like...
  55 *
  56 * DS2100/3100's, aka kn01, aka Pmax:
  57 *
  58 *      MIPS IRQ        Source
  59 *      --------        ------
  60 *             0        Software (ignored)
  61 *             1        Software (ignored)
  62 *             2        SCSI
  63 *             3        Lance Ethernet
  64 *             4        DZ11 serial
  65 *             5        RTC
  66 *             6        Memory Controller & Video
  67 *             7        FPU
  68 *
  69 * DS5000/200, aka kn02, aka 3max:
  70 *
  71 *      MIPS IRQ        Source
  72 *      --------        ------
  73 *             0        Software (ignored)
  74 *             1        Software (ignored)
  75 *             2        TurboChannel
  76 *             3        RTC
  77 *             4        Reserved
  78 *             5        Memory Controller
  79 *             6        Reserved
  80 *             7        FPU
  81 *
  82 * DS5000/1xx's, aka kn02ba, aka 3min:
  83 *
  84 *      MIPS IRQ        Source
  85 *      --------        ------
  86 *             0        Software (ignored)
  87 *             1        Software (ignored)
  88 *             2        TurboChannel Slot 0
  89 *             3        TurboChannel Slot 1
  90 *             4        TurboChannel Slot 2
  91 *             5        TurboChannel Slot 3 (ASIC)
  92 *             6        Halt button
  93 *             7        FPU/R4k timer
  94 *
  95 * DS5000/2x's, aka kn02ca, aka maxine:
  96 *
  97 *      MIPS IRQ        Source
  98 *      --------        ------
  99 *             0        Software (ignored)
 100 *             1        Software (ignored)
 101 *             2        Periodic Interrupt (100usec)
 102 *             3        RTC
 103 *             4        I/O write timeout
 104 *             5        TurboChannel (ASIC)
 105 *             6        Halt Keycode from Access.Bus keyboard (CTRL-ALT-ENTER)
 106 *             7        FPU/R4k timer
 107 *
 108 * DS5000/2xx's, aka kn03, aka 3maxplus:
 109 *
 110 *      MIPS IRQ        Source
 111 *      --------        ------
 112 *             0        Software (ignored)
 113 *             1        Software (ignored)
 114 *             2        System Board (ASIC)
 115 *             3        RTC
 116 *             4        Reserved
 117 *             5        Memory
 118 *             6        Halt Button
 119 *             7        FPU/R4k timer
 120 *
 121 * We handle the IRQ according to _our_ priority (see setup.c),
 122 * then we just return.  If multiple IRQs are pending then we will
 123 * just take another exception, big deal.
 124 */
 125                .align  5
 126                NESTED(plat_irq_dispatch, PT_SIZE, ra)
 127                .set    noreorder
 128
 129                /*
 130                 * Get pending Interrupts
 131                 */
 132                mfc0    t0,CP0_CAUSE            # get pending interrupts
 133                mfc0    t1,CP0_STATUS
 134#ifdef CONFIG_32BIT
 135                lw      t2,cpu_fpu_mask
 136#endif
 137                andi    t0,ST0_IM               # CAUSE.CE may be non-zero!
 138                and     t0,t1                   # isolate allowed ones
 139
 140                beqz    t0,spurious
 141
 142#ifdef CONFIG_32BIT
 143                 and    t2,t0
 144                bnez    t2,fpu                  # handle FPU immediately
 145#endif
 146
 147                /*
 148                 * Find irq with highest priority
 149                 */
 150                # open coded PTR_LA t1, cpu_mask_nr_tbl
 151#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
 152                # open coded la t1, cpu_mask_nr_tbl
 153                lui     t1, %hi(cpu_mask_nr_tbl)
 154                addiu   t1, %lo(cpu_mask_nr_tbl)
 155#else
 156#error GCC `-msym32' option required for 64-bit DECstation builds
 157#endif
 1581:              lw      t2,(t1)
 159                nop
 160                and     t2,t0
 161                beqz    t2,1b
 162                 addu   t1,2*PTRSIZE            # delay slot
 163
 164                /*
 165                 * Do the low-level stuff
 166                 */
 167                lw      a0,(-PTRSIZE)(t1)
 168                nop
 169                bgez    a0,handle_it            # irq_nr >= 0?
 170                                                # irq_nr < 0: it is an address
 171                 nop
 172                jr      a0
 173                                                # a trick to save a branch:
 174                 lui    t2,(KN03_IOASIC_BASE>>16)&0xffff
 175                                                # upper part of IOASIC Address
 176
 177/*
 178 * Handle "IRQ Controller" Interrupts
 179 * Masked Interrupts are still visible and have to be masked "by hand".
 180 */
 181                FEXPORT(kn02_io_int)            # 3max
 182                lui     t0,(KN02_CSR_BASE>>16)&0xffff
 183                                                # get interrupt status and mask
 184                lw      t0,(t0)
 185                nop
 186                andi    t1,t0,KN02_IRQ_ALL
 187                b       1f
 188                 srl    t0,16                   # shift interrupt mask
 189
 190                FEXPORT(kn02xa_io_int)          # 3min/maxine
 191                lui     t2,(KN02XA_IOASIC_BASE>>16)&0xffff
 192                                                # upper part of IOASIC Address
 193
 194                FEXPORT(kn03_io_int)            # 3max+ (t2 loaded earlier)
 195                lw      t0,IO_REG_SIR(t2)       # get status: IOASIC sir
 196                lw      t1,IO_REG_SIMR(t2)      # get mask:   IOASIC simr
 197                nop
 198
 1991:              and     t0,t1                   # mask out allowed ones
 200
 201                beqz    t0,spurious
 202
 203                /*
 204                 * Find irq with highest priority
 205                 */
 206                # open coded PTR_LA t1,asic_mask_nr_tbl
 207#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
 208                # open coded la t1, asic_mask_nr_tbl
 209                lui     t1, %hi(asic_mask_nr_tbl)
 210                addiu   t1, %lo(asic_mask_nr_tbl)
 211#else
 212#error GCC `-msym32' option required for 64-bit DECstation builds
 213#endif
 2142:              lw      t2,(t1)
 215                nop
 216                and     t2,t0
 217                beq     zero,t2,2b
 218                 addu   t1,2*PTRSIZE            # delay slot
 219
 220                /*
 221                 * Do the low-level stuff
 222                 */
 223                lw      a0,%lo(-PTRSIZE)(t1)
 224                nop
 225                bgez    a0,handle_it            # irq_nr >= 0?
 226                                                # irq_nr < 0: it is an address
 227                 nop
 228                jr      a0
 229                 nop                            # delay slot
 230
 231/*
 232 * Dispatch low-priority interrupts.  We reconsider all status
 233 * bits again, which looks like a lose, but it makes the code
 234 * simple and O(log n), so it gets compensated.
 235 */
 236                FEXPORT(cpu_all_int)            # HALT, timers, software junk
 237                li      a0,DEC_CPU_IRQ_BASE
 238                srl     t0,CAUSEB_IP
 239                li      t1,CAUSEF_IP>>CAUSEB_IP # mask
 240                b       1f
 241                 li     t2,4                    # nr of bits / 2
 242
 243                FEXPORT(kn02_all_int)           # impossible ?
 244                li      a0,KN02_IRQ_BASE
 245                li      t1,KN02_IRQ_ALL         # mask
 246                b       1f
 247                 li     t2,4                    # nr of bits / 2
 248
 249                FEXPORT(asic_all_int)           # various I/O ASIC junk
 250                li      a0,IO_IRQ_BASE
 251                li      t1,IO_IRQ_ALL           # mask
 252                b       1f
 253                 li     t2,8                    # nr of bits / 2
 254
 255/*
 256 * Dispatch DMA interrupts -- O(log n).
 257 */
 258                FEXPORT(asic_dma_int)           # I/O ASIC DMA events
 259                li      a0,IO_IRQ_BASE+IO_INR_DMA
 260                srl     t0,IO_INR_DMA
 261                li      t1,IO_IRQ_DMA>>IO_INR_DMA # mask
 262                li      t2,8                    # nr of bits / 2
 263
 264                /*
 265                 * Find irq with highest priority.
 266                 * Highest irq number takes precedence.
 267                 */
 2681:              srlv    t3,t1,t2
 2692:              xor     t1,t3
 270                and     t3,t0,t1
 271                beqz    t3,3f
 272                 nop
 273                move    t0,t3
 274                addu    a0,t2
 2753:              srl     t2,1
 276                bnez    t2,2b
 277                 srlv   t3,t1,t2
 278
 279handle_it:
 280                j       dec_irq_dispatch
 281                 nop
 282
 283#ifdef CONFIG_32BIT
 284fpu:
 285                lw      t0,fpu_kstat_irq
 286                nop
 287                lw      t1,(t0)
 288                nop
 289                addu    t1,1
 290                j       handle_fpe_int
 291                 sw     t1,(t0)
 292#endif
 293
 294spurious:
 295                j       spurious_interrupt
 296                 nop
 297                END(plat_irq_dispatch)
 298
 299/*
 300 * Generic unimplemented interrupt routines -- cpu_mask_nr_tbl
 301 * and asic_mask_nr_tbl are initialized to point all interrupts here.
 302 * The tables are then filled in by machine-specific initialisation
 303 * in dec_setup().
 304 */
 305                FEXPORT(dec_intr_unimplemented)
 306                move    a1,t0                   # cheats way of printing an arg!
 307                ASM_PANIC("Unimplemented cpu interrupt! CP0_CAUSE: 0x%08x");
 308
 309                FEXPORT(asic_intr_unimplemented)
 310                move    a1,t0                   # cheats way of printing an arg!
 311                ASM_PANIC("Unimplemented asic interrupt! ASIC ISR: 0x%08x");
 312