Commit e4ac58af authored by Ralf Baechle's avatar Ralf Baechle

[MIPS] Rewrite all the assembler interrupt handlers to C.

Saves like 1,600 lines of code, is way easier to debug, compilers
frequently do a better job than the cut and paste type of handlers many
boards had.  And finally having all the stuff done in a single place
also means alot of bug potencial for the MT ASE is gone.

The only surviving handler in assembler is the DECstation one; I hope
Maciej will rewrite it.
Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent d35d473c
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
# Makefile for the Alchemy Au1000 CPU, generic files. # Makefile for the Alchemy Au1000 CPU, generic files.
# #
obj-y += prom.o int-handler.o irq.o puts.o time.o reset.o \ obj-y += prom.o irq.o puts.o time.o reset.o \
au1xxx_irqmap.o clocks.o platform.o power.o setup.o \ au1xxx_irqmap.o clocks.o platform.o power.o setup.o \
sleeper.o cputable.o dma.o dbdma.o gpio.o sleeper.o cputable.o dma.o dbdma.o gpio.o
......
/*
* Copyright 2001 MontaVista Software Inc.
* Author: ppopov@mvista.com
*
* Interrupt dispatcher for Au1000 boards.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/addrspace.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
.text
.set macro
.set noat
.align 5
NESTED(au1000_IRQ, PT_SIZE, sp)
SAVE_ALL
CLI # Important: mark KERNEL mode !
mfc0 t0,CP0_CAUSE # get pending interrupts
mfc0 t1,CP0_STATUS # get enabled interrupts
and t0,t1 # isolate allowed ones
andi t0,0xff00 # isolate pending bits
beqz t0, 3f # spurious interrupt
andi a0, t0, CAUSEF_IP7
beq a0, zero, 1f
move a0, sp
jal mips_timer_interrupt
j ret_from_irq
1:
andi a0, t0, CAUSEF_IP2 # Interrupt Controller 0, Request 0
beq a0, zero, 2f
move a0,sp
jal intc0_req0_irqdispatch
j ret_from_irq
2:
andi a0, t0, CAUSEF_IP3 # Interrupt Controller 0, Request 1
beq a0, zero, 3f
move a0,sp
jal intc0_req1_irqdispatch
j ret_from_irq
3:
andi a0, t0, CAUSEF_IP4 # Interrupt Controller 1, Request 0
beq a0, zero, 4f
move a0,sp
jal intc1_req0_irqdispatch
j ret_from_irq
4:
andi a0, t0, CAUSEF_IP5 # Interrupt Controller 1, Request 1
beq a0, zero, 5f
move a0, sp
jal intc1_req1_irqdispatch
j ret_from_irq
5:
move a0, sp
jal spurious_interrupt
j ret_from_irq
END(au1000_IRQ)
...@@ -66,7 +66,6 @@ ...@@ -66,7 +66,6 @@
#define EXT_INTC1_REQ1 5 /* IP 5 */ #define EXT_INTC1_REQ1 5 /* IP 5 */
#define MIPS_TIMER_IP 7 /* IP 7 */ #define MIPS_TIMER_IP 7 /* IP 7 */
extern asmlinkage void au1000_IRQ(void);
extern void set_debug_traps(void); extern void set_debug_traps(void);
extern irq_cpustat_t irq_stat [NR_CPUS]; extern irq_cpustat_t irq_stat [NR_CPUS];
...@@ -446,7 +445,6 @@ void __init arch_init_irq(void) ...@@ -446,7 +445,6 @@ void __init arch_init_irq(void)
extern int au1xxx_ic0_nr_irqs; extern int au1xxx_ic0_nr_irqs;
cp0_status = read_c0_status(); cp0_status = read_c0_status();
set_except_vector(0, au1000_IRQ);
/* Initialize interrupt controllers to a safe state. /* Initialize interrupt controllers to a safe state.
*/ */
...@@ -661,3 +659,21 @@ restore_au1xxx_intctl(void) ...@@ -661,3 +659,21 @@ restore_au1xxx_intctl(void)
au_writel(sleep_intctl_mask[0], IC0_MASKSET); au_sync(); au_writel(sleep_intctl_mask[0], IC0_MASKSET); au_sync();
} }
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
if (pending & CAUSEF_IP7)
mips_timer_interrupt(regs);
else if (pending & CAUSEF_IP2)
intc0_req0_irqdispatch(regs);
else if (pending & CAUSEF_IP3)
intc0_req1_irqdispatch(regs);
else if (pending & CAUSEF_IP4)
intc1_req0_irqdispatch(regs);
else if (pending & CAUSEF_IP5)
intc1_req1_irqdispatch(regs);
else
spurious_interrupt(regs);
}
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Makefile for the Cobalt micro systems family specific parts of the kernel # Makefile for the Cobalt micro systems family specific parts of the kernel
# #
obj-y := irq.o int-handler.o reset.o setup.o obj-y := irq.o reset.o setup.o
obj-$(CONFIG_EARLY_PRINTK) += console.o obj-$(CONFIG_EARLY_PRINTK) += console.o
......
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1995, 1996, 1997, 2003 by Ralf Baechle
* Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv)
*/
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/mach-cobalt/cobalt.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
.text
.align 5
NESTED(cobalt_handle_int, PT_SIZE, sp)
SAVE_ALL
CLI
PTR_LA ra, ret_from_irq
move a0, sp
j cobalt_irq
END(cobalt_handle_int)
...@@ -20,8 +20,6 @@ ...@@ -20,8 +20,6 @@
#include <asm/mach-cobalt/cobalt.h> #include <asm/mach-cobalt/cobalt.h>
extern void cobalt_handle_int(void);
/* /*
* We have two types of interrupts that we handle, ones that come in through * We have two types of interrupts that we handle, ones that come in through
* the CPU interrupt lines, and ones that come in on the via chip. The CPU * the CPU interrupt lines, and ones that come in on the via chip. The CPU
...@@ -79,7 +77,7 @@ static inline void via_pic_irq(struct pt_regs *regs) ...@@ -79,7 +77,7 @@ static inline void via_pic_irq(struct pt_regs *regs)
do_IRQ(irq, regs); do_IRQ(irq, regs);
} }
asmlinkage void cobalt_irq(struct pt_regs *regs) asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{ {
unsigned pending; unsigned pending;
...@@ -122,8 +120,6 @@ void __init arch_init_irq(void) ...@@ -122,8 +120,6 @@ void __init arch_init_irq(void)
*/ */
GALILEO_OUTL(0, GT_INTRMASK_OFS); GALILEO_OUTL(0, GT_INTRMASK_OFS);
set_except_vector(0, cobalt_handle_int);
init_i8259_irqs(); /* 0 ... 15 */ init_i8259_irqs(); /* 0 ... 15 */
mips_cpu_irq_init(COBALT_CPU_IRQ); /* 16 ... 23 */ mips_cpu_irq_init(COBALT_CPU_IRQ); /* 16 ... 23 */
......
...@@ -3,6 +3,6 @@ ...@@ -3,6 +3,6 @@
# under Linux. # under Linux.
# #
obj-y += setup.o irq.o int-handler.o nile4_pic.o obj-y += setup.o irq.o nile4_pic.o
EXTRA_AFLAGS := $(CFLAGS) EXTRA_AFLAGS := $(CFLAGS)
/*
* arch/mips/ddb5074/int-handler.S -- NEC DDB Vrc-5074 interrupt handler
*
* Based on arch/mips/sgi/kernel/indyIRQ.S
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*
* Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
* Sony Software Development Center Europe (SDCE), Brussels
*/
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
/* A lot of complication here is taken away because:
*
* 1) We handle one interrupt and return, sitting in a loop and moving across
* all the pending IRQ bits in the cause register is _NOT_ the answer, the
* common case is one pending IRQ so optimize in that direction.
*
* 2) We need not check against bits in the status register IRQ mask, that
* would make this routine slow as hell.
*
* 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
* between like BSD spl() brain-damage.
*
* Furthermore, the IRQs on the INDY look basically (barring software IRQs
* which we don't use at all) like:
*
* MIPS IRQ Source
* -------- ------
* 0 Software (ignored)
* 1 Software (ignored)
* 2 Local IRQ level zero
* 3 Local IRQ level one
* 4 8254 Timer zero
* 5 8254 Timer one
* 6 Bus Error
* 7 R4k timer (what we use)
*
* We handle the IRQ according to _our_ priority which is:
*
* Highest ---- R4k Timer
* Local IRQ zero
* Local IRQ one
* Bus Error
* 8254 Timer zero
* Lowest ---- 8254 Timer one
*
* then we just return, if multiple IRQs are pending then we will just take
* another exception, big deal.
*/
.text
.set noreorder
.set noat
.align 5
NESTED(ddbIRQ, PT_SIZE, sp)
SAVE_ALL
CLI
.set at
mfc0 s0, CP0_CAUSE # get irq mask
#if 1
mfc0 t2,CP0_STATUS # get enabled interrupts
and s0,t2 # isolate allowed ones
#endif
/* First we check for r4k counter/timer IRQ. */
andi a0, s0, CAUSEF_IP2 # delay slot, check local level zero
beq a0, zero, 1f
andi a0, s0, CAUSEF_IP3 # delay slot, check local level one
/* Wheee, local level zero interrupt. */
jal ddb_local0_irqdispatch
move a0, sp # delay slot
j ret_from_irq
nop # delay slot
1:
beq a0, zero, 1f
andi a0, s0, CAUSEF_IP6 # delay slot, check bus error
/* Wheee, local level one interrupt. */
move a0, sp
jal ddb_local1_irqdispatch
nop
j ret_from_irq
nop
1:
beq a0, zero, 1f
nop
/* Wheee, an asynchronous bus error... */
move a0, sp
jal ddb_buserror_irq
nop
j ret_from_irq
nop
1:
/* Here by mistake? This is possible, what can happen
* is that by the time we take the exception the IRQ
* pin goes low, so just leave if this is the case.
*/
andi a0, s0, (CAUSEF_IP4 | CAUSEF_IP5)
beq a0, zero, 1f
/* Must be one of the 8254 timers... */
move a0, sp
jal ddb_8254timer_irq
nop
1:
j ret_from_irq
nop
END(ddbIRQ)
...@@ -21,8 +21,6 @@ ...@@ -21,8 +21,6 @@
#include <asm/ddb5xxx/ddb5074.h> #include <asm/ddb5xxx/ddb5074.h>
extern asmlinkage void ddbIRQ(void);
static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL }; static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL };
#define M1543_PNP_CONFIG 0x03f0 /* PnP Config Port */ #define M1543_PNP_CONFIG 0x03f0 /* PnP Config Port */
...@@ -90,7 +88,7 @@ static void m1543_irq_setup(void) ...@@ -90,7 +88,7 @@ static void m1543_irq_setup(void)
} }
void ddb_local0_irqdispatch(struct pt_regs *regs) static void ddb_local0_irqdispatch(struct pt_regs *regs)
{ {
u32 mask; u32 mask;
int nile4_irq; int nile4_irq;
...@@ -118,29 +116,41 @@ void ddb_local0_irqdispatch(struct pt_regs *regs) ...@@ -118,29 +116,41 @@ void ddb_local0_irqdispatch(struct pt_regs *regs)
} }
} }
void ddb_local1_irqdispatch(void) static void ddb_local1_irqdispatch(void)
{ {
printk("ddb_local1_irqdispatch called\n"); printk("ddb_local1_irqdispatch called\n");
} }
void ddb_buserror_irq(void) static void ddb_buserror_irq(void)
{ {
printk("ddb_buserror_irq called\n"); printk("ddb_buserror_irq called\n");
} }
void ddb_8254timer_irq(void) static void ddb_8254timer_irq(void)
{ {
printk("ddb_8254timer_irq called\n"); printk("ddb_8254timer_irq called\n");
} }
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending = read_c0_cause() & read_c0_status();
if (pending & CAUSEF_IP2)
ddb_local0_irqdispatch(regs);
else if (pending & CAUSEF_IP3)
ddb_local1_irqdispatch();
else if (pending & CAUSEF_IP6)
ddb_buserror_irq();
else if (pending & (CAUSEF_IP4 | CAUSEF_IP5))
ddb_8254timer_irq();
}
void __init arch_init_irq(void) void __init arch_init_irq(void)
{ {
/* setup cascade interrupts */ /* setup cascade interrupts */
setup_irq(NILE4_IRQ_BASE + NILE4_INT_INTE, &irq_cascade); setup_irq(NILE4_IRQ_BASE + NILE4_INT_INTE, &irq_cascade);
setup_irq(CPU_IRQ_BASE + CPU_NILE4_CASCADE, &irq_cascade); setup_irq(CPU_IRQ_BASE + CPU_NILE4_CASCADE, &irq_cascade);
set_except_vector(0, ddbIRQ);
nile4_irq_setup(NILE4_IRQ_BASE); nile4_irq_setup(NILE4_IRQ_BASE);
m1543_irq_setup(); m1543_irq_setup();
init_i8259_irqs(); init_i8259_irqs();
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# under Linux. # under Linux.
# #
obj-y += setup.o irq.o int-handler.o nile4_pic.o vrc5476_irq.o obj-y += setup.o irq.o nile4_pic.o vrc5476_irq.o
obj-$(CONFIG_KGDB) += dbg_io.o obj-$(CONFIG_KGDB) += dbg_io.o
EXTRA_AFLAGS := $(CFLAGS) EXTRA_AFLAGS := $(CFLAGS)
/*
* Copyright 2001 MontaVista Software Inc.
* Author: jsun@mvista.com or jsun@junsun.net
*
* First-level interrupt dispatcher for ddb5476
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/addrspace.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
#include <asm/ddb5xxx/ddb5476.h>
/*
* first level interrupt dispatcher for ocelot board -
* We check for the timer first, then check PCI ints A and D.
* Then check for serial IRQ and fall through.
*/
.align 5
NESTED(ddb5476_handle_int, PT_SIZE, sp)
SAVE_ALL
CLI
.set at
.set noreorder
mfc0 t0, CP0_CAUSE
mfc0 t2, CP0_STATUS
and t0, t2
andi t1, t0, STATUSF_IP7 /* cpu timer */
bnez t1, ll_cpu_ip7
andi t1, t0, STATUSF_IP2 /* vrc5476 & i8259 */
bnez t1, ll_cpu_ip2
andi t1, t0, STATUSF_IP3
bnez t1, ll_cpu_ip3
andi t1, t0, STATUSF_IP4
bnez t1, ll_cpu_ip4
andi t1, t0, STATUSF_IP5
bnez t1, ll_cpu_ip5
andi t1, t0, STATUSF_IP6
bnez t1, ll_cpu_ip6
andi t1, t0, STATUSF_IP0 /* software int 0 */
bnez t1, ll_cpu_ip0
andi t1, t0, STATUSF_IP1 /* software int 1 */
bnez t1, ll_cpu_ip1
nop
.set reorder
/* wrong alarm or masked ... */
// jal spurious_interrupt
// j ret_from_irq
move a0, sp
jal vrc5476_irq_dispatch
j ret_from_irq
nop
.align 5
ll_cpu_ip0:
li a0, CPU_IRQ_BASE + 0
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cpu_ip1:
li a0, CPU_IRQ_BASE + 1
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cpu_ip2: /* jump to second-level dispatching */
move a0, sp
jal vrc5476_irq_dispatch
j ret_from_irq
ll_cpu_ip3:
li a0, CPU_IRQ_BASE + 3
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cpu_ip4:
li a0, CPU_IRQ_BASE + 4
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cpu_ip5:
li a0, CPU_IRQ_BASE + 5
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cpu_ip6:
li a0, CPU_IRQ_BASE + 6
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cpu_ip7:
li a0, CPU_IRQ_BASE + 7
move a1, sp
jal do_IRQ
j ret_from_irq
END(ddb5476_handle_int)
...@@ -110,11 +110,36 @@ static void nile4_irq_setup(void) ...@@ -110,11 +110,36 @@ static void nile4_irq_setup(void)
static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL }; static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL };
static struct irqaction irq_error = { no_action, 0, CPU_MASK_NONE, "error", NULL, NULL }; static struct irqaction irq_error = { no_action, 0, CPU_MASK_NONE, "error", NULL, NULL };
extern asmlinkage void ddb5476_handle_int(void);
extern int setup_irq(unsigned int irq, struct irqaction *irqaction); extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
extern void mips_cpu_irq_init(u32 irq_base); extern void mips_cpu_irq_init(u32 irq_base);
extern void vrc5476_irq_init(u32 irq_base); extern void vrc5476_irq_init(u32 irq_base);
extern void vrc5476_irq_dispatch(struct pt_regs *regs);
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending = read_c0_cause() & read_c0_status();
if (pending & STATUSF_IP7)
do_IRQ(CPU_IRQ_BASE + 7, regs);
else if (pending & STATUSF_IP2)
vrc5476_irq_dispatch(regs);
else if (pending & STATUSF_IP3)
do_IRQ(CPU_IRQ_BASE + 3, regs);
else if (pending & STATUSF_IP4)
do_IRQ(CPU_IRQ_BASE + 4, regs);
else if (pending & STATUSF_IP5)
do_IRQ(CPU_IRQ_BASE + 5, regs);
else if (pending & STATUSF_IP6)
do_IRQ(CPU_IRQ_BASE + 6, regs);
else if (pending & STATUSF_IP0)
do_IRQ(CPU_IRQ_BASE, regs);
else if (pending & STATUSF_IP1)
do_IRQ(CPU_IRQ_BASE + 1, regs);
vrc5476_irq_dispatch(regs);
}
void __init arch_init_irq(void) void __init arch_init_irq(void)
{ {
/* hardware initialization */ /* hardware initialization */
...@@ -137,7 +162,4 @@ void __init arch_init_irq(void) ...@@ -137,7 +162,4 @@ void __init arch_init_irq(void)
setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_LBRT, &irq_error); setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_LBRT, &irq_error);
setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_PCIS, &irq_error); setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_PCIS, &irq_error);
setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_PCI, &irq_error); setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_PCI, &irq_error);
/* setup the grandpa intr vector */
set_except_vector(0, ddb5476_handle_int);
} }
...@@ -77,7 +77,7 @@ vrc5476_irq_init(u32 base) ...@@ -77,7 +77,7 @@ vrc5476_irq_init(u32 base)
} }
asmlinkage void void
vrc5476_irq_dispatch(struct pt_regs *regs) vrc5476_irq_dispatch(struct pt_regs *regs)
{ {
u32 mask; u32 mask;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Makefile for NEC DDB-Vrc5477 board # Makefile for NEC DDB-Vrc5477 board
# #
obj-y += int-handler.o irq.o irq_5477.o setup.o lcd44780.o obj-y += irq.o irq_5477.o setup.o lcd44780.o
obj-$(CONFIG_RUNTIME_DEBUG) += debug.o obj-$(CONFIG_RUNTIME_DEBUG) += debug.o
obj-$(CONFIG_KGDB) += kgdb_io.o obj-$(CONFIG_KGDB) += kgdb_io.o
......
/*
* Copyright 2001 MontaVista Software Inc.
* Author: jsun@mvista.com or jsun@junsun.net
*
* First-level interrupt dispatcher for ddb5477
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/addrspace.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
#include <asm/ddb5xxx/ddb5477.h>
/*
* first level interrupt dispatcher for ocelot board -
* We check for the timer first, then check PCI ints A and D.
* Then check for serial IRQ and fall through.
*/
.align 5
NESTED(ddb5477_handle_int, PT_SIZE, sp)
SAVE_ALL
CLI
.set at
.set noreorder
mfc0 t0, CP0_CAUSE
mfc0 t2, CP0_STATUS
and t0, t2
andi t1, t0, STATUSF_IP7 /* cpu timer */
bnez t1, ll_cputimer_irq
andi t1, t0, (STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP5 | STATUSF_IP6 )
bnez t1, ll_vrc5477_irq
andi t1, t0, STATUSF_IP0 /* software int 0 */
bnez t1, ll_cpu_ip0
andi t1, t0, STATUSF_IP1 /* software int 1 */
bnez t1, ll_cpu_ip1
nop
.set reorder
/* wrong alarm or masked ... */
jal spurious_interrupt
j ret_from_irq
END(ddb5477_handle_int)
.align 5
ll_vrc5477_irq:
move a0, sp
jal vrc5477_irq_dispatch
j ret_from_irq
ll_cputimer_irq:
li a0, CPU_IRQ_BASE + 7
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cpu_ip0:
li a0, CPU_IRQ_BASE + 0
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cpu_ip1:
li a0, CPU_IRQ_BASE + 1
move a1, sp
jal do_IRQ
j ret_from_irq
...@@ -75,7 +75,6 @@ set_pci_int_attr(u32 pci, u32 intn, u32 active, u32 trigger) ...@@ -75,7 +75,6 @@ set_pci_int_attr(u32 pci, u32 intn, u32 active, u32 trigger)
extern void vrc5477_irq_init(u32 base); extern void vrc5477_irq_init(u32 base);
extern void mips_cpu_irq_init(u32 base); extern void mips_cpu_irq_init(u32 base);
extern asmlinkage void ddb5477_handle_int(void);
extern int setup_irq(unsigned int irq, struct irqaction *irqaction); extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL }; static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL };
...@@ -135,9 +134,6 @@ void __init arch_init_irq(void) ...@@ -135,9 +134,6 @@ void __init arch_init_irq(void)
/* setup cascade interrupts */ /* setup cascade interrupts */
setup_irq(VRC5477_IRQ_BASE + VRC5477_I8259_CASCADE, &irq_cascade); setup_irq(VRC5477_IRQ_BASE + VRC5477_I8259_CASCADE, &irq_cascade);
setup_irq(CPU_IRQ_BASE + CPU_VRC5477_CASCADE, &irq_cascade); setup_irq(CPU_IRQ_BASE + CPU_VRC5477_CASCADE, &irq_cascade);
/* hook up the first-level interrupt handler */
set_except_vector(0, ddb5477_handle_int);
} }
u8 i8259_interrupt_ack(void) u8 i8259_interrupt_ack(void)
...@@ -159,7 +155,7 @@ u8 i8259_interrupt_ack(void) ...@@ -159,7 +155,7 @@ u8 i8259_interrupt_ack(void)
* the first level int-handler will jump here if it is a vrc5477 irq * the first level int-handler will jump here if it is a vrc5477 irq
*/ */
#define NUM_5477_IRQS 32 #define NUM_5477_IRQS 32
asmlinkage void static void
vrc5477_irq_dispatch(struct pt_regs *regs) vrc5477_irq_dispatch(struct pt_regs *regs)
{ {
u32 intStatus; u32 intStatus;
...@@ -197,3 +193,21 @@ vrc5477_irq_dispatch(struct pt_regs *regs) ...@@ -197,3 +193,21 @@ vrc5477_irq_dispatch(struct pt_regs *regs)
} }
} }
} }
#define VR5477INTS (STATUSF_IP2|STATUSF_IP3|STATUSF_IP4|STATUSF_IP5|STATUSF_IP6)
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending = read_c0_cause() & read_c0_status();
if (pending & STATUSF_IP7)
do_IRQ(CPU_IRQ_BASE + 7, regs);
else if (pending & VR5477INTS)
vrc5477_irq_dispatch(regs);
else if (pending & STATUSF_IP0)
do_IRQ(CPU_IRQ_BASE, regs);
else if (pending & STATUSF_IP1)
do_IRQ(CPU_IRQ_BASE + 1, regs);
else
spurious_interrupt(regs);
}
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
.text .text
.set noreorder .set noreorder
/* /*
* decstation_handle_int: Interrupt handler for DECstations * plat_irq_dispatch: Interrupt handler for DECstations
* *
* We follow the model in the Indy interrupt code by David Miller, where he * We follow the model in the Indy interrupt code by David Miller, where he
* says: a lot of complication here is taken away because: * says: a lot of complication here is taken away because:
...@@ -125,11 +125,7 @@ ...@@ -125,11 +125,7 @@
* just take another exception, big deal. * just take another exception, big deal.
*/ */
.align 5 .align 5
NESTED(decstation_handle_int, PT_SIZE, ra) NESTED(plat_irq_dispatch, PT_SIZE, ra)
.set noat
SAVE_ALL
CLI # TEST: interrupts should be off
.set at
.set noreorder .set noreorder
/* /*
...@@ -286,7 +282,7 @@ spurious: ...@@ -286,7 +282,7 @@ spurious:
nop nop
j ret_from_irq j ret_from_irq
nop nop
END(decstation_handle_int) END(plat_irq_dispatch)
/* /*
* Generic unimplemented interrupt routines -- cpu_mask_nr_tbl * Generic unimplemented interrupt routines -- cpu_mask_nr_tbl
......
...@@ -48,8 +48,6 @@ extern void dec_machine_halt(void); ...@@ -48,8 +48,6 @@ extern void dec_machine_halt(void);
extern void dec_machine_power_off(void); extern void dec_machine_power_off(void);
extern irqreturn_t dec_intr_halt(int irq, void *dev_id, struct pt_regs *regs); extern irqreturn_t dec_intr_halt(int irq, void *dev_id, struct pt_regs *regs);
extern asmlinkage void decstation_handle_int(void);
unsigned long dec_kn_slot_base, dec_kn_slot_size; unsigned long dec_kn_slot_base, dec_kn_slot_size;
EXPORT_SYMBOL(dec_kn_slot_base); EXPORT_SYMBOL(dec_kn_slot_base);
...@@ -744,7 +742,6 @@ void __init arch_init_irq(void) ...@@ -744,7 +742,6 @@ void __init arch_init_irq(void)
panic("Don't know how to set this up!"); panic("Don't know how to set this up!");
break; break;
} }
set_except_vector(0, decstation_handle_int);
/* Free the FPU interrupt if the exception is present. */ /* Free the FPU interrupt if the exception is present. */
if (!cpu_has_nofpuex) { if (!cpu_has_nofpuex) {
......
...@@ -6,4 +6,4 @@ ...@@ -6,4 +6,4 @@
# Makefile for the Galileo EV96100 board. # Makefile for the Galileo EV96100 board.
# #
obj-y += init.o irq.o puts.o reset.o time.o int-handler.o setup.o obj-y += init.o irq.o puts.o reset.o time.o setup.o
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
.set noat
.align 5
NESTED(ev96100IRQ, PT_SIZE, sp)
SAVE_ALL
CLI # Important: mark KERNEL mode !
mfc0 t0, CP0_CAUSE # get pending interrupts
mfc0 t1, CP0_STATUS # get enabled interrupts
and t0, t1 # isolate allowed ones
# FIX ME add R7000 extensions
andi t0,0xff00 # isolate pending bits
andi a0, t0, CAUSEF_IP7
beq a0, zero, 1f
move a0, sp
jal mips_timer_interrupt
j ret_from_irq
1: beqz t0, 3f # spurious interrupt
move a0, t0
move a1, sp
jal ev96100_cpu_irq
j ret_from_irq
3: jal spurious_interrupt
j ret_from_irq
END(ev96100IRQ)
...@@ -40,8 +40,6 @@ ...@@ -40,8 +40,6 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <asm/irq_cpu.h> #include <asm/irq_cpu.h>
extern asmlinkage void ev96100IRQ(void);
static inline unsigned int ffz8(unsigned int word) static inline unsigned int ffz8(unsigned int word)
{ {
unsigned long k; unsigned long k;
...@@ -54,13 +52,26 @@ static inline unsigned int ffz8(unsigned int word) ...@@ -54,13 +52,26 @@ static inline unsigned int ffz8(unsigned int word)
return k; return k;
} }
extern void mips_timer_interrupt(struct pt_regs *regs);
asmlinkage void ev96100_cpu_irq(unsigned int pending, struct pt_regs *regs) asmlinkage void ev96100_cpu_irq(unsigned int pending, struct pt_regs *regs)
{ {
do_IRQ(ffz8(pending >> 8), regs); do_IRQ(ffz8(pending >> 8), regs);
} }
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
if (pending & CAUSEF_IP7)
mips_timer_interrupt(regs);
else if (pending)
ev96100_cpu_irq(pending, regs);
else
spurious_interrupt(regs);
}
void __init arch_init_irq(void) void __init arch_init_irq(void)
{ {
set_except_vector(0, ev96100IRQ);
mips_cpu_irq_init(0); mips_cpu_irq_init(0);
} }
...@@ -6,6 +6,6 @@ ...@@ -6,6 +6,6 @@
# Makefile for the Galileo EV64120 board. # Makefile for the Galileo EV64120 board.
# #
obj-y += int-handler.o irq.o promcon.o reset.o serialGT.o setup.o obj-y += irq.o promcon.o reset.o serialGT.o setup.o
EXTRA_AFLAGS := $(CFLAGS) EXTRA_AFLAGS := $(CFLAGS)
/*
* int-handler.S
*
* Based on the cobalt handler.
*/
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/addrspace.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
/*
* galileo_handle_int -
* We check for the timer first, then check PCI ints A and D.
* Then check for serial IRQ and fall through.
*/
.align 5
.set reorder
.set noat
NESTED(galileo_handle_int, PT_SIZE, sp)
SAVE_ALL
CLI
.set at
mfc0 t0,CP0_CAUSE
mfc0 t2,CP0_STATUS
and t0,t2
andi t1,t0,STATUSF_IP4 /* int2 hardware line (timer) */
bnez t1,ll_gt64120_irq
andi t1,t0,STATUSF_IP2 /* int0 hardware line */
bnez t1,ll_pci_intA
andi t1,t0,STATUSF_IP5 /* int3 hardware line */
bnez t1,ll_pci_intD
andi t1,t0,STATUSF_IP6 /* int4 hardware line */
bnez t1,ll_serial_irq
andi t1,t0,STATUSF_IP7 /* compare int */
bnez t1,ll_compare_irq
nop
/* wrong alarm or masked ... */
jal spurious_interrupt
nop
j ret_from_irq
END(galileo_handle_int)
.align 5
.set reorder
ll_gt64120_irq:
li a0,4
move a1,sp
jal do_IRQ
nop
j ret_from_irq
nop
.align 5
.set reorder
ll_compare_irq:
li a0,7
move a1,sp
jal do_IRQ
nop
j ret_from_irq
nop
.align 5
.set reorder
ll_pci_intA:
move a0,sp
jal pci_intA
nop
j ret_from_irq
nop
#if 0
.align 5
.set reorder
ll_pci_intB:
move a0,sp
jal pci_intB
nop
j ret_from_irq
nop
.align 5
.set reorder
ll_pci_intC:
move a0,sp
jal pci_intC
nop
j ret_from_irq
nop
#endif
.align 5
.set reorder
ll_pci_intD:
move a0,sp
jal pci_intD
nop
j ret_from_irq
nop
.align 5
.set reorder
ll_serial_irq:
li a0,6
move a1,sp
jal do_IRQ
nop
j ret_from_irq
nop
...@@ -46,14 +46,22 @@ ...@@ -46,14 +46,22 @@
#include <asm/system.h> #include <asm/system.h>
#include <asm/gt64120.h> #include <asm/gt64120.h>
asmlinkage inline void pci_intA(struct pt_regs *regs) asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{ {
do_IRQ(GT_INTA, regs); unsigned int pending = read_c0_status() & read_c0_cause();
}
asmlinkage inline void pci_intD(struct pt_regs *regs) if (pending & STATUSF_IP4) /* int2 hardware line (timer) */
{ do_IRQ(4, regs);
else if (pending & STATUSF_IP2) /* int0 hardware line */
do_IRQ(GT_INTA, regs);
else if (pending & STATUSF_IP5) /* int3 hardware line */
do_IRQ(GT_INTD, regs); do_IRQ(GT_INTD, regs);
else if (pending & STATUSF_IP6) /* int4 hardware line */
do_IRQ(6, regs);
else if (pending & STATUSF_IP7) /* compare int */
do_IRQ(7, regs);
else
spurious_interrupt(regs);
} }
static void disable_ev64120_irq(unsigned int irq_nr) static void disable_ev64120_irq(unsigned int irq_nr)
...@@ -109,16 +117,11 @@ static struct hw_interrupt_type ev64120_irq_type = { ...@@ -109,16 +117,11 @@ static struct hw_interrupt_type ev64120_irq_type = {
void gt64120_irq_setup(void) void gt64120_irq_setup(void)
{ {
extern asmlinkage void galileo_handle_int(void);
/* /*
* Clear all of the interrupts while we change the able around a bit. * Clear all of the interrupts while we change the able around a bit.
*/ */
clear_c0_status(ST0_IM); clear_c0_status(ST0_IM);
/* Sets the exception_handler array. */
set_except_vector(0, galileo_handle_int);
local_irq_disable(); local_irq_disable();
/* /*
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Makefile for Momentum's Ocelot board. # Makefile for Momentum's Ocelot board.
# #
obj-y += int-handler.o irq.o prom.o reset.o setup.o obj-y += irq.o prom.o reset.o setup.o
obj-$(CONFIG_KGDB) += dbg_io.o obj-$(CONFIG_KGDB) += dbg_io.o
......
/*
* Copyright 2001 MontaVista Software Inc.
* Author: jsun@mvista.com or jsun@junsun.net
*
* First-level interrupt dispatcher for ocelot board.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/addrspace.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
/*
* first level interrupt dispatcher for ocelot board -
* We check for the timer first, then check PCI ints A and D.
* Then check for serial IRQ and fall through.
*/
.align 5
NESTED(ocelot_handle_int, PT_SIZE, sp)
SAVE_ALL
CLI
.set at
mfc0 t0, CP0_CAUSE
mfc0 t2, CP0_STATUS
and t0, t2
andi t1, t0, STATUSF_IP2 /* int0 hardware line */
bnez t1, ll_pri_enet_irq
andi t1, t0, STATUSF_IP3 /* int1 hardware line */
bnez t1, ll_sec_enet_irq
andi t1, t0, STATUSF_IP4 /* int2 hardware line */
bnez t1, ll_uart1_irq
andi t1, t0, STATUSF_IP5 /* int3 hardware line */
bnez t1, ll_cpci_irq
andi t1, t0, STATUSF_IP6 /* int4 hardware line */
bnez t1, ll_galileo_irq
andi t1, t0, STATUSF_IP7 /* cpu timer */
bnez t1, ll_cputimer_irq
/* now look at the extended interrupts */
mfc0 t0, CP0_CAUSE
cfc0 t1, CP0_S1_INTCONTROL
/* shift the mask 8 bits left to line up the bits */
sll t2, t1, 8
and t0, t2
srl t0, t0, 16
andi t1, t0, STATUSF_IP8 /* int6 hardware line */
bnez t1, ll_pmc1_irq
andi t1, t0, STATUSF_IP9 /* int7 hardware line */
bnez t1, ll_pmc2_irq
andi t1, t0, STATUSF_IP10 /* int8 hardware line */
bnez t1, ll_cpci_abcd_irq
andi t1, t0, STATUSF_IP11 /* int9 hardware line */
bnez t1, ll_uart2_irq
.set reorder
/* wrong alarm or masked ... */
j spurious_interrupt
nop
END(ocelot_handle_int)
.align 5
ll_pri_enet_irq:
li a0, 2
move a1, sp
jal do_IRQ
j ret_from_irq
ll_sec_enet_irq:
li a0, 3
move a1, sp
jal do_IRQ
j ret_from_irq
ll_uart1_irq:
li a0, 4
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cpci_irq:
li a0, 5
move a1, sp
jal do_IRQ
j ret_from_irq
ll_galileo_irq:
li a0, 6
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cputimer_irq:
li a0, 7
move a1, sp
jal do_IRQ
j ret_from_irq
ll_pmc1_irq:
li a0, 8
move a1, sp
jal do_IRQ
j ret_from_irq
ll_pmc2_irq:
li a0, 9
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cpci_abcd_irq:
li a0, 10
move a1, sp
jal do_IRQ
j ret_from_irq
ll_uart2_irq:
li a0, 11
move a1, sp
jal do_IRQ
j ret_from_irq
...@@ -48,7 +48,38 @@ ...@@ -48,7 +48,38 @@
#include <asm/mipsregs.h> #include <asm/mipsregs.h>
#include <asm/system.h> #include <asm/system.h>
extern asmlinkage void ocelot_handle_int(void); asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending = read_c0_status() & read_c0_cause();
if (pending & STATUSF_IP2) /* int0 hardware line */
do_IRQ(2, regs);
else if (pending & STATUSF_IP3) /* int1 hardware line */
do_IRQ(3, regs);
else if (pending & STATUSF_IP4) /* int2 hardware line */
do_IRQ(4, regs);
else if (pending & STATUSF_IP5) /* int3 hardware line */
do_IRQ(5, regs);
else if (pending & STATUSF_IP6) /* int4 hardware line */
do_IRQ(6, regs);
else if (pending & STATUSF_IP7) /* cpu timer */
do_IRQ(7, regs);
else {
/*
* Now look at the extended interrupts
*/
pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16;
if (pending & STATUSF_IP8) /* int6 hardware line */
do_IRQ(8, regs);
else if (pending & STATUSF_IP9) /* int7 hardware line */
do_IRQ(9, regs);
else if (pending & STATUSF_IP10) /* int8 hardware line */
do_IRQ(10, regs);
else if (pending & STATUSF_IP11) /* int9 hardware line */
do_IRQ(11, regs);
}
}
void __init arch_init_irq(void) void __init arch_init_irq(void)
{ {
...@@ -59,9 +90,6 @@ void __init arch_init_irq(void) ...@@ -59,9 +90,6 @@ void __init arch_init_irq(void)
clear_c0_status(ST0_IM); clear_c0_status(ST0_IM);
local_irq_disable(); local_irq_disable();
/* Sets the first-level interrupt dispatcher. */
set_except_vector(0, ocelot_handle_int);
mips_cpu_irq_init(0); mips_cpu_irq_init(0);
rm7k_cpu_irq_init(8); rm7k_cpu_irq_init(8);
} }
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
# Makefile for the ITE 8172 (qed-4n-s01b) board, generic files. # Makefile for the ITE 8172 (qed-4n-s01b) board, generic files.
# #
obj-y += it8172_setup.o irq.o int-handler.o pmon_prom.o \ obj-y += it8172_setup.o irq.o pmon_prom.o \
time.o lpc.o puts.o reset.o time.o lpc.o puts.o reset.o
obj-$(CONFIG_IT8172_CIR)+= it8172_cir.o obj-$(CONFIG_IT8172_CIR)+= it8172_cir.o
......
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
.text
.set macro
.set noat
.align 5
NESTED(it8172_IRQ, PT_SIZE, sp)
SAVE_ALL
CLI # Important: mark KERNEL mode !
/* We're working with 'reorder' set at this point. */
/*
* Get pending interrupts
*/
mfc0 t0,CP0_CAUSE # get pending interrupts
mfc0 t1,CP0_STATUS # get enabled interrupts
and t0,t1 # isolate allowed ones
andi t0,0xff00 # isolate pending bits
beqz t0, 3f # spurious interrupt
andi a0, t0, CAUSEF_IP7
beq a0, zero, 1f
li a0, 127 # MIPS_CPU_TIMER_IRQ = (NR_IRQS-1)
move a1, sp
jal ll_timer_interrupt
j ret_from_irq
nop
1:
andi a0, t0, CAUSEF_IP2 # the only int we expect at this time
beq a0, zero, 3f
move a0,sp
jal it8172_hw0_irqdispatch
mfc0 t0,CP0_STATUS # disable interrupts
ori t0,1
xori t0,1
mtc0 t0,CP0_STATUS
nop
nop
nop
la a1, ret_from_irq
jr a1
nop
3:
move a0, sp
jal mips_spurious_interrupt
nop
la a1, ret_from_irq
jr a1
nop
END(it8172_IRQ)
...@@ -64,7 +64,6 @@ ...@@ -64,7 +64,6 @@
extern void set_debug_traps(void); extern void set_debug_traps(void);
extern void mips_timer_interrupt(int irq, struct pt_regs *regs); extern void mips_timer_interrupt(int irq, struct pt_regs *regs);
extern asmlinkage void it8172_IRQ(void);
struct it8172_intc_regs volatile *it8172_hw0_icregs = struct it8172_intc_regs volatile *it8172_hw0_icregs =
(struct it8172_intc_regs volatile *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_INTC_BASE)); (struct it8172_intc_regs volatile *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_INTC_BASE));
...@@ -178,8 +177,6 @@ void __init arch_init_irq(void) ...@@ -178,8 +177,6 @@ void __init arch_init_irq(void)
int i; int i;
unsigned long flags; unsigned long flags;
set_except_vector(0, it8172_IRQ);
/* mask all interrupts */ /* mask all interrupts */
it8172_hw0_icregs->lb_mask = 0xffff; it8172_hw0_icregs->lb_mask = 0xffff;
it8172_hw0_icregs->lpc_mask = 0xffff; it8172_hw0_icregs->lpc_mask = 0xffff;
...@@ -279,6 +276,18 @@ void it8172_hw0_irqdispatch(struct pt_regs *regs) ...@@ -279,6 +276,18 @@ void it8172_hw0_irqdispatch(struct pt_regs *regs)
do_IRQ(irq, regs); do_IRQ(irq, regs);
} }
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
if (!pending)
mips_spurious_interrupt(regs);
else if (pending & CAUSEF_IP7)
ll_timer_interrupt(127, regs);
else if (pending & CAUSEF_IP2)
it8172_hw0_irqdispatch(regs);
}
void show_pending_irqs(void) void show_pending_irqs(void)
{ {
fputs("intstatus: "); fputs("intstatus: ");
......
...@@ -2,6 +2,6 @@ ...@@ -2,6 +2,6 @@
# Makefile for the Jazz family specific parts of the kernel # Makefile for the Jazz family specific parts of the kernel
# #
obj-y := int-handler.o irq.o jazzdma.o reset.o setup.o obj-y := irq.o jazzdma.o reset.o setup.o
EXTRA_AFLAGS := $(CFLAGS) EXTRA_AFLAGS := $(CFLAGS)
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle and Andreas Busse
*
* Jazz family specific interrupt stuff
*
* To do: On Jazz machines we remap some non-ISA interrupts to ISA
* interrupts. These interrupts should use their own vectors.
* Squeeze the last cycles out of the handlers. Only a dead
* cycle is a good cycle.
*/
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/jazz.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
/*
* jazz_handle_int: Interrupt handler for the ACER Pica-61 boards
*/
.set noreorder
NESTED(jazz_handle_int, PT_SIZE, ra)
.set noat
SAVE_ALL
CLI
.set at
/*
* Get pending interrupts
*/
mfc0 t0,CP0_CAUSE # get pending interrupts
mfc0 t1,CP0_STATUS # get enabled interrupts
and t0,t1 # isolate allowed ones
andi t0,0xff00 # isolate pending bits
beqz t0,3f
sll t0,16 # delay slot
/*
* Find irq with highest priority
* FIXME: This is slow - use binary search
*/
la t1,ll_vectors
1: bltz t0,2f # found pending irq
sll t0,1
b 1b
subu t1,PTRSIZE # delay slot
/*
* Do the low-level stuff
*/
2: lw t0,(t1)
jr t0
nop # delay slot
END(jazz_handle_int)
ll_sw0: li s1,~IE_SW0
mfc0 t0,CP0_CAUSE
and t0,s1
mtc0 t0,CP0_CAUSE
PANIC("Unimplemented sw0 handler")
ll_sw1: li s1,~IE_SW1
mfc0 t0,CP0_CAUSE
and t0,s1
mtc0 t0,CP0_CAUSE
PANIC("Unimplemented sw1 handler")
ll_local_dma: li s1,~IE_IRQ0
PANIC("Unimplemented local_dma handler")
ll_local_dev: lbu t0,JAZZ_IO_IRQ_SOURCE
#if PTRSIZE == 8 /* True 64 bit kernel */
dsll t0,1
#endif
.set reorder
LONG_L t0,local_vector(t0)
jr t0
.set noreorder
/*
* The braindead PICA hardware gives us no way to distinguish if we really
* received interrupt 7 from the (E)ISA bus or if we just received an
* interrupt with no findable cause. This sometimes happens with braindead
* cards. Oh well - for all the Jazz boxes slots are more or less just
* whistles and bells and we're aware of the problem.
*/
ll_isa_irq: lw a0, JAZZ_EISA_IRQ_ACK
jal do_IRQ
move a1,sp
j ret_from_irq
nop
/*
* Hmm... This is not just a plain PC clone so the question is
* which devices on Jazz machines can generate an (E)ISA NMI?
* (Writing to nonexistent memory?)
*/
ll_isa_nmi: li s1,~IE_IRQ3
PANIC("Unimplemented isa_nmi handler")
/*
* Timer IRQ - remapped to be more similar to an IBM compatible.
*
* The timer interrupt is handled specially to ensure that the jiffies
* variable is updated at all times. Specifically, the timer interrupt is
* just like the complete handlers except that it is invoked with interrupts
* disabled and should never re-enable them. If other interrupts were
* allowed to be processed while the timer interrupt is active, then the
* other interrupts would have to avoid using the jiffies variable for delay
* and interval timing operations to avoid hanging the system.
*/
ll_timer: lw zero,JAZZ_TIMER_REGISTER # timer irq cleared on read
li s1,~IE_IRQ4
li a0, JAZZ_TIMER_IRQ
jal do_IRQ
move a1,sp
mfc0 t0,CP0_STATUS # disable interrupts again
ori t0,1
xori t0,1
mtc0 t0,CP0_STATUS
j ret_from_irq
nop
/*
* CPU count/compare IRQ (unused)
*/
ll_count: j ret_from_irq
mtc0 zero,CP0_COMPARE
#if 0
/*
* Call the handler for the interrupt
* (Currently unused)
*/
call_real: /*
* temporarily disable interrupt
*/
mfc0 t2,CP0_STATUS
and t2,s1
mtc0 t2,CP0_STATUS
nor s1,zero,s1
jal do_IRQ
/*
* reenable interrupt
*/
mfc0 t2,CP0_STATUS
or t2,s1
mtc0 t2,CP0_STATUS
j ret_from_irq
#endif
.data
PTR ll_sw0 # SW0
PTR ll_sw1 # SW1
PTR ll_local_dma # Local DMA
PTR ll_local_dev # Local devices
PTR ll_isa_irq # ISA IRQ
PTR ll_isa_nmi # ISA NMI
PTR ll_timer # Timer
ll_vectors: PTR ll_count # Count/Compare IRQ
/*
* Interrupt handlers for local devices.
*/
.text
.set reorder
loc_no_irq: PANIC("Unimplemented loc_no_irq handler")
/*
* Parallel port IRQ
*/
loc_parallel: li s1,~JAZZ_IE_PARALLEL
li a0,JAZZ_PARALLEL_IRQ
b loc_call
/*
* Floppy IRQ
*/
loc_floppy: li s1,~JAZZ_IE_FLOPPY
li a0,JAZZ_FLOPPY_IRQ
b loc_call
/*
* Sound IRQ
*/
loc_sound: PANIC("Unimplemented loc_sound handler")
loc_video: PANIC("Unimplemented loc_video handler")
/*
* Ethernet interrupt handler
*/
loc_ethernet: li s1,~JAZZ_IE_ETHERNET
li a0,JAZZ_ETHERNET_IRQ
b loc_call
/*
* SCSI interrupt handler
*/
loc_scsi: li s1,~JAZZ_IE_SCSI
li a0,JAZZ_SCSI_IRQ
b loc_call
/*
* Keyboard interrupt handler
*/
loc_keyboard: li s1,~JAZZ_IE_KEYBOARD
li a0,JAZZ_KEYBOARD_IRQ
b loc_call
/*
* Mouse interrupt handler
*/
loc_mouse: li s1,~JAZZ_IE_MOUSE
li a0,JAZZ_MOUSE_IRQ
b loc_call
/*
* Serial port 1 IRQ
*/
loc_serial1: li s1,~JAZZ_IE_SERIAL1
li a0,JAZZ_SERIAL1_IRQ
b loc_call
/*
* Serial port 2 IRQ
*/
loc_serial2: li s1,~JAZZ_IE_SERIAL2
li a0,JAZZ_SERIAL2_IRQ
b loc_call
/*
* Call the interrupt handler for an interrupt generated by a
* local device.
*/
loc_call: /*
* Temporarily disable interrupt source
*/
lhu t2,JAZZ_IO_IRQ_ENABLE
and t2,s1
sh t2,JAZZ_IO_IRQ_ENABLE
nor s1,zero,s1
jal do_IRQ
/*
* Reenable interrupt
*/
lhu t2,JAZZ_IO_IRQ_ENABLE
or t2,s1
sh t2,JAZZ_IO_IRQ_ENABLE
j ret_from_irq
/*
* "Jump extender" to reach spurious_interrupt
*/
3: jal spurious_interrupt
j ret_from_irq
/*
* Vectors for interrupts generated by local devices
*/
.data
local_vector: PTR loc_no_irq
PTR loc_parallel
PTR loc_floppy
PTR loc_sound
PTR loc_video
PTR loc_ethernet
PTR loc_scsi
PTR loc_keyboard
PTR loc_mouse
PTR loc_serial1
PTR loc_serial2
...@@ -15,8 +15,6 @@ ...@@ -15,8 +15,6 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/jazz.h> #include <asm/jazz.h>
extern asmlinkage void jazz_handle_int(void);
static DEFINE_SPINLOCK(r4030_lock); static DEFINE_SPINLOCK(r4030_lock);
static void enable_r4030_irq(unsigned int irq) static void enable_r4030_irq(unsigned int irq)
...@@ -90,10 +88,82 @@ void __init init_r4030_ints(void) ...@@ -90,10 +88,82 @@ void __init init_r4030_ints(void)
*/ */
void __init arch_init_irq(void) void __init arch_init_irq(void)
{ {
set_except_vector(0, jazz_handle_int);
init_i8259_irqs(); /* Integrated i8259 */ init_i8259_irqs(); /* Integrated i8259 */
init_r4030_ints(); init_r4030_ints();
change_c0_status(ST0_IM, IE_IRQ4 | IE_IRQ3 | IE_IRQ2 | IE_IRQ1); change_c0_status(ST0_IM, IE_IRQ4 | IE_IRQ3 | IE_IRQ2 | IE_IRQ1);
} }
static void loc_call(unsigned int irq, struct pt_regs *regs, unsigned int mask)
{
r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) & mask);
do_IRQ(irq, regs);
r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) | mask);
}
static void ll_local_dev(struct pt_regs *regs)
{
switch (r4030_read_reg32(JAZZ_IO_IRQ_SOURCE)) {
case 0:
panic("Unimplemented loc_no_irq handler");
break;
case 4:
loc_call(JAZZ_PARALLEL_IRQ, regs, JAZZ_IE_PARALLEL);
break;
case 8:
loc_call(JAZZ_PARALLEL_IRQ, regs, JAZZ_IE_FLOPPY);
break;
case 12:
panic("Unimplemented loc_sound handler");
break;
case 16:
panic("Unimplemented loc_video handler");
break;
case 20:
loc_call(JAZZ_ETHERNET_IRQ, regs, JAZZ_IE_ETHERNET);
break;
case 24:
loc_call(JAZZ_SCSI_IRQ, regs, JAZZ_IE_SCSI);
break;
case 28:
loc_call(JAZZ_KEYBOARD_IRQ, regs, JAZZ_IE_KEYBOARD);
break;
case 32:
loc_call(JAZZ_MOUSE_IRQ, regs, JAZZ_IE_MOUSE);
break;
case 36:
loc_call(JAZZ_SERIAL1_IRQ, regs, JAZZ_IE_SERIAL1);
break;
case 40:
loc_call(JAZZ_SERIAL2_IRQ, regs, JAZZ_IE_SERIAL2);
break;
}
}
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
if (pending & IE_IRQ5)
write_c0_compare(0);
else if (pending & IE_IRQ4) {
r4030_read_reg32(JAZZ_TIMER_REGISTER);
do_IRQ(JAZZ_TIMER_IRQ, regs);
} else if (pending & IE_IRQ3)
panic("Unimplemented ISA NMI handler");
else if (pending & IE_IRQ2)
do_IRQ(r4030_read_reg32(JAZZ_EISA_IRQ_ACK), regs);
else if (pending & IE_IRQ1) {
ll_local_dev(regs);
} else if (unlikely(pending & IE_IRQ0))
panic("Unimplemented local_dma handler");
else if (pending & IE_SW1) {
clear_c0_cause(IE_SW1);
panic("Unimplemented sw1 handler");
} else if (pending & IE_SW0) {
clear_c0_cause(IE_SW0);
panic("Unimplemented sw0 handler");
}
}
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Makefile for TOSHIBA JMR-TX3927 board # Makefile for TOSHIBA JMR-TX3927 board
# #
obj-y += init.o int-handler.o irq.o setup.o obj-y += init.o irq.o setup.o
obj-$(CONFIG_RUNTIME_DEBUG) += debug.o obj-$(CONFIG_RUNTIME_DEBUG) += debug.o
obj-$(CONFIG_KGDB) += kgdb_io.o obj-$(CONFIG_KGDB) += kgdb_io.o
......
/*
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ahennessy@mvista.com
*
* Based on arch/mips/tsdb/kernel/int-handler.S
*
* Copyright (C) 2000-2001 Toshiba Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
#include <asm/jmr3927/jmr3927.h>
/* A lot of complication here is taken away because:
*
* 1) We handle one interrupt and return, sitting in a loop
* and moving across all the pending IRQ bits in the cause
* register is _NOT_ the answer, the common case is one
* pending IRQ so optimize in that direction.
*
* 2) We need not check against bits in the status register
* IRQ mask, that would make this routine slow as hell.
*
* 3) Linux only thinks in terms of all IRQs on or all IRQs
* off, nothing in between like BSD spl() brain-damage.
*
*/
/* Flush write buffer (needed?)
* NOTE: TX39xx performs "non-blocking load", so explicitly use the target
* register of LBU to flush immediately.
*/
#define FLUSH_WB(tmp) \
la tmp, JMR3927_IOC_REV_ADDR; \
lbu tmp, (tmp); \
move tmp, zero;
.text
.set noreorder
.set noat
.align 5
NESTED(jmr3927_IRQ, PT_SIZE, sp)
SAVE_ALL
CLI
.set at
jal jmr3927_irc_irqdispatch
move a0, sp
FLUSH_WB(t0)
j ret_from_irq
nop
END(jmr3927_IRQ)
...@@ -77,8 +77,6 @@ static int jmr3927_gen_iack(void) ...@@ -77,8 +77,6 @@ static int jmr3927_gen_iack(void)
} }
#endif #endif
extern asmlinkage void jmr3927_IRQ(void);
#define irc_dlevel 0 #define irc_dlevel 0
#define irc_elevel 1 #define irc_elevel 1
...@@ -262,7 +260,7 @@ void jmr3927_spurious(struct pt_regs *regs) ...@@ -262,7 +260,7 @@ void jmr3927_spurious(struct pt_regs *regs)
regs->cp0_cause, regs->cp0_epc, regs->regs[31]); regs->cp0_cause, regs->cp0_epc, regs->regs[31]);
} }
void jmr3927_irc_irqdispatch(struct pt_regs *regs) asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{ {
int irq; int irq;
...@@ -398,8 +396,6 @@ void __init arch_init_irq(void) ...@@ -398,8 +396,6 @@ void __init arch_init_irq(void)
jmr3927_irq_init(NR_ISA_IRQS); jmr3927_irq_init(NR_ISA_IRQS);
set_except_vector(0, jmr3927_IRQ);
/* setup irq space */ /* setup irq space */
add_tb_irq_space(&jmr3927_isac_irqspace); add_tb_irq_space(&jmr3927_isac_irqspace);
add_tb_irq_space(&jmr3927_ioc_irqspace); add_tb_irq_space(&jmr3927_ioc_irqspace);
......
...@@ -122,6 +122,20 @@ handle_vcei: ...@@ -122,6 +122,20 @@ handle_vcei:
.set pop .set pop
END(except_vec3_r4000) END(except_vec3_r4000)
__FINIT
.align 5
NESTED(handle_int, PT_SIZE, sp)
SAVE_ALL
CLI
PTR_LA ra, ret_from_irq
move a0, sp
j plat_irq_dispatch
END(handle_int)
__INIT
/* /*
* Special interrupt vector for MIPS64 ISA & embedded MIPS processors. * Special interrupt vector for MIPS64 ISA & embedded MIPS processors.
* This is a dedicated interrupt exception vector which reduces the * This is a dedicated interrupt exception vector which reduces the
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include <asm/watch.h> #include <asm/watch.h>
#include <asm/types.h> #include <asm/types.h>
extern asmlinkage void handle_int(void);
extern asmlinkage void handle_tlbm(void); extern asmlinkage void handle_tlbm(void);
extern asmlinkage void handle_tlbl(void); extern asmlinkage void handle_tlbl(void);
extern asmlinkage void handle_tlbs(void); extern asmlinkage void handle_tlbs(void);
...@@ -1296,6 +1297,7 @@ void __init trap_init(void) ...@@ -1296,6 +1297,7 @@ void __init trap_init(void)
if (board_be_init) if (board_be_init)
board_be_init(); board_be_init();
set_except_vector(0, handle_int);
set_except_vector(1, handle_tlbm); set_except_vector(1, handle_tlbm);
set_except_vector(2, handle_tlbl); set_except_vector(2, handle_tlbl);
set_except_vector(3, handle_tlbs); set_except_vector(3, handle_tlbs);
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# #
obj-y += reset.o setup.o prom.o lasat_board.o \ obj-y += reset.o setup.o prom.o lasat_board.o \
at93c.o interrupt.o lasatIRQ.o at93c.o interrupt.o
obj-$(CONFIG_LASAT_SYSCTL) += sysctl.o obj-$(CONFIG_LASAT_SYSCTL) += sysctl.o
obj-$(CONFIG_DS1603) += ds1603.o obj-$(CONFIG_DS1603) += ds1603.o
......
...@@ -27,14 +27,13 @@ ...@@ -27,14 +27,13 @@
#include <asm/bootinfo.h> #include <asm/bootinfo.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/lasat/lasatint.h> #include <asm/lasat/lasatint.h>
#include <asm/time.h>
#include <asm/gdb-stub.h> #include <asm/gdb-stub.h>
static volatile int *lasat_int_status = NULL; static volatile int *lasat_int_status = NULL;
static volatile int *lasat_int_mask = NULL; static volatile int *lasat_int_mask = NULL;
static volatile int lasat_int_mask_shift; static volatile int lasat_int_mask_shift;
extern asmlinkage void lasatIRQ(void);
void disable_lasat_irq(unsigned int irq_nr) void disable_lasat_irq(unsigned int irq_nr)
{ {
unsigned long flags; unsigned long flags;
...@@ -109,11 +108,17 @@ static unsigned long get_int_status_200(void) ...@@ -109,11 +108,17 @@ static unsigned long get_int_status_200(void)
return int_status; return int_status;
} }
void lasat_hw0_irqdispatch(struct pt_regs *regs) asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{ {
unsigned long int_status; unsigned long int_status;
unsigned int cause = read_c0_cause();
int irq; int irq;
if (cause & CAUSEF_IP7) { /* R4000 count / compare IRQ */
ll_timer_interrupt(7, regs);
return;
}
int_status = get_int_status(); int_status = get_int_status();
/* if int_status == 0, then the interrupt has already been cleared */ /* if int_status == 0, then the interrupt has already been cleared */
...@@ -147,9 +152,6 @@ void __init arch_init_irq(void) ...@@ -147,9 +152,6 @@ void __init arch_init_irq(void)
panic("arch_init_irq: mips_machtype incorrect"); panic("arch_init_irq: mips_machtype incorrect");
} }
/* Now safe to set the exception vector. */
set_except_vector(0, lasatIRQ);
for (i = 0; i <= LASATINT_END; i++) { for (i = 0; i <= LASATINT_END; i++) {
irq_desc[i].status = IRQ_DISABLED; irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = 0; irq_desc[i].action = 0;
......
/*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 1999, 2000 MIPS Technologies, Inc. All rights reserved.
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
* Interrupt exception dispatch code.
*/
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
.text
.set noreorder
.align 5
NESTED(lasatIRQ, PT_SIZE, sp)
.set noat
SAVE_ALL
CLI
.set at
.set noreorder
mfc0 s0, CP0_CAUSE # get irq mask
/* First we check for r4k counter/timer IRQ. */
andi a0, s0, CAUSEF_IP7
beq a0, zero, 1f
andi a0, s0, CAUSEF_IP2 # delay slot, check hw0 interrupt
/* Wheee, a timer interrupt. */
li a0, 7
jal ll_timer_interrupt
move a1, sp
j ret_from_irq
nop
1:
/* Wheee, combined hardware level zero interrupt. */
jal lasat_hw0_irqdispatch
move a0, sp # delay slot
j ret_from_irq
nop # delay slot
1:
/*
* Here by mistake? This is possible, what can happen is that by the
* time we take the exception the IRQ pin goes low, so just leave if
* this is the case.
*/
move a1,s0
mfc0 a1, CP0_EPC
j ret_from_irq
nop
END(lasatIRQ)
...@@ -16,5 +16,5 @@ ...@@ -16,5 +16,5 @@
# 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. # 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
# #
obj-y := atlas_int.o atlas-irq.o atlas_setup.o obj-y := atlas_int.o atlas_setup.o
obj-$(CONFIG_KGDB) += atlas_gdb.o obj-$(CONFIG_KGDB) += atlas_gdb.o
/*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 1999, 2000 MIPS Technologies, Inc. All rights reserved.
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
* Interrupt exception dispatch code.
*/
#include <linux/config.h>
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
#include <asm/mips-boards/atlasint.h>
/*
* Furthermore, the IRQs on the MIPS board look basically (barring software
* IRQs which we don't use at all and all external interrupt sources are
* combined together on hardware interrupt 0 (MIPS IRQ 2)) like:
*
* MIPS IRQ Source
* -------- ------
* 0 Software (ignored)
* 1 Software (ignored)
* 2 Combined hardware interrupt (hw0)
* 3 Hardware (ignored)
* 4 Hardware (ignored)
* 5 Hardware (ignored)
* 6 Hardware (ignored)
* 7 R4k timer (what we use)
*
* Note: On the SEAD board thing are a little bit different.
* Here IRQ 2 (hw0) is wired to the UART0 and IRQ 3 (hw1) is wired
* wired to UART1.
*
* We handle the IRQ according to _our_ priority which is:
*
* Highest ---- R4k Timer
* Lowest ---- Combined hardware interrupt
*
* then we just return, if multiple IRQs are pending then we will just take
* another exception, big deal.
*/
.text
.set noreorder
.set noat
.align 5
NESTED(mipsIRQ, PT_SIZE, sp)
SAVE_ALL
CLI
.set at
mfc0 s0, CP0_CAUSE # get irq bits
mfc0 s1, CP0_STATUS # get irq mask
andi s0, ST0_IM # CAUSE.CE may be non-zero!
and s0, s1
#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
.set mips32
clz a0, s0
.set mips0
negu a0
addu a0, 31-CAUSEB_IP
bltz a0, spurious
#else
beqz s0, spurious
li a0, 7
and t0, s0, 0xf000
sltiu t0, t0, 1
sll t0, 2
subu a0, t0
sll s0, t0
and t0, s0, 0xc000
sltiu t0, t0, 1
sll t0, 1
subu a0, t0
sll s0, t0
and t0, s0, 0x8000
sltiu t0, t0, 1
# sll t0, 0
subu a0, t0
# sll s0, t0
#endif
li a1, MIPSCPU_INT_ATLAS
bne a0, a1, 1f
addu a0, MIPSCPU_INT_BASE
jal atlas_hw0_irqdispatch
move a0, sp
j ret_from_irq
nop
1: jal do_IRQ
move a1, sp
j ret_from_irq
nop
spurious:
j spurious_interrupt
nop
END(mipsIRQ)
...@@ -39,8 +39,6 @@ ...@@ -39,8 +39,6 @@
static struct atlas_ictrl_regs *atlas_hw0_icregs; static struct atlas_ictrl_regs *atlas_hw0_icregs;
extern asmlinkage void mipsIRQ(void);
#if 0 #if 0
#define DEBUG_INT(x...) printk(x) #define DEBUG_INT(x...) printk(x)
#else #else
...@@ -98,7 +96,7 @@ static inline int ls1bit32(unsigned int x) ...@@ -98,7 +96,7 @@ static inline int ls1bit32(unsigned int x)
return b; return b;
} }
void atlas_hw0_irqdispatch(struct pt_regs *regs) static inline void atlas_hw0_irqdispatch(struct pt_regs *regs)
{ {
unsigned long int_status; unsigned long int_status;
int irq; int irq;
...@@ -116,6 +114,91 @@ void atlas_hw0_irqdispatch(struct pt_regs *regs) ...@@ -116,6 +114,91 @@ void atlas_hw0_irqdispatch(struct pt_regs *regs)
do_IRQ(irq, regs); do_IRQ(irq, regs);
} }
static inline int clz(unsigned long x)
{
__asm__ (
" .set push \n"
" .set mips32 \n"
" clz %0, %1 \n"
" .set pop \n"
: "=r" (x)
: "r" (x));
return x;
}
/*
* Version of ffs that only looks at bits 12..15.
*/
static inline unsigned int irq_ffs(unsigned int pending)
{
#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
return -clz(pending) + 31 - CAUSEB_IP;
#else
unsigned int a0 = 7;
unsigned int t0;
t0 = s0 & 0xf000;
t0 = t0 < 1;
t0 = t0 << 2;
a0 = a0 - t0;
s0 = s0 << t0;
t0 = s0 & 0xc000;
t0 = t0 < 1;
t0 = t0 << 1;
a0 = a0 - t0;
s0 = s0 << t0;
t0 = s0 & 0x8000;
t0 = t0 < 1;
//t0 = t0 << 2;
a0 = a0 - t0;
//s0 = s0 << t0;
return a0;
#endif
}
/*
* IRQs on the Atlas board look basically (barring software IRQs which we
* don't use at all and all external interrupt sources are combined together
* on hardware interrupt 0 (MIPS IRQ 2)) like:
*
* MIPS IRQ Source
* -------- ------
* 0 Software (ignored)
* 1 Software (ignored)
* 2 Combined hardware interrupt (hw0)
* 3 Hardware (ignored)
* 4 Hardware (ignored)
* 5 Hardware (ignored)
* 6 Hardware (ignored)
* 7 R4k timer (what we use)
*
* We handle the IRQ according to _our_ priority which is:
*
* Highest ---- R4k Timer
* Lowest ---- Combined hardware interrupt
*
* then we just return, if multiple IRQs are pending then we will just take
* another exception, big deal.
*/
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
int irq;
irq = irq_ffs(pending);
if (irq == MIPSCPU_INT_ATLAS)
atlas_hw0_irqdispatch(regs);
else if (irq > 0)
do_IRQ(MIPSCPU_INT_BASE + irq, regs);
else
spurious_interrupt(regs);
}
void __init arch_init_irq(void) void __init arch_init_irq(void)
{ {
int i; int i;
...@@ -128,9 +211,6 @@ void __init arch_init_irq(void) ...@@ -128,9 +211,6 @@ void __init arch_init_irq(void)
*/ */
atlas_hw0_icregs->intrsten = 0xffffffff; atlas_hw0_icregs->intrsten = 0xffffffff;
/* Now safe to set the exception vector. */
set_except_vector(0, mipsIRQ);
for (i = ATLASINT_BASE; i <= ATLASINT_END; i++) { for (i = ATLASINT_BASE; i <= ATLASINT_END; i++) {
irq_desc[i].status = IRQ_DISABLED; irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = 0; irq_desc[i].action = 0;
......
...@@ -19,4 +19,4 @@ ...@@ -19,4 +19,4 @@
# under Linux. # under Linux.
# #
obj-y := malta_int.o malta-irq.o malta_setup.o obj-y := malta_int.o malta_setup.o
/*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 1999, 2000 MIPS Technologies, Inc. All rights reserved.
*
* ########################################################################
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
* ########################################################################
*
* Interrupt exception dispatch code.
*
*/
#include <linux/config.h>
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
#include <asm/mips-boards/maltaint.h>
/*
* IRQs on the Malta board look basically (barring software IRQs which we
* don't use at all and all external interrupt sources are combined together
* on hardware interrupt 0 (MIPS IRQ 2)) like:
*
* MIPS IRQ Source
* -------- ------
* 0 Software (ignored)
* 1 Software (ignored)
* 2 Combined hardware interrupt (hw0)
* 3 Hardware (ignored)
* 4 Hardware (ignored)
* 5 Hardware (ignored)
* 6 Hardware (ignored)
* 7 R4k timer (what we use)
*
* We handle the IRQ according to _our_ priority which is:
*
* Highest ---- R4k Timer
* Lowest ---- Combined hardware interrupt
*
* then we just return, if multiple IRQs are pending then we will just take
* another exception, big deal.
*/
.text
.set noreorder
.set noat
.align 5
NESTED(mipsIRQ, PT_SIZE, sp)
SAVE_ALL
CLI
.set at
mfc0 s0, CP0_CAUSE # get irq bits
mfc0 s1, CP0_STATUS # get irq mask
andi s0, ST0_IM # CAUSE.CE may be non-zero!
and s0, s1
#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
.set mips32
clz a0, s0
.set mips0
negu a0
addu a0, 31-CAUSEB_IP
bltz a0, spurious
#else
beqz s0, spurious
li a0, 7
and t0, s0, 0xf000
sltiu t0, t0, 1
sll t0, 2
subu a0, t0
sll s0, t0
and t0, s0, 0xc000
sltiu t0, t0, 1
sll t0, 1
subu a0, t0
sll s0, t0
and t0, s0, 0x8000
sltiu t0, t0, 1
# sll t0, 0
subu a0, t0
# sll s0, t0
#endif
li a1, MIPSCPU_INT_I8259A
bne a0, a1, 1f
addu a0, MIPSCPU_INT_BASE
jal malta_hw0_irqdispatch
move a0, sp
j ret_from_irq
nop
1:
jal do_IRQ
move a1, sp
j ret_from_irq
nop
spurious:
j spurious_interrupt
nop
END(mipsIRQ)
...@@ -40,7 +40,6 @@ ...@@ -40,7 +40,6 @@
#include <asm/mips-boards/msc01_pci.h> #include <asm/mips-boards/msc01_pci.h>
#include <asm/msc01_ic.h> #include <asm/msc01_ic.h>
extern asmlinkage void mipsIRQ(void);
extern void mips_timer_interrupt(void); extern void mips_timer_interrupt(void);
static DEFINE_SPINLOCK(mips_irq_lock); static DEFINE_SPINLOCK(mips_irq_lock);
...@@ -114,7 +113,7 @@ static inline int get_int(void) ...@@ -114,7 +113,7 @@ static inline int get_int(void)
return irq; return irq;
} }
void malta_hw0_irqdispatch(struct pt_regs *regs) static void malta_hw0_irqdispatch(struct pt_regs *regs)
{ {
int irq; int irq;
...@@ -182,6 +181,92 @@ void corehi_irqdispatch(struct pt_regs *regs) ...@@ -182,6 +181,92 @@ void corehi_irqdispatch(struct pt_regs *regs)
die("CoreHi interrupt", regs); die("CoreHi interrupt", regs);
} }
static inline int clz(unsigned long x)
{
__asm__ (
" .set push \n"
" .set mips32 \n"
" clz %0, %1 \n"
" .set pop \n"
: "=r" (x)
: "r" (x));
return x;
}
/*
* Version of ffs that only looks at bits 12..15.
*/
static inline unsigned int irq_ffs(unsigned int pending)
{
#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
return -clz(pending) + 31 - CAUSEB_IP;
#else
unsigned int a0 = 7;
unsigned int t0;
t0 = s0 & 0xf000;
t0 = t0 < 1;
t0 = t0 << 2;
a0 = a0 - t0;
s0 = s0 << t0;
t0 = s0 & 0xc000;
t0 = t0 < 1;
t0 = t0 << 1;
a0 = a0 - t0;
s0 = s0 << t0;
t0 = s0 & 0x8000;
t0 = t0 < 1;
//t0 = t0 << 2;
a0 = a0 - t0;
//s0 = s0 << t0;
return a0;
#endif
}
/*
* IRQs on the Malta board look basically (barring software IRQs which we
* don't use at all and all external interrupt sources are combined together
* on hardware interrupt 0 (MIPS IRQ 2)) like:
*
* MIPS IRQ Source
* -------- ------
* 0 Software (ignored)
* 1 Software (ignored)
* 2 Combined hardware interrupt (hw0)
* 3 Hardware (ignored)
* 4 Hardware (ignored)
* 5 Hardware (ignored)
* 6 Hardware (ignored)
* 7 R4k timer (what we use)
*
* We handle the IRQ according to _our_ priority which is:
*
* Highest ---- R4k Timer
* Lowest ---- Combined hardware interrupt
*
* then we just return, if multiple IRQs are pending then we will just take
* another exception, big deal.
*/
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
int irq;
irq = irq_ffs(pending);
if (irq == MIPSCPU_INT_I8259A)
malta_hw0_irqdispatch(regs);
else if (irq > 0)
do_IRQ(MIPSCPU_INT_BASE + irq, regs);
else
spurious_interrupt(regs);
}
static struct irqaction i8259irq = { static struct irqaction i8259irq = {
.handler = no_action, .handler = no_action,
.name = "XT-PIC cascade" .name = "XT-PIC cascade"
...@@ -214,7 +299,6 @@ int __initdata msc_nr_eicirqs = sizeof(msc_eicirqmap)/sizeof(msc_irqmap_t); ...@@ -214,7 +299,6 @@ int __initdata msc_nr_eicirqs = sizeof(msc_eicirqmap)/sizeof(msc_irqmap_t);
void __init arch_init_irq(void) void __init arch_init_irq(void)
{ {
set_except_vector(0, mipsIRQ);
init_i8259_irqs(); init_i8259_irqs();
if (!cpu_has_veic) if (!cpu_has_veic)
...@@ -245,7 +329,6 @@ void __init arch_init_irq(void) ...@@ -245,7 +329,6 @@ void __init arch_init_irq(void)
setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction); setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction);
} }
else { else {
set_except_vector(0, mipsIRQ);
setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq); setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq);
setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction); setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction);
} }
......
...@@ -23,4 +23,4 @@ ...@@ -23,4 +23,4 @@
# under Linux. # under Linux.
# #
obj-y := sead_int.o sead-irq.o sead_setup.o obj-y := sead_int.o sead_setup.o
/*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 1999, 2000 MIPS Technologies, Inc. All rights reserved.
*
* ########################################################################
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
* ########################################################################
*
* Interrupt exception dispatch code.
*
*/
#include <linux/config.h>
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
#include <asm/mips-boards/seadint.h>
/*
* IRQs on the SEAD board look basically are combined together on hardware
* interrupt 0 (MIPS IRQ 2)) like:
*
* MIPS IRQ Source
* -------- ------
* 0 Software (ignored)
* 1 Software (ignored)
* 2 UART0 (hw0)
* 3 UART1 (hw1)
* 4 Hardware (ignored)
* 5 Hardware (ignored)
* 6 Hardware (ignored)
* 7 R4k timer (what we use)
*
* We handle the IRQ according to _our_ priority which is:
*
* Highest ---- R4k Timer
* Lowest ---- Combined hardware interrupt
*
* then we just return, if multiple IRQs are pending then we will just take
* another exception, big deal.
*/
.text
.set noreorder
.set noat
.align 5
NESTED(mipsIRQ, PT_SIZE, sp)
SAVE_ALL
CLI
.set at
mfc0 s0, CP0_CAUSE # get irq bits
mfc0 s1, CP0_STATUS # get irq mask
andi s0, ST0_IM # CAUSE.CE may be non-zero!
and s0, s1
#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
.set mips32
clz a0, s0
.set mips0
negu a0
addu a0, 31-CAUSEB_IP
bltz a0, spurious
#else
beqz s0, spurious
li a0, 7
and t0, s0, 0xf000
sltiu t0, t0, 1
sll t0, 2
subu a0, t0
sll s0, t0
and t0, s0, 0xc000
sltiu t0, t0, 1
sll t0, 1
subu a0, t0
sll s0, t0
and t0, s0, 0x8000
sltiu t0, t0, 1
# sll t0, 0
subu a0, t0
# sll s0, t0
#endif
addu a0, MIPSCPU_INT_BASE
jal do_IRQ
move a1, sp
j ret_from_irq
nop
spurious:
j spurious_interrupt
nop
END(mipsIRQ)
...@@ -24,16 +24,94 @@ ...@@ -24,16 +24,94 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <asm/irq_cpu.h> #include <asm/irq_cpu.h>
#include <asm/mipsregs.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/mips-boards/seadint.h> #include <asm/mips-boards/seadint.h>
extern asmlinkage void mipsIRQ(void); static inline int clz(unsigned long x)
{
__asm__ (
" .set push \n"
" .set mips32 \n"
" clz %0, %1 \n"
" .set pop \n"
: "=r" (x)
: "r" (x));
return x;
}
/*
* Version of ffs that only looks at bits 12..15.
*/
static inline unsigned int irq_ffs(unsigned int pending)
{
#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
return -clz(pending) + 31 - CAUSEB_IP;
#else
unsigned int a0 = 7;
unsigned int t0;
t0 = s0 & 0xf000;
t0 = t0 < 1;
t0 = t0 << 2;
a0 = a0 - t0;
s0 = s0 << t0;
t0 = s0 & 0xc000;
t0 = t0 < 1;
t0 = t0 << 1;
a0 = a0 - t0;
s0 = s0 << t0;
t0 = s0 & 0x8000;
t0 = t0 < 1;
//t0 = t0 << 2;
a0 = a0 - t0;
//s0 = s0 << t0;
return a0;
#endif
}
/*
* IRQs on the SEAD board look basically are combined together on hardware
* interrupt 0 (MIPS IRQ 2)) like:
*
* MIPS IRQ Source
* -------- ------
* 0 Software (ignored)
* 1 Software (ignored)
* 2 UART0 (hw0)
* 3 UART1 (hw1)
* 4 Hardware (ignored)
* 5 Hardware (ignored)
* 6 Hardware (ignored)
* 7 R4k timer (what we use)
*
* We handle the IRQ according to _our_ priority which is:
*
* Highest ---- R4k Timer
* Lowest ---- Combined hardware interrupt
*
* then we just return, if multiple IRQs are pending then we will just take
* another exception, big deal.
*/
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
int irq;
irq = irq_ffs(pending);
if (irq >= 0)
do_IRQ(MIPSCPU_INT_BASE + irq, regs);
else
spurious_interrupt(regs);
}
void __init arch_init_irq(void) void __init arch_init_irq(void)
{ {
mips_cpu_irq_init(MIPSCPU_INT_BASE); mips_cpu_irq_init(MIPSCPU_INT_BASE);
/* Now safe to set the exception vector. */
set_except_vector(0, mipsIRQ);
} }
...@@ -25,17 +25,71 @@ ...@@ -25,17 +25,71 @@
extern void mips_cpu_irq_init(int); extern void mips_cpu_irq_init(int);
extern asmlinkage void simIRQ(void); static inline int clz(unsigned long x)
{
__asm__ (
" .set push \n"
" .set mips32 \n"
" clz %0, %1 \n"
" .set pop \n"
: "=r" (x)
: "r" (x));
return x;
}
/*
* Version of ffs that only looks at bits 12..15.
*/
static inline unsigned int irq_ffs(unsigned int pending)
{
#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
return -clz(pending) + 31 - CAUSEB_IP;
#else
unsigned int a0 = 7;
unsigned int t0;
t0 = s0 & 0xf000;
t0 = t0 < 1;
t0 = t0 << 2;
a0 = a0 - t0;
s0 = s0 << t0;
t0 = s0 & 0xc000;
t0 = t0 < 1;
t0 = t0 << 1;
a0 = a0 - t0;
s0 = s0 << t0;
asmlinkage void sim_hw0_irqdispatch(struct pt_regs *regs) t0 = s0 & 0x8000;
t0 = t0 < 1;
//t0 = t0 << 2;
a0 = a0 - t0;
//s0 = s0 << t0;
return a0;
#endif
}
static inline void sim_hw0_irqdispatch(struct pt_regs *regs)
{ {
do_IRQ(2, regs); do_IRQ(2, regs);
} }
void __init arch_init_irq(void) asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{ {
/* Now safe to set the exception vector. */ unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
set_except_vector(0, simIRQ); int irq;
irq = irq_ffs(pending);
if (irq > 0)
do_IRQ(MIPSCPU_INT_BASE + irq, regs);
else
spurious_interrupt(regs);
}
void __init arch_init_irq(void)
{
mips_cpu_irq_init(MIPSCPU_INT_BASE); mips_cpu_irq_init(MIPSCPU_INT_BASE);
} }
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
# unless it's something special (ie not a .c file). # unless it's something special (ie not a .c file).
# #
obj-y += int-handler.o irq.o prom.o reset.o setup.o obj-y += irq.o prom.o reset.o setup.o
obj-$(CONFIG_SERIAL_8250_CONSOLE) += ja-console.o obj-$(CONFIG_SERIAL_8250_CONSOLE) += ja-console.o
obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o
/*
* Copyright 2002 Momentum Computer Inc.
* Author: Matthew Dharm <mdharm@momenco.com>
*
* Based on work:
* Copyright 2001 MontaVista Software Inc.
* Author: jsun@mvista.com or jsun@junsun.net
*
* First-level interrupt dispatcher for Jaguar-ATX board.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/addrspace.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
/*
* First level interrupt dispatcher for Ocelot-CS board
*/
.align 5
NESTED(jaguar_handle_int, PT_SIZE, sp)
SAVE_ALL
CLI
.set at
mfc0 t0, CP0_CAUSE
mfc0 t2, CP0_STATUS
and t0, t2
andi t1, t0, STATUSF_IP0 /* sw0 software interrupt */
bnez t1, ll_sw0_irq
andi t1, t0, STATUSF_IP1 /* sw1 software interrupt */
bnez t1, ll_sw1_irq
andi t1, t0, STATUSF_IP2 /* int0 hardware line */
bnez t1, ll_pcixa_irq
andi t1, t0, STATUSF_IP3 /* int1 hardware line */
bnez t1, ll_pcixb_irq
andi t1, t0, STATUSF_IP4 /* int2 hardware line */
bnez t1, ll_pcia_irq
andi t1, t0, STATUSF_IP5 /* int3 hardware line */
bnez t1, ll_pcib_irq
andi t1, t0, STATUSF_IP6 /* int4 hardware line */
bnez t1, ll_uart_irq
andi t1, t0, STATUSF_IP7 /* cpu timer */
bnez t1, ll_cputimer_irq
nop
nop
/* now look at extended interrupts */
mfc0 t0, CP0_CAUSE
cfc0 t1, CP0_S1_INTCONTROL
/* shift the mask 8 bits left to line up the bits */
sll t2, t1, 8
and t0, t2
srl t0, t0, 16
andi t1, t0, STATUSF_IP8 /* int6 hardware line */
bnez t1, ll_mv64340_decode_irq
nop
nop
.set reorder
/* wrong alarm or masked ... */
j spurious_interrupt
nop
END(jaguar_handle_int)
.align 5
ll_sw0_irq:
li a0, 0
move a1, sp
jal do_IRQ
j ret_from_irq
ll_sw1_irq:
li a0, 1
move a1, sp
jal do_IRQ
j ret_from_irq
ll_pcixa_irq:
li a0, 2
move a1, sp
jal do_IRQ
j ret_from_irq
ll_pcixb_irq:
li a0, 3
move a1, sp
jal do_IRQ
j ret_from_irq
ll_pcia_irq:
li a0, 4
move a1, sp
jal do_IRQ
j ret_from_irq
ll_pcib_irq:
li a0, 5
move a1, sp
jal do_IRQ
j ret_from_irq
ll_uart_irq:
li a0, 6
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cputimer_irq:
li a0, 7
move a1, sp
jal ll_timer_interrupt
j ret_from_irq
ll_mv64340_decode_irq:
move a0, sp
jal ll_mv64340_irq
j ret_from_irq
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* Copyright 2001 MontaVista Software Inc. * Copyright 2001 MontaVista Software Inc.
* Author: Jun Sun, jsun@mvista.com or jsun@junsun.net * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
* *
* Copyright (C) 2000, 2001 Ralf Baechle (ralf@gnu.org) * Copyright (C) 2000, 01, 06 Ralf Baechle (ralf@linux-mips.org)
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the * under the terms of the GNU General Public License as published by the
...@@ -38,8 +38,37 @@ ...@@ -38,8 +38,37 @@
#include <linux/types.h> #include <linux/types.h>
#include <asm/irq_cpu.h> #include <asm/irq_cpu.h>
#include <asm/mipsregs.h> #include <asm/mipsregs.h>
#include <asm/time.h>
extern asmlinkage void jaguar_handle_int(void); asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending = read_c0_cause() & read_c0_status();
if (pending & STATUSF_IP0)
do_IRQ(0, regs);
else if (pending & STATUSF_IP1)
do_IRQ(1, regs);
else if (pending & STATUSF_IP2)
do_IRQ(2, regs);
else if (pending & STATUSF_IP3)
do_IRQ(3, regs);
else if (pending & STATUSF_IP4)
do_IRQ(4, regs);
else if (pending & STATUSF_IP5)
do_IRQ(5, regs);
else if (pending & STATUSF_IP6)
do_IRQ(6, regs);
else if (pending & STATUSF_IP7)
ll_timer_interrupt(7, regs);
else {
/*
* Now look at the extended interrupts
*/
pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16;
if (pending & STATUSF_IP8)
ll_mv64340_irq(regs);
}
}
static struct irqaction cascade_mv64340 = { static struct irqaction cascade_mv64340 = {
no_action, SA_INTERRUPT, CPU_MASK_NONE, "MV64340-Cascade", NULL, NULL no_action, SA_INTERRUPT, CPU_MASK_NONE, "MV64340-Cascade", NULL, NULL
...@@ -53,8 +82,6 @@ void __init arch_init_irq(void) ...@@ -53,8 +82,6 @@ void __init arch_init_irq(void)
*/ */
clear_c0_status(ST0_IM); clear_c0_status(ST0_IM);
/* Sets the first-level interrupt dispatcher. */
set_except_vector(0, jaguar_handle_int);
mips_cpu_irq_init(0); mips_cpu_irq_init(0);
rm7k_cpu_irq_init(8); rm7k_cpu_irq_init(8);
......
...@@ -5,4 +5,4 @@ ...@@ -5,4 +5,4 @@
# removes any old dependencies. DON'T put your own dependencies here # removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file). # unless it's something special (ie not a .c file).
# #
obj-y += int-handler.o irq.o prom.o reset.o setup.o obj-y += irq.o prom.o reset.o setup.o
/*
* Copyright 2002 Momentum Computer Inc.
* Author: Matthew Dharm <mdharm@momenco.com>
*
* Copyright 2001 MontaVista Software Inc.
* Author: jsun@mvista.com or jsun@junsun.net
*
* Copyright 2004 PMC-Sierra
* Author: Manish Lachwani (lachwani@pmc-sierra.com)
*
* Copyright (C) 2004 MontaVista Software Inc.
* Author: Manish Lachwani, mlachwani@mvista.com
*
* First-level interrupt dispatcher for Ocelot-3 board.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/addrspace.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
/*
* First level interrupt dispatcher for Ocelot-3 board
*/
.align 5
NESTED(ocelot3_handle_int, PT_SIZE, sp)
SAVE_ALL
CLI
.set at
mfc0 t0, CP0_CAUSE
mfc0 t2, CP0_STATUS
and t0, t2
andi t1, t0, STATUSF_IP0 /* sw0 software interrupt (IRQ0) */
bnez t1, ll_sw0_irq
andi t1, t0, STATUSF_IP1 /* sw1 software interrupt (IRQ1) */
bnez t1, ll_sw1_irq
andi t1, t0, STATUSF_IP2 /* int0 hardware line (IRQ2) */
bnez t1, ll_pci0slot1_irq
andi t1, t0, STATUSF_IP3 /* int1 hardware line (IRQ3) */
bnez t1, ll_pci0slot2_irq
andi t1, t0, STATUSF_IP4 /* int2 hardware line (IRQ4) */
bnez t1, ll_pci1slot1_irq
andi t1, t0, STATUSF_IP5 /* int3 hardware line (IRQ5) */
bnez t1, ll_pci1slot2_irq
andi t1, t0, STATUSF_IP6 /* int4 hardware line (IRQ6) */
bnez t1, ll_uart_irq
andi t1, t0, STATUSF_IP7 /* cpu timer (IRQ7) */
bnez t1, ll_cputimer_irq
/* now look at extended interrupts */
mfc0 t0, CP0_CAUSE
cfc0 t1, CP0_S1_INTCONTROL
/* shift the mask 8 bits left to line up the bits */
sll t2, t1, 8
and t0, t2
srl t0, t0, 16
andi t1, t0, STATUSF_IP8 /* int6 hardware line (IRQ9) */
bnez t1, ll_mv64340_decode_irq
.set reorder
/* wrong alarm or masked ... */
jal spurious_interrupt
nop
j ret_from_irq
nop
END(ocelot3_handle_int)
.align 5
ll_sw0_irq:
li a0, 0 /* IRQ 1 */
move a1, sp
jal do_IRQ
j ret_from_irq
ll_sw1_irq:
li a0, 1 /* IRQ 2 */
move a1, sp
jal do_IRQ
j ret_from_irq
ll_pci0slot1_irq:
li a0, 2 /* IRQ 3 */
move a1, sp
jal do_IRQ
j ret_from_irq
ll_pci0slot2_irq:
li a0, 3 /* IRQ 4 */
move a1, sp
jal do_IRQ
j ret_from_irq
ll_pci1slot1_irq:
li a0, 4 /* IRQ 5 */
move a1, sp
jal do_IRQ
j ret_from_irq
ll_pci1slot2_irq:
li a0, 5 /* IRQ 6 */
move a1, sp
jal do_IRQ
j ret_from_irq
ll_uart_irq:
li a0, 6 /* IRQ 7 */
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cputimer_irq:
li a0, 7 /* IRQ 8 */
move a1, sp
jal do_IRQ
j ret_from_irq
ll_mv64340_decode_irq:
move a0, sp
jal ll_mv64340_irq
j ret_from_irq
...@@ -53,8 +53,6 @@ ...@@ -53,8 +53,6 @@
#include <asm/mipsregs.h> #include <asm/mipsregs.h>
#include <asm/system.h> #include <asm/system.h>
extern asmlinkage void ocelot3_handle_int(void);
static struct irqaction cascade_mv64340 = { static struct irqaction cascade_mv64340 = {
no_action, SA_INTERRUPT, CPU_MASK_NONE, "MV64340-Cascade", NULL, NULL no_action, SA_INTERRUPT, CPU_MASK_NONE, "MV64340-Cascade", NULL, NULL
}; };
...@@ -67,9 +65,6 @@ void __init arch_init_irq(void) ...@@ -67,9 +65,6 @@ void __init arch_init_irq(void)
*/ */
clear_c0_status(ST0_IM | ST0_BEV); clear_c0_status(ST0_IM | ST0_BEV);
/* Sets the first-level interrupt dispatcher. */
set_except_vector(0, ocelot3_handle_int);
mips_cpu_irq_init(0);
rm7k_cpu_irq_init(8); rm7k_cpu_irq_init(8);
/* set up the cascading interrupts */ /* set up the cascading interrupts */
...@@ -79,3 +74,36 @@ void __init arch_init_irq(void) ...@@ -79,3 +74,36 @@ void __init arch_init_irq(void)
set_c0_status(ST0_IM); /* IE in the status register */ set_c0_status(ST0_IM); /* IE in the status register */
} }
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending = read_c0_cause() & read_c0_status();
if (pending & STATUSF_IP0)
do_IRQ(0, regs);
else if (pending & STATUSF_IP1)
do_IRQ(1, regs);
else if (pending & STATUSF_IP2)
do_IRQ(2, regs);
else if (pending & STATUSF_IP3)
do_IRQ(3, regs);
else if (pending & STATUSF_IP4)
do_IRQ(4, regs);
else if (pending & STATUSF_IP5)
do_IRQ(5, regs);
else if (pending & STATUSF_IP6)
do_IRQ(6, regs);
else if (pending & STATUSF_IP7)
do_IRQ(7, regs);
else {
/*
* Now look at the extended interrupts
*/
pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16;
if (pending & STATUSF_IP8)
ll_mv64340_irq(regs);
else
spurious_interrupt(regs);
}
}
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Makefile for Momentum Computer's Ocelot-C and -CS boards. # Makefile for Momentum Computer's Ocelot-C and -CS boards.
# #
obj-y += cpci-irq.o int-handler.o irq.o prom.o reset.o \ obj-y += cpci-irq.o irq.o prom.o reset.o \
setup.o uart-irq.o setup.o uart-irq.o
obj-$(CONFIG_KGDB) += dbg_io.o obj-$(CONFIG_KGDB) += dbg_io.o
/*
* Copyright 2002 Momentum Computer Inc.
* Author: Matthew Dharm <mdharm@momenco.com>
*
* Copyright 2001 MontaVista Software Inc.
* Author: jsun@mvista.com or jsun@junsun.net
*
* First-level interrupt dispatcher for Ocelot-CS board.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/addrspace.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
#include "ocelot_c_fpga.h"
/*
* First level interrupt dispatcher for Ocelot-CS board
*/
.align 5
NESTED(ocelot_handle_int, PT_SIZE, sp)
SAVE_ALL
CLI
.set at
mfc0 t0, CP0_CAUSE
mfc0 t2, CP0_STATUS
and t0, t2
andi t1, t0, STATUSF_IP0 /* sw0 software interrupt */
bnez t1, ll_sw0_irq
andi t1, t0, STATUSF_IP1 /* sw1 software interrupt */
bnez t1, ll_sw1_irq
andi t1, t0, STATUSF_IP2 /* int0 hardware line */
bnez t1, ll_scsi_irq
andi t1, t0, STATUSF_IP3 /* int1 hardware line */
bnez t1, ll_uart_decode_irq
andi t1, t0, STATUSF_IP4 /* int2 hardware line */
bnez t1, ll_pmc_irq
andi t1, t0, STATUSF_IP5 /* int3 hardware line */
bnez t1, ll_cpci_decode_irq
andi t1, t0, STATUSF_IP6 /* int4 hardware line */
bnez t1, ll_mv64340_decode_irq
andi t1, t0, STATUSF_IP7 /* cpu timer */
bnez t1, ll_cputimer_irq
.set reorder
/* wrong alarm or masked ... */
jal spurious_interrupt
nop
j ret_from_irq
END(ocelot_handle_int)
.align 5
ll_sw0_irq:
li a0, 0
move a1, sp
jal do_IRQ
j ret_from_irq
ll_sw1_irq:
li a0, 1
move a1, sp
jal do_IRQ
j ret_from_irq
ll_scsi_irq:
li a0, 2
move a1, sp
jal do_IRQ
j ret_from_irq
ll_uart_decode_irq:
move a0, sp
jal ll_uart_irq
j ret_from_irq
ll_pmc_irq:
li a0, 4
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cpci_decode_irq:
move a0, sp
jal ll_cpci_irq
j ret_from_irq
ll_mv64340_decode_irq:
move a0, sp
jal ll_mv64340_irq
j ret_from_irq
ll_cputimer_irq:
li a0, 7
move a1, sp
jal do_IRQ
j ret_from_irq
...@@ -48,7 +48,6 @@ ...@@ -48,7 +48,6 @@
#include <asm/mipsregs.h> #include <asm/mipsregs.h>
#include <asm/system.h> #include <asm/system.h>
extern asmlinkage void ocelot_handle_int(void);
extern void uart_irq_init(void); extern void uart_irq_init(void);
extern void cpci_irq_init(void); extern void cpci_irq_init(void);
...@@ -60,6 +59,33 @@ static struct irqaction cascade_mv64340 = { ...@@ -60,6 +59,33 @@ static struct irqaction cascade_mv64340 = {
no_action, SA_INTERRUPT, CPU_MASK_NONE, "cascade via MV64340", NULL, NULL no_action, SA_INTERRUPT, CPU_MASK_NONE, "cascade via MV64340", NULL, NULL
}; };
extern void ll_uart_irq(struct pt_regs *regs);
extern void ll_cpci_irq(struct pt_regs *regs);
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending = read_c0_cause() & read_c0_status();
if (pending & STATUSF_IP0)
do_IRQ(0, regs);
else if (pending & STATUSF_IP1)
do_IRQ(1, regs);
else if (pending & STATUSF_IP2)
do_IRQ(2, regs);
else if (pending & STATUSF_IP3)
ll_uart_irq(regs);
else if (pending & STATUSF_IP4)
do_IRQ(4, regs);
else if (pending & STATUSF_IP5)
ll_cpci_irq(regs);
else if (pending & STATUSF_IP6)
ll_mv64340_irq(regs);
else if (pending & STATUSF_IP7)
do_IRQ(7, regs);
else
spurious_interrupt(regs);
}
void __init arch_init_irq(void) void __init arch_init_irq(void)
{ {
/* /*
...@@ -68,8 +94,6 @@ void __init arch_init_irq(void) ...@@ -68,8 +94,6 @@ void __init arch_init_irq(void)
*/ */
clear_c0_status(ST0_IM); clear_c0_status(ST0_IM);
/* Sets the first-level interrupt dispatcher. */
set_except_vector(0, ocelot_handle_int);
mips_cpu_irq_init(0); mips_cpu_irq_init(0);
/* set up the cascading interrupts */ /* set up the cascading interrupts */
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Makefile for Momentum Computer's Ocelot-G board. # Makefile for Momentum Computer's Ocelot-G board.
# #
obj-y += int-handler.o irq.o gt-irq.o prom.o reset.o setup.o obj-y += irq.o gt-irq.o prom.o reset.o setup.o
obj-$(CONFIG_KGDB) += dbg_io.o obj-$(CONFIG_KGDB) += dbg_io.o
EXTRA_AFLAGS := $(CFLAGS) EXTRA_AFLAGS := $(CFLAGS)
/*
* Copyright 2001 MontaVista Software Inc.
* Author: jsun@mvista.com or jsun@junsun.net
*
* First-level interrupt dispatcher for ocelot board.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/addrspace.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
/*
* first level interrupt dispatcher for ocelot board -
* We check for the timer first, then check PCI ints A and D.
* Then check for serial IRQ and fall through.
*/
.align 5
NESTED(ocelot_handle_int, PT_SIZE, sp)
SAVE_ALL
CLI
.set at
mfc0 t0, CP0_CAUSE
mfc0 t2, CP0_STATUS
and t0, t2
andi t1, t0, STATUSF_IP2 /* int0 hardware line */
bnez t1, ll_pri_enet_irq
andi t1, t0, STATUSF_IP3 /* int1 hardware line */
bnez t1, ll_sec_enet_irq
andi t1, t0, STATUSF_IP4 /* int2 hardware line */
bnez t1, ll_uart_irq
andi t1, t0, STATUSF_IP5 /* int3 hardware line */
bnez t1, ll_cpci_irq
andi t1, t0, STATUSF_IP6 /* int4 hardware line */
bnez t1, ll_galileo_p0_irq
andi t1, t0, STATUSF_IP7 /* cpu timer */
bnez t1, ll_cputimer_irq
/* now look at the extended interrupts */
mfc0 t0, CP0_CAUSE
cfc0 t1, CP0_S1_INTCONTROL
/* shift the mask 8 bits left to line up the bits */
sll t2, t1, 8
and t0, t2
srl t0, t0, 16
andi t1, t0, STATUSF_IP8 /* int6 hardware line */
bnez t1, ll_galileo_p1_irq
andi t1, t0, STATUSF_IP9 /* int7 hardware line */
bnez t1, ll_pmc_irq
andi t1, t0, STATUSF_IP10 /* int8 hardware line */
bnez t1, ll_cpci_abcd_irq
andi t1, t0, STATUSF_IP11 /* int9 hardware line */
bnez t1, ll_testpoint_irq
.set reorder
/* wrong alarm or masked ... */
j spurious_interrupt
nop
END(ocelot_handle_int)
.align 5
ll_pri_enet_irq:
li a0, 2
move a1, sp
jal do_IRQ
j ret_from_irq
ll_sec_enet_irq:
li a0, 3
move a1, sp
jal do_IRQ
j ret_from_irq
ll_uart_irq:
li a0, 4
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cpci_irq:
li a0, 5
move a1, sp
jal do_IRQ
j ret_from_irq
ll_galileo_p0_irq:
li a0, 6
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cputimer_irq:
li a0, 7
move a1, sp
jal do_IRQ
j ret_from_irq
ll_galileo_p1_irq:
li a0, 8
move a1, sp
jal do_IRQ
j ret_from_irq
ll_pmc_irq:
li a0, 9
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cpci_abcd_irq:
li a0, 10
move a1, sp
jal do_IRQ
j ret_from_irq
ll_testpoint_irq:
li a0, 11
move a1, sp
jal do_IRQ
j ret_from_irq
...@@ -48,7 +48,41 @@ ...@@ -48,7 +48,41 @@
#include <asm/mipsregs.h> #include <asm/mipsregs.h>
#include <asm/system.h> #include <asm/system.h>
extern asmlinkage void ocelot_handle_int(void); asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending = read_c0_cause() & read_c0_status();
if (pending & STATUSF_IP2)
do_IRQ(2, regs);
else if (pending & STATUSF_IP3)
do_IRQ(3, regs);
else if (pending & STATUSF_IP4)
do_IRQ(4, regs);
else if (pending & STATUSF_IP5)
do_IRQ(5, regs);
else if (pending & STATUSF_IP6)
do_IRQ(6, regs);
else if (pending & STATUSF_IP7)
do_IRQ(7, regs);
else {
/*
* Now look at the extended interrupts
*/
pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16;
if (pending & STATUSF_IP8)
do_IRQ(8, regs);
else if (pending & STATUSF_IP9)
do_IRQ(9, regs);
else if (pending & STATUSF_IP10)
do_IRQ(10, regs);
else if (pending & STATUSF_IP11)
do_IRQ(11, regs);
else
spurious_interrupt(regs);
}
}
extern void gt64240_irq_init(void); extern void gt64240_irq_init(void);
void __init arch_init_irq(void) void __init arch_init_irq(void)
...@@ -60,8 +94,6 @@ void __init arch_init_irq(void) ...@@ -60,8 +94,6 @@ void __init arch_init_irq(void)
clear_c0_status(ST0_IM); clear_c0_status(ST0_IM);
local_irq_disable(); local_irq_disable();
/* Sets the first-level interrupt dispatcher. */
set_except_vector(0, ocelot_handle_int);
mips_cpu_irq_init(0); mips_cpu_irq_init(0);
rm7k_cpu_irq_init(8); rm7k_cpu_irq_init(8);
......
...@@ -22,6 +22,6 @@ ...@@ -22,6 +22,6 @@
# under Linux. # under Linux.
# #
obj-y := setup.o prom.o mipsIRQ.o int.o reset.o time.o proc.o platform.o obj-y := setup.o prom.o int.o reset.o time.o proc.o platform.o
obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_KGDB) += gdb_hook.o obj-$(CONFIG_KGDB) += gdb_hook.o
...@@ -38,8 +38,6 @@ ...@@ -38,8 +38,6 @@
#include <int.h> #include <int.h>
#include <uart.h> #include <uart.h>
extern asmlinkage void cp0_irqdispatch(void);
static DEFINE_SPINLOCK(irq_lock); static DEFINE_SPINLOCK(irq_lock);
/* default prio for interrupts */ /* default prio for interrupts */
...@@ -55,7 +53,7 @@ static char gic_prio[PNX8550_INT_GIC_TOTINT] = { ...@@ -55,7 +53,7 @@ static char gic_prio[PNX8550_INT_GIC_TOTINT] = {
1 // 70 1 // 70
}; };
void hw0_irqdispatch(int irq, struct pt_regs *regs) static void hw0_irqdispatch(int irq, struct pt_regs *regs)
{ {
/* find out which interrupt */ /* find out which interrupt */
irq = PNX8550_GIC_VECTOR_0 >> 3; irq = PNX8550_GIC_VECTOR_0 >> 3;
...@@ -68,7 +66,7 @@ void hw0_irqdispatch(int irq, struct pt_regs *regs) ...@@ -68,7 +66,7 @@ void hw0_irqdispatch(int irq, struct pt_regs *regs)
} }
void timer_irqdispatch(int irq, struct pt_regs *regs) static void timer_irqdispatch(int irq, struct pt_regs *regs)
{ {
irq = (0x01c0 & read_c0_config7()) >> 6; irq = (0x01c0 & read_c0_config7()) >> 6;
...@@ -88,6 +86,20 @@ void timer_irqdispatch(int irq, struct pt_regs *regs) ...@@ -88,6 +86,20 @@ void timer_irqdispatch(int irq, struct pt_regs *regs)
} }
} }
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending = read_c0_status() & read_c0_cause();
if (pending & STATUSF_IP2)
do_IRQ(2, regs);
else if (pending & STATUSF_IP7) {
if (read_c0_config7() & 0x01c0)
timer_irqdispatch(7, regs);
}
spurious_interrupt(regs);
}
static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask) static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask)
{ {
unsigned long status = read_c0_status(); unsigned long status = read_c0_status();
...@@ -223,9 +235,6 @@ void __init arch_init_irq(void) ...@@ -223,9 +235,6 @@ void __init arch_init_irq(void)
int i; int i;
int configPR; int configPR;
/* init of cp0 interrupts */
set_except_vector(0, cp0_irqdispatch);
for (i = 0; i < PNX8550_INT_CP0_TOTINT; i++) { for (i = 0; i < PNX8550_INT_CP0_TOTINT; i++) {
irq_desc[i].handler = &level_irq_type; irq_desc[i].handler = &level_irq_type;
pnx8550_ack(i); /* mask the irq just in case */ pnx8550_ack(i); /* mask the irq just in case */
......
/*
* Copyright (c) 2002 Philips, Inc. All rights.
* Copyright (c) 2002 Red Hat, Inc. All rights.
*
* This software may be freely redistributed under the terms of the
* GNU General Public License.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Based upon arch/mips/galileo-boards/ev64240/int-handler.S
*
*/
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/addrspace.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
/*
* cp0_irqdispatch
*
* Code to handle in-core interrupt exception.
*/
.align 5
.set reorder
.set noat
NESTED(cp0_irqdispatch, PT_SIZE, sp)
SAVE_ALL
CLI
.set at
mfc0 t0,CP0_CAUSE
mfc0 t2,CP0_STATUS
and t0,t2
andi t1,t0,STATUSF_IP2 /* int0 hardware line */
bnez t1,ll_hw0_irq
nop
andi t1,t0,STATUSF_IP7 /* int5 hardware line */
bnez t1,ll_timer_irq
nop
/* wrong alarm or masked ... */
jal spurious_interrupt
nop
j ret_from_irq
END(cp0_irqdispatch)
.align 5
.set reorder
ll_hw0_irq:
li a0,2
move a1,sp
jal hw0_irqdispatch
nop
j ret_from_irq
nop
.align 5
.set reorder
ll_timer_irq:
mfc0 t3,CP0_CONFIG,7
andi t4,t3,0x01c0
beqz t4,ll_timer_out
nop
li a0,7
move a1,sp
jal timer_irqdispatch
nop
ll_timer_out: j ret_from_irq
nop
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Makefile for the PMC-Sierra Titan # Makefile for the PMC-Sierra Titan
# #
obj-y += irq-handler.o irq.o i2c-yosemite.o prom.o py-console.o setup.o obj-y += irq.o i2c-yosemite.o prom.o py-console.o setup.o
obj-$(CONFIG_KGDB) += dbg_io.o obj-$(CONFIG_KGDB) += dbg_io.o
obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SMP) += smp.o
/*
* Copyright 2003, 04 PMC-Sierra Inc.
* Author: Manish Lachwani (lachwani@pmc-sierra.com
* Copyright 2004 Ralf Baechle (ralf@linux-mips.org)
*
* First-level interrupt router for the PMC-Sierra Titan board
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* Titan supports Hypertransport or PCI but not both. Hence, one interrupt
* line is shared between the PCI slot A and Hypertransport. This is the
* Processor INTB #0.
*/
#include <linux/config.h>
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/addrspace.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
.align 5
NESTED(titan_handle_int, PT_SIZE, sp)
SAVE_ALL
CLI
.set at
.set noreorder
la ra, ret_from_irq
mfc0 t0, CP0_CAUSE
mfc0 t2, CP0_STATUS
and t0, t2
andi t2, t0, STATUSF_IP7 /* INTB5 hardware line */
bnez t2, ll_timer_irq /* Timer */
andi t1, t0, STATUSF_IP2 /* INTB0 hardware line */
bnez t1, ll_pcia_irq /* 64-bit PCI */
andi t2, t0, STATUSF_IP3 /* INTB1 hardware line */
bnez t2, ll_pcib_irq /* second 64-bit PCI slot */
andi t1, t0, STATUSF_IP4 /* INTB2 hardware line */
bnez t1, ll_duart_irq /* UART */
andi t2, t0, STATUSF_IP5 /* SMP inter-core interrupts */
bnez t2, ll_smp_irq
andi t1, t0, STATUSF_IP6
bnez t1, ll_ht_irq /* Hypertransport */
move a0, sp
j do_extended_irq
END(titan_handle_int)
.set reorder
.align 5
ll_pcia_irq:
li a0, 2
move a1, sp
#ifdef CONFIG_HYPERTRANSPORT
j ll_ht_smp_irq_handler
#else
j do_IRQ
#endif
ll_pcib_irq:
li a0, 3
move a1, sp
j do_IRQ
ll_duart_irq:
li a0, 4
move a1, sp
j do_IRQ
ll_smp_irq:
li a0, 5
move a1, sp
#ifdef CONFIG_SMP
j titan_mailbox_irq
#else
j do_IRQ
#endif
ll_ht_irq:
li a0, 6
move a1, sp
j ll_ht_smp_irq_handler
ll_timer_irq:
li a0, 7
move a1, sp
j do_IRQ
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
* Copyright (C) 2003 PMC-Sierra Inc. * Copyright (C) 2003 PMC-Sierra Inc.
* Author: Manish Lachwani (lachwani@pmc-sierra.com) * Author: Manish Lachwani (lachwani@pmc-sierra.com)
* *
* Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
*
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the * under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your * Free Software Foundation; either version 2 of the License, or (at your
...@@ -55,7 +57,6 @@ ...@@ -55,7 +57,6 @@
#define HYPERTRANSPORT_INTC 0x7a /* INTC# */ #define HYPERTRANSPORT_INTC 0x7a /* INTC# */
#define HYPERTRANSPORT_INTD 0x7b /* INTD# */ #define HYPERTRANSPORT_INTD 0x7b /* INTD# */
extern asmlinkage void titan_handle_int(void);
extern void jaguar_mailbox_irq(struct pt_regs *); extern void jaguar_mailbox_irq(struct pt_regs *);
/* /*
...@@ -125,6 +126,35 @@ asmlinkage void do_extended_irq(struct pt_regs *regs) ...@@ -125,6 +126,35 @@ asmlinkage void do_extended_irq(struct pt_regs *regs)
} }
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int cause = read_c0_cause();
unsigned int status = read_c0_status();
unsigned int pending = cause & status;
if (pending & STATUSF_IP7) {
do_IRQ(7, regs);
} else if (pending & STATUSF_IP2) {
#ifdef CONFIG_HYPERTRANSPORT
ll_ht_smp_irq_handler(2, regs);
#else
do_IRQ(2, regs);
#endif
} else if (pending & STATUSF_IP3) {
do_IRQ(3, regs);
} else if (pending & STATUSF_IP4) {
do_IRQ(4, regs);
} else if (pending & STATUSF_IP5) {
#ifdef CONFIG_SMP
titan_mailbox_irq(regs);
#else
do_IRQ(5, regs);
#endif
} else if (pending & STATUSF_IP6) {
do_IRQ(4, regs);
}
}
#ifdef CONFIG_KGDB #ifdef CONFIG_KGDB
extern void init_second_port(void); extern void init_second_port(void);
#endif #endif
...@@ -136,7 +166,6 @@ void __init arch_init_irq(void) ...@@ -136,7 +166,6 @@ void __init arch_init_irq(void)
{ {
clear_c0_status(ST0_IM); clear_c0_status(ST0_IM);
set_except_vector(0, titan_handle_int);
mips_cpu_irq_init(0); mips_cpu_irq_init(0);
rm7k_cpu_irq_init(8); rm7k_cpu_irq_init(8);
rm9k_cpu_irq_init(12); rm9k_cpu_irq_init(12);
......
...@@ -2,6 +2,6 @@ ...@@ -2,6 +2,6 @@
# Makefile for Qemu specific kernel interface routines under Linux. # Makefile for Qemu specific kernel interface routines under Linux.
# #
obj-y = q-firmware.o q-int.o q-irq.o q-mem.o q-setup.o obj-y = q-firmware.o q-irq.o q-mem.o q-setup.o
obj-$(CONFIG_SMP) += q-smp.o obj-$(CONFIG_SMP) += q-smp.o
/*
* Qemu interrupt handler code.
*
* Copyright (C) 2005 by Ralf Baechle
*/
#include <asm/asm.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
.align 5
NESTED(qemu_handle_int, PT_SIZE, sp)
SAVE_ALL
CLI
move a0, sp
PTR_LA ra, ret_from_irq
j do_qemu_int
END(qemu_handle_int)
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
extern asmlinkage void qemu_handle_int(void); extern asmlinkage void qemu_handle_int(void);
asmlinkage void do_qemu_int(struct pt_regs *regs) asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{ {
unsigned int pending = read_c0_status() & read_c0_cause(); unsigned int pending = read_c0_status() & read_c0_cause();
...@@ -29,7 +29,6 @@ asmlinkage void do_qemu_int(struct pt_regs *regs) ...@@ -29,7 +29,6 @@ asmlinkage void do_qemu_int(struct pt_regs *regs)
void __init arch_init_irq(void) void __init arch_init_irq(void)
{ {
set_except_vector(0, qemu_handle_int);
mips_hpt_frequency = QEMU_C0_COUNTER_CLOCK; /* 100MHz */ mips_hpt_frequency = QEMU_C0_COUNTER_CLOCK; /* 100MHz */
init_i8259_irqs(); init_i8259_irqs();
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# under Linux. # under Linux.
# #
obj-y += ip22-mc.o ip22-hpc.o ip22-int.o ip22-irq.o ip22-berr.o \ obj-y += ip22-mc.o ip22-hpc.o ip22-int.o ip22-berr.o \
ip22-time.o ip22-nvram.o ip22-reset.o ip22-setup.o ip22-time.o ip22-nvram.o ip22-reset.o ip22-setup.o
obj-$(CONFIG_EISA) += ip22-eisa.o obj-$(CONFIG_EISA) += ip22-eisa.o
......
...@@ -37,7 +37,6 @@ static char lc1msk_to_irqnr[256]; ...@@ -37,7 +37,6 @@ static char lc1msk_to_irqnr[256];
static char lc2msk_to_irqnr[256]; static char lc2msk_to_irqnr[256];
static char lc3msk_to_irqnr[256]; static char lc3msk_to_irqnr[256];
extern asmlinkage void indyIRQ(void);
extern int ip22_eisa_init(void); extern int ip22_eisa_init(void);
static void enable_local0_irq(unsigned int irq) static void enable_local0_irq(unsigned int irq)
...@@ -224,7 +223,7 @@ static struct hw_interrupt_type ip22_local3_irq_type = { ...@@ -224,7 +223,7 @@ static struct hw_interrupt_type ip22_local3_irq_type = {
.end = end_local3_irq, .end = end_local3_irq,
}; };
void indy_local0_irqdispatch(struct pt_regs *regs) static void indy_local0_irqdispatch(struct pt_regs *regs)
{ {
u8 mask = sgint->istat0 & sgint->imask0; u8 mask = sgint->istat0 & sgint->imask0;
u8 mask2; u8 mask2;
...@@ -242,7 +241,7 @@ void indy_local0_irqdispatch(struct pt_regs *regs) ...@@ -242,7 +241,7 @@ void indy_local0_irqdispatch(struct pt_regs *regs)
return; return;
} }
void indy_local1_irqdispatch(struct pt_regs *regs) static void indy_local1_irqdispatch(struct pt_regs *regs)
{ {
u8 mask = sgint->istat1 & sgint->imask1; u8 mask = sgint->istat1 & sgint->imask1;
u8 mask2; u8 mask2;
...@@ -262,7 +261,7 @@ void indy_local1_irqdispatch(struct pt_regs *regs) ...@@ -262,7 +261,7 @@ void indy_local1_irqdispatch(struct pt_regs *regs)
extern void ip22_be_interrupt(int irq, struct pt_regs *regs); extern void ip22_be_interrupt(int irq, struct pt_regs *regs);
void indy_buserror_irq(struct pt_regs *regs) static void indy_buserror_irq(struct pt_regs *regs)
{ {
int irq = SGI_BUSERR_IRQ; int irq = SGI_BUSERR_IRQ;
...@@ -307,6 +306,56 @@ static struct irqaction map1_cascade = { ...@@ -307,6 +306,56 @@ static struct irqaction map1_cascade = {
#define SGI_INTERRUPTS SGINT_LOCAL3 #define SGI_INTERRUPTS SGINT_LOCAL3
#endif #endif
extern void indy_r4k_timer_interrupt(struct pt_regs *regs);
extern void indy_8254timer_irq(struct pt_regs *regs);
/*
* IRQs on the INDY look basically (barring software IRQs which we don't use
* at all) like:
*
* MIPS IRQ Source
* -------- ------
* 0 Software (ignored)
* 1 Software (ignored)
* 2 Local IRQ level zero
* 3 Local IRQ level one
* 4 8254 Timer zero
* 5 8254 Timer one
* 6 Bus Error
* 7 R4k timer (what we use)
*
* We handle the IRQ according to _our_ priority which is:
*
* Highest ---- R4k Timer
* Local IRQ zero
* Local IRQ one
* Bus Error
* 8254 Timer zero
* Lowest ---- 8254 Timer one
*
* then we just return, if multiple IRQs are pending then we will just take
* another exception, big deal.
*/
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending = read_c0_cause();
/*
* First we check for r4k counter/timer IRQ.
*/
if (pending & CAUSEF_IP7)
indy_r4k_timer_interrupt(regs);
else if (pending & CAUSEF_IP2)
indy_local0_irqdispatch(regs);
else if (pending & CAUSEF_IP3)
indy_local1_irqdispatch(regs);
else if (pending & CAUSEF_IP6)
indy_buserror_irq(regs);
else if (pending & (CAUSEF_IP4 | CAUSEF_IP5))
indy_8254timer_irq(regs);
}
extern void mips_cpu_irq_init(unsigned int irq_base); extern void mips_cpu_irq_init(unsigned int irq_base);
void __init arch_init_irq(void) void __init arch_init_irq(void)
...@@ -369,8 +418,6 @@ void __init arch_init_irq(void) ...@@ -369,8 +418,6 @@ void __init arch_init_irq(void)
sgint->cmeimask0 = 0; sgint->cmeimask0 = 0;
sgint->cmeimask1 = 0; sgint->cmeimask1 = 0;
set_except_vector(0, indyIRQ);
/* init CPU irqs */ /* init CPU irqs */
mips_cpu_irq_init(SGINT_CPU); mips_cpu_irq_init(SGINT_CPU);
......
/*
* ip22-irq.S: Interrupt exception dispatch code for FullHouse and
* Guiness.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*/
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
/* A lot of complication here is taken away because:
*
* 1) We handle one interrupt and return, sitting in a loop and moving across
* all the pending IRQ bits in the cause register is _NOT_ the answer, the
* common case is one pending IRQ so optimize in that direction.
*
* 2) We need not check against bits in the status register IRQ mask, that
* would make this routine slow as hell.
*
* 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
* between like BSD spl() brain-damage.
*
* Furthermore, the IRQs on the INDY look basically (barring software IRQs
* which we don't use at all) like:
*
* MIPS IRQ Source
* -------- ------
* 0 Software (ignored)
* 1 Software (ignored)
* 2 Local IRQ level zero
* 3 Local IRQ level one
* 4 8254 Timer zero
* 5 8254 Timer one
* 6 Bus Error
* 7 R4k timer (what we use)
*
* We handle the IRQ according to _our_ priority which is:
*
* Highest ---- R4k Timer
* Local IRQ zero
* Local IRQ one
* Bus Error
* 8254 Timer zero
* Lowest ---- 8254 Timer one
*
* then we just return, if multiple IRQs are pending then we will just take
* another exception, big deal.
*/
.text
.set noreorder
.set noat
.align 5
NESTED(indyIRQ, PT_SIZE, sp)
SAVE_ALL
CLI
.set at
mfc0 s0, CP0_CAUSE # get irq mask
/* First we check for r4k counter/timer IRQ. */
andi a0, s0, CAUSEF_IP7
beq a0, zero, 1f
andi a0, s0, CAUSEF_IP2 # delay slot, check local level zero
/* Wheee, a timer interrupt. */
jal indy_r4k_timer_interrupt
move a0, sp # delay slot
j ret_from_irq
nop # delay slot
1:
beq a0, zero, 1f
andi a0, s0, CAUSEF_IP3 # delay slot, check local level one
/* Wheee, local level zero interrupt. */
jal indy_local0_irqdispatch
move a0, sp # delay slot
j ret_from_irq
nop # delay slot
1:
beq a0, zero, 1f
andi a0, s0, CAUSEF_IP6 # delay slot, check bus error
/* Wheee, local level one interrupt. */
jal indy_local1_irqdispatch
move a0, sp # delay slot
j ret_from_irq
nop # delay slot
1:
beq a0, zero, 1f
andi a0, s0, (CAUSEF_IP4 | CAUSEF_IP5) # delay slot
/* Wheee, an asynchronous bus error... */
jal indy_buserror_irq
move a0, sp # delay slot
j ret_from_irq
nop # delay slot
1:
/* Here by mistake? It is possible, that by the time we take
* the exception the IRQ pin goes low, so just leave if this
* is the case.
*/
beq a0, zero, 1f
nop # delay slot
/* Must be one of the 8254 timers... */
jal indy_8254timer_irq
move a0, sp # delay slot
1:
j ret_from_irq
nop # delay slot
END(indyIRQ)
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Makefile for the IP27 specific kernel interface routines under Linux. # Makefile for the IP27 specific kernel interface routines under Linux.
# #
obj-y := ip27-berr.o ip27-console.o ip27-irq.o ip27-init.o ip27-irq-glue.o \ obj-y := ip27-berr.o ip27-console.o ip27-irq.o ip27-init.o \
ip27-klconfig.o ip27-klnuma.o ip27-memory.o ip27-nmi.o ip27-reset.o \ ip27-klconfig.o ip27-klnuma.o ip27-memory.o ip27-nmi.o ip27-reset.o \
ip27-timer.o ip27-hubio.o ip27-xtalk.o ip27-timer.o ip27-hubio.o ip27-xtalk.o
......
...@@ -9,10 +9,6 @@ ip27-init.c:find_lbaord_real. DONE ...@@ -9,10 +9,6 @@ ip27-init.c:find_lbaord_real. DONE
in irix? in irix?
6. Investigate why things do not work without the setup_test() call 6. Investigate why things do not work without the setup_test() call
being invoked on all nodes in ip27-memory.c. being invoked on all nodes in ip27-memory.c.
7. Too many CLIs in the locore handlers :
For the low level handlers set up by set_except_vector(),
__tlb_refill_debug_tramp, __xtlb_refill_debug_tramp and cacheerror,
investigate whether the code should do CLI, STI or KMODE.
8. Too many do_page_faults invoked - investigate. 8. Too many do_page_faults invoked - investigate.
9. start_thread must turn off UX64 ... and define tlb_refill_debug. 9. start_thread must turn off UX64 ... and define tlb_refill_debug.
10. Need a bad pmd table, bad pte table. __bad_pmd_table/__bad_pagetable 10. Need a bad pmd table, bad pte table. __bad_pmd_table/__bad_pagetable
......
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1999 Ralf Baechle
* Copyright (C) 1999 Silicon Graphics, Inc.
*/
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
.text
.align 5
NESTED(ip27_irq, PT_SIZE, sp)
SAVE_ALL
CLI
mfc0 s0, CP0_CAUSE
mfc0 t0, CP0_STATUS
and s0, t0
move a0, sp
PTR_LA ra, ret_from_irq
/* First check for RT interrupt. */
andi t0, s0, CAUSEF_IP4
bnez t0, ip4
andi t0, s0, CAUSEF_IP2
bnez t0, ip2
andi t0, s0, CAUSEF_IP3
bnez t0, ip3
andi t0, s0, CAUSEF_IP5
bnez t0, ip5
andi t0, s0, CAUSEF_IP6
bnez t0, ip6
j ra
ip2: j ip27_do_irq_mask0 # PI_INT_PEND_0 or CC_PEND_{A|B}
ip3: j ip27_do_irq_mask1 # PI_INT_PEND_1
ip4: j ip27_rt_timer_interrupt
ip5: j ip27_prof_timer
ip6: j ip27_hub_error
END(ip27_irq)
...@@ -130,7 +130,7 @@ static int ms1bit(unsigned long x) ...@@ -130,7 +130,7 @@ static int ms1bit(unsigned long x)
* Kanoj 05.13.00 * Kanoj 05.13.00
*/ */
void ip27_do_irq_mask0(struct pt_regs *regs) static void ip27_do_irq_mask0(struct pt_regs *regs)
{ {
int irq, swlevel; int irq, swlevel;
hubreg_t pend0, mask0; hubreg_t pend0, mask0;
...@@ -171,7 +171,7 @@ void ip27_do_irq_mask0(struct pt_regs *regs) ...@@ -171,7 +171,7 @@ void ip27_do_irq_mask0(struct pt_regs *regs)
LOCAL_HUB_L(PI_INT_PEND0); LOCAL_HUB_L(PI_INT_PEND0);
} }
void ip27_do_irq_mask1(struct pt_regs *regs) static void ip27_do_irq_mask1(struct pt_regs *regs)
{ {
int irq, swlevel; int irq, swlevel;
hubreg_t pend1, mask1; hubreg_t pend1, mask1;
...@@ -196,12 +196,12 @@ void ip27_do_irq_mask1(struct pt_regs *regs) ...@@ -196,12 +196,12 @@ void ip27_do_irq_mask1(struct pt_regs *regs)
LOCAL_HUB_L(PI_INT_PEND1); LOCAL_HUB_L(PI_INT_PEND1);
} }
void ip27_prof_timer(struct pt_regs *regs) static void ip27_prof_timer(struct pt_regs *regs)
{ {
panic("CPU %d got a profiling interrupt", smp_processor_id()); panic("CPU %d got a profiling interrupt", smp_processor_id());
} }
void ip27_hub_error(struct pt_regs *regs) static void ip27_hub_error(struct pt_regs *regs)
{ {
panic("CPU %d got a hub error interrupt", smp_processor_id()); panic("CPU %d got a hub error interrupt", smp_processor_id());
} }
...@@ -421,9 +421,26 @@ int __devinit request_bridge_irq(struct bridge_controller *bc) ...@@ -421,9 +421,26 @@ int __devinit request_bridge_irq(struct bridge_controller *bc)
return irq; return irq;
} }
extern void ip27_rt_timer_interrupt(struct pt_regs *regs);
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned long pending = read_c0_cause() & read_c0_status();
if (pending & CAUSEF_IP4)
ip27_rt_timer_interrupt(regs);
else if (pending & CAUSEF_IP2) /* PI_INT_PEND_0 or CC_PEND_{A|B} */
ip27_do_irq_mask0(regs);
else if (pending & CAUSEF_IP3) /* PI_INT_PEND_1 */
ip27_do_irq_mask1(regs);
else if (pending & CAUSEF_IP5)
ip27_prof_timer(regs);
else if (pending & CAUSEF_IP6)
ip27_hub_error(regs);
}
void __init arch_init_irq(void) void __init arch_init_irq(void)
{ {
set_except_vector(0, ip27_irq);
} }
void install_ipi(void) void install_ipi(void)
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# under Linux. # under Linux.
# #
obj-y += ip32-berr.o ip32-irq.o ip32-irq-glue.o ip32-setup.o ip32-reset.o \ obj-y += ip32-berr.o ip32-irq.o ip32-setup.o ip32-reset.o \
crime.o ip32-memory.o crime.o ip32-memory.o
EXTRA_AFLAGS := $(CFLAGS) EXTRA_AFLAGS := $(CFLAGS)
/*
* Low level interrupt handler for the SGI O2 aka IP32 aka Moosehead
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2000 Harald Koerfgen
* Copyright (C) 2001 Keith M Wesolowski
*/
#include <asm/asm.h>
#include <asm/regdef.h>
#include <asm/mipsregs.h>
#include <asm/stackframe.h>
#include <asm/addrspace.h>
.text
.set noreorder
.set noat
.align 5
NESTED(ip32_handle_int, PT_SIZE, ra)
.set noat
SAVE_ALL
CLI # TEST: interrupts should be off
.set at
.set noreorder
mfc0 s0,CP0_CAUSE
andi t1, s0, IE_IRQ0
bnez t1, handle_irq0
andi t1, s0, IE_IRQ1
bnez t1, handle_irq1
andi t1, s0, IE_IRQ2
bnez t1, handle_irq2
andi t1, s0, IE_IRQ3
bnez t1, handle_irq3
andi t1, s0, IE_IRQ4
bnez t1, handle_irq4
andi t1, s0, IE_IRQ5
bnez t1, handle_irq5
nop
/* Either someone has triggered the "software interrupts"
* or we lost an interrupt somehow. Ignore it.
*/
j ret_from_irq
nop
handle_irq0:
jal ip32_irq0
move a0, sp
j ret_from_irq
nop
handle_irq1:
jal ip32_irq1
move a0, sp
j ret_from_irq
nop
handle_irq2:
jal ip32_irq2
move a0, sp
j ret_from_irq
nop
handle_irq3:
jal ip32_irq3
move a0, sp
j ret_from_irq
nop
handle_irq4:
jal ip32_irq4
move a0, sp
j ret_from_irq
nop
handle_irq5:
jal ip32_irq5
move a0, sp
j ret_from_irq
nop
END(ip32_handle_int)
...@@ -130,8 +130,6 @@ struct irqaction memerr_irq = { crime_memerr_intr, SA_INTERRUPT, ...@@ -130,8 +130,6 @@ struct irqaction memerr_irq = { crime_memerr_intr, SA_INTERRUPT,
struct irqaction cpuerr_irq = { crime_cpuerr_intr, SA_INTERRUPT, struct irqaction cpuerr_irq = { crime_cpuerr_intr, SA_INTERRUPT,
CPU_MASK_NONE, "CRIME CPU error", NULL, NULL }; CPU_MASK_NONE, "CRIME CPU error", NULL, NULL };
extern void ip32_handle_int(void);
/* /*
* For interrupts wired from a single device to the CPU. Only the clock * For interrupts wired from a single device to the CPU. Only the clock
* uses this it seems, which is IRQ 0 and IP7. * uses this it seems, which is IRQ 0 and IP7.
...@@ -503,7 +501,7 @@ static void ip32_unknown_interrupt(struct pt_regs *regs) ...@@ -503,7 +501,7 @@ static void ip32_unknown_interrupt(struct pt_regs *regs)
/* CRIME 1.1 appears to deliver all interrupts to this one pin. */ /* CRIME 1.1 appears to deliver all interrupts to this one pin. */
/* change this to loop over all edge-triggered irqs, exception masked out ones */ /* change this to loop over all edge-triggered irqs, exception masked out ones */
void ip32_irq0(struct pt_regs *regs) static void ip32_irq0(struct pt_regs *regs)
{ {
uint64_t crime_int; uint64_t crime_int;
int irq = 0; int irq = 0;
...@@ -520,31 +518,49 @@ void ip32_irq0(struct pt_regs *regs) ...@@ -520,31 +518,49 @@ void ip32_irq0(struct pt_regs *regs)
do_IRQ(irq, regs); do_IRQ(irq, regs);
} }
void ip32_irq1(struct pt_regs *regs) static void ip32_irq1(struct pt_regs *regs)
{ {
ip32_unknown_interrupt(regs); ip32_unknown_interrupt(regs);
} }
void ip32_irq2(struct pt_regs *regs) static void ip32_irq2(struct pt_regs *regs)
{ {
ip32_unknown_interrupt(regs); ip32_unknown_interrupt(regs);
} }
void ip32_irq3(struct pt_regs *regs) static void ip32_irq3(struct pt_regs *regs)
{ {
ip32_unknown_interrupt(regs); ip32_unknown_interrupt(regs);
} }
void ip32_irq4(struct pt_regs *regs) static void ip32_irq4(struct pt_regs *regs)
{ {
ip32_unknown_interrupt(regs); ip32_unknown_interrupt(regs);
} }
void ip32_irq5(struct pt_regs *regs) static void ip32_irq5(struct pt_regs *regs)
{ {
ll_timer_interrupt(IP32_R4K_TIMER_IRQ, regs); ll_timer_interrupt(IP32_R4K_TIMER_IRQ, regs);
} }
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending = read_c0_cause();
if (likely(pending & IE_IRQ0))
ip32_irq0(regs);
else if (unlikely(pending & IE_IRQ1))
ip32_irq1(regs);
else if (unlikely(pending & IE_IRQ2))
ip32_irq2(regs);
else if (unlikely(pending & IE_IRQ3))
ip32_irq3(regs);
else if (unlikely(pending & IE_IRQ4))
ip32_irq4(regs);
else if (likely(pending & IE_IRQ5))
ip32_irq5(regs);
}
void __init arch_init_irq(void) void __init arch_init_irq(void)
{ {
unsigned int irq; unsigned int irq;
...@@ -556,7 +572,6 @@ void __init arch_init_irq(void) ...@@ -556,7 +572,6 @@ void __init arch_init_irq(void)
crime->soft_int = 0; crime->soft_int = 0;
mace->perif.ctrl.istat = 0; mace->perif.ctrl.istat = 0;
mace->perif.ctrl.imask = 0; mace->perif.ctrl.imask = 0;
set_except_vector(0, ip32_handle_int);
for (irq = 0; irq <= IP32_IRQ_MAX; irq++) { for (irq = 0; irq <= IP32_IRQ_MAX; irq++) {
hw_irq_controller *controller; hw_irq_controller *controller;
......
obj-y := setup.o irq.o irq_handler.o time.o obj-y := setup.o irq.o time.o
obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SMP) += smp.o
......
...@@ -187,9 +187,6 @@ static void bcm1480_set_affinity(unsigned int irq, cpumask_t mask) ...@@ -187,9 +187,6 @@ static void bcm1480_set_affinity(unsigned int irq, cpumask_t mask)
#endif #endif
/* Defined in arch/mips/sibyte/bcm1480/irq_handler.S */
extern void bcm1480_irq_handler(void);
/*****************************************************************************/ /*****************************************************************************/
static unsigned int startup_bcm1480_irq(unsigned int irq) static unsigned int startup_bcm1480_irq(unsigned int irq)
...@@ -422,7 +419,6 @@ void __init arch_init_irq(void) ...@@ -422,7 +419,6 @@ void __init arch_init_irq(void)
#endif #endif
/* Enable necessary IPs, disable the rest */ /* Enable necessary IPs, disable the rest */
change_c0_status(ST0_IM, imask); change_c0_status(ST0_IM, imask);
set_except_vector(0, bcm1480_irq_handler);
#ifdef CONFIG_KGDB #ifdef CONFIG_KGDB
if (kgdb_flag) { if (kgdb_flag) {
...@@ -473,3 +469,76 @@ void bcm1480_kgdb_interrupt(struct pt_regs *regs) ...@@ -473,3 +469,76 @@ void bcm1480_kgdb_interrupt(struct pt_regs *regs)
} }
#endif /* CONFIG_KGDB */ #endif /* CONFIG_KGDB */
static inline int dclz(unsigned long long x)
{
int lz;
__asm__ (
" .set push \n"
" .set mips64 \n"
" dclz %0, %1 \n"
" .set pop \n"
: "=r" (lz)
: "r" (x));
return lz;
}
extern void bcm1480_timer_interrupt(struct pt_regs *regs);
extern void bcm1480_mailbox_interrupt(struct pt_regs *regs);
extern void bcm1480_kgdb_interrupt(struct pt_regs *regs);
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending;
#ifdef CONFIG_SIBYTE_BCM1480_PROF
/* Set compare to count to silence count/compare timer interrupts */
write_c0_compare(read_c0_count());
#endif
pending = read_c0_cause();
#ifdef CONFIG_SIBYTE_BCM1480_PROF
if (pending & CAUSEF_IP7) /* Cpu performance counter interrupt */
sbprof_cpu_intr(exception_epc(regs));
#endif
if (pending & CAUSEF_IP4)
bcm1480_timer_interrupt(regs);
#ifdef CONFIG_SMP
if (pending & CAUSEF_IP3)
bcm1480_mailbox_interrupt(regs);
#endif
#ifdef CONFIG_KGDB
if (pending & CAUSEF_IP6)
bcm1480_kgdb_interrupt(regs); /* KGDB (uart 1) */
#endif
if (pending & CAUSEF_IP2) {
unsigned long long mask_h, mask_l;
unsigned long base;
/*
* Default...we've hit an IP[2] interrupt, which means we've
* got to check the 1480 interrupt registers to figure out what
* to do. Need to detect which CPU we're on, now that
* smp_affinity is supported.
*/
base = A_BCM1480_IMR_MAPPER(smp_processor_id());
mask_h = __raw_readq(
IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H));
mask_l = __raw_readq(
IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L));
if (!mask_h) {
if (mask_h ^ 1)
do_IRQ(63 - dclz(mask_h), regs);
else
do_IRQ(127 - dclz(mask_l), regs);
}
}
}
/*
* Copyright (C) 2000,2001,2002,2003,2004 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* bcm1480_irq_handler() is the routine that is actually called when an
* interrupt occurs. It is installed as the exception vector handler in
* init_IRQ() in arch/mips/sibyte/bcm1480/irq.c
*
* In the handle we figure out which interrupts need handling, and use that
* to call the dispatcher, which will take care of actually calling
* registered handlers
*
* Note that we take care of all raised interrupts in one go at the handler.
* This is more BSDish than the Indy code, and also, IMHO, more sane.
*/
#include <linux/config.h>
#include <asm/addrspace.h>
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
#include <asm/sibyte/sb1250_defs.h>
#include <asm/sibyte/bcm1480_regs.h>
#include <asm/sibyte/bcm1480_int.h>
/*
* What a pain. We have to be really careful saving the upper 32 bits of any
* register across function calls if we don't want them trashed--since were
* running in -o32, the calling routing never saves the full 64 bits of a
* register across a function call. Being the interrupt handler, we're
* guaranteed that interrupts are disabled during this code so we don't have
* to worry about random interrupts blasting the high 32 bits.
*/
.text
.set push
.set noreorder
.set noat
.set mips64
#.set mips4
.align 5
NESTED(bcm1480_irq_handler, PT_SIZE, sp)
SAVE_ALL
CLI
#ifdef CONFIG_SIBYTE_BCM1480_PROF
/* Set compare to count to silence count/compare timer interrupts */
mfc0 t1, CP0_COUNT
mtc0 t1, CP0_COMPARE /* pause to clear IP[7] bit of cause ? */
#endif
/* Read cause */
mfc0 s0, CP0_CAUSE
#ifdef CONFIG_SIBYTE_BCM1480_PROF
/* Cpu performance counter interrupt is routed to IP[7] */
andi t1, s0, CAUSEF_IP7
beqz t1, 0f
srl t1, s0, (CAUSEB_BD-2) /* Shift BD bit to bit 2 */
and t1, t1, 0x4 /* mask to get just BD bit */
#ifdef CONFIG_MIPS64
dmfc0 a0, CP0_EPC
daddu a0, a0, t1 /* a0 = EPC + (BD ? 4 : 0) */
#else
mfc0 a0, CP0_EPC
addu a0, a0, t1 /* a0 = EPC + (BD ? 4 : 0) */
#endif
jal sbprof_cpu_intr
nop
j ret_from_irq
nop
0:
#endif
/* Timer interrupt is routed to IP[4] */
andi t1, s0, CAUSEF_IP4
beqz t1, 1f
nop
jal bcm1480_timer_interrupt
move a0, sp /* Pass the registers along */
j ret_from_irq
nop /* delay slot */
1:
#ifdef CONFIG_SMP
/* Mailbox interrupt is routed to IP[3] */
andi t1, s0, CAUSEF_IP3
beqz t1, 2f
nop
jal bcm1480_mailbox_interrupt
move a0, sp
j ret_from_irq
nop /* delay slot */
2:
#endif
#ifdef CONFIG_KGDB
/* KGDB (uart 1) interrupt is routed to IP[6] */
andi t1, s0, CAUSEF_IP6
beqz t1, 3f
nop /* delay slot */
jal bcm1480_kgdb_interrupt
move a0, sp
j ret_from_irq
nop /* delay slot */
3:
#endif
and t1, s0, CAUSEF_IP2
beqz t1, 9f
nop
/*
* Default...we've hit an IP[2] interrupt, which means we've got
* to check the 1480 interrupt registers to figure out what to do
* Need to detect which CPU we're on, now that smp_affinity is
* supported.
*/
PTR_LA v0, CKSEG1 + A_BCM1480_IMR_CPU0_BASE
#ifdef CONFIG_SMP
lw t1, TI_CPU($28)
sll t1, t1, BCM1480_IMR_REGISTER_SPACING_SHIFT
addu v0, v0, t1
#endif
/* Read IP[2] status (get both high and low halves of status) */
ld s0, R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H(v0)
ld s1, R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L(v0)
move s2, zero /* intr number */
li s3, 64
beqz s0, 9f /* No interrupts. Return. */
move a1, sp
xori s4, s0, 1 /* if s0 (_H) == 1, it's a low intr, so... */
movz s2, s3, s4 /* start the intr number at 64, and */
movz s0, s1, s4 /* look at the low status value. */
dclz s1, s0 /* Find the next interrupt. */
dsubu a0, zero, s1
daddiu a0, a0, 63
jal do_IRQ
daddu a0, a0, s2
9: j ret_from_irq
nop
.set pop
END(bcm1480_irq_handler)
obj-y := setup.o irq.o irq_handler.o time.o obj-y := setup.o irq.o time.o
obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_SIBYTE_TBPROF) += bcm1250_tbprof.o obj-$(CONFIG_SIBYTE_TBPROF) += bcm1250_tbprof.o
......
...@@ -163,10 +163,6 @@ static void sb1250_set_affinity(unsigned int irq, cpumask_t mask) ...@@ -163,10 +163,6 @@ static void sb1250_set_affinity(unsigned int irq, cpumask_t mask)
} }
#endif #endif
/* Defined in arch/mips/sibyte/sb1250/irq_handler.S */
extern void sb1250_irq_handler(void);
/*****************************************************************************/ /*****************************************************************************/
static unsigned int startup_sb1250_irq(unsigned int irq) static unsigned int startup_sb1250_irq(unsigned int irq)
...@@ -379,7 +375,6 @@ void __init arch_init_irq(void) ...@@ -379,7 +375,6 @@ void __init arch_init_irq(void)
#endif #endif
/* Enable necessary IPs, disable the rest */ /* Enable necessary IPs, disable the rest */
change_c0_status(ST0_IM, imask); change_c0_status(ST0_IM, imask);
set_except_vector(0, sb1250_irq_handler);
#ifdef CONFIG_KGDB #ifdef CONFIG_KGDB
if (kgdb_flag) { if (kgdb_flag) {
...@@ -409,7 +404,7 @@ void __init arch_init_irq(void) ...@@ -409,7 +404,7 @@ void __init arch_init_irq(void)
#define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg))) #define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg)))
#define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg))) #define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg)))
void sb1250_kgdb_interrupt(struct pt_regs *regs) static void sb1250_kgdb_interrupt(struct pt_regs *regs)
{ {
/* /*
* Clear break-change status (allow some time for the remote * Clear break-change status (allow some time for the remote
...@@ -424,3 +419,74 @@ void sb1250_kgdb_interrupt(struct pt_regs *regs) ...@@ -424,3 +419,74 @@ void sb1250_kgdb_interrupt(struct pt_regs *regs)
} }
#endif /* CONFIG_KGDB */ #endif /* CONFIG_KGDB */
static inline int dclz(unsigned long long x)
{
int lz;
__asm__ (
" .set push \n"
" .set mips64 \n"
" dclz %0, %1 \n"
" .set pop \n"
: "=r" (lz)
: "r" (x));
return lz;
}
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending;
#ifdef CONFIG_SIBYTE_SB1250_PROF
/* Set compare to count to silence count/compare timer interrupts */
write_c0_count(read_c0_count());
#endif
/*
* What a pain. We have to be really careful saving the upper 32 bits
* of any * register across function calls if we don't want them
* trashed--since were running in -o32, the calling routing never saves
* the full 64 bits of a register across a function call. Being the
* interrupt handler, we're guaranteed that interrupts are disabled
* during this code so we don't have to worry about random interrupts
* blasting the high 32 bits.
*/
pending = read_c0_cause();
#ifdef CONFIG_SIBYTE_SB1250_PROF
if (pending & CAUSEF_IP7) { /* Cpu performance counter interrupt */
sbprof_cpu_intr(exception_epc(regs));
}
#endif
if (pending & CAUSEF_IP4)
sb1250_timer_interrupt(regs);
#ifdef CONFIG_SMP
if (pending & CAUSEF_IP3)
sb1250_mailbox_interrupt(regs);
#endif
#ifdef CONFIG_KGDB
if (pending & CAUSEF_IP6) /* KGDB (uart 1) */
sb1250_kgdb_interrupt(regs);
#endif
if (pending & CAUSEF_IP2) {
unsigned long long mask;
/*
* Default...we've hit an IP[2] interrupt, which means we've
* got to check the 1250 interrupt registers to figure out what
* to do. Need to detect which CPU we're on, now that
~ smp_affinity is supported.
*/
mask = __raw_readq(IOADDR(A_IMR_REGISTER(smp_processor_id(),
R_IMR_INTERRUPT_STATUS_BASE)));
if (mask)
do_IRQ(63 - dclz(mask), regs);
}
}
/*
* Copyright (C) 2000, 2001, 2002, 2003 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* sb1250_handle_int() is the routine that is actually called when an interrupt
* occurs. It is installed as the exception vector handler in arch_init_irq()
* in arch/mips/sibyte/sb1250/irq.c
*
* In the handle we figure out which interrupts need handling, and use that to
* call the dispatcher, which will take care of actually calling registered
* handlers
*
* Note that we take care of all raised interrupts in one go at the handler.
* This is more BSDish than the Indy code, and also, IMHO, more sane.
*/
#include <linux/config.h>
#include <asm/addrspace.h>
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
#include <asm/sibyte/sb1250_defs.h>
#include <asm/sibyte/sb1250_regs.h>
#include <asm/sibyte/sb1250_int.h>
/*
* What a pain. We have to be really careful saving the upper 32 bits of any
* register across function calls if we don't want them trashed--since were
* running in -o32, the calling routing never saves the full 64 bits of a
* register across a function call. Being the interrupt handler, we're
* guaranteed that interrupts are disabled during this code so we don't have
* to worry about random interrupts blasting the high 32 bits.
*/
.text
.set push
.set noreorder
.set noat
.set mips64
.align 5
NESTED(sb1250_irq_handler, PT_SIZE, sp)
SAVE_ALL
CLI
#ifdef CONFIG_SIBYTE_SB1250_PROF
/* Set compare to count to silence count/compare timer interrupts */
mfc0 t1, CP0_COUNT
mtc0 t1, CP0_COMPARE /* pause to clear IP[7] bit of cause ? */
#endif
/* Read cause */
mfc0 s0, CP0_CAUSE
#ifdef CONFIG_SIBYTE_SB1250_PROF
/* Cpu performance counter interrupt is routed to IP[7] */
andi t1, s0, CAUSEF_IP7
beqz t1, 0f
srl t1, s0, (CAUSEB_BD-2) /* Shift BD bit to bit 2 */
and t1, t1, 0x4 /* mask to get just BD bit */
mfc0 a0, CP0_EPC
jal sbprof_cpu_intr
addu a0, a0, t1 /* a0 = EPC + (BD ? 4 : 0) */
j ret_from_irq
nop
0:
#endif
/* Timer interrupt is routed to IP[4] */
andi t1, s0, CAUSEF_IP4
beqz t1, 1f
nop
jal sb1250_timer_interrupt
move a0, sp /* Pass the registers along */
j ret_from_irq
nop # delay slot
1:
#ifdef CONFIG_SMP
/* Mailbox interrupt is routed to IP[3] */
andi t1, s0, CAUSEF_IP3
beqz t1, 2f
nop
jal sb1250_mailbox_interrupt
move a0, sp
j ret_from_irq
nop # delay slot
2:
#endif
#ifdef CONFIG_KGDB
/* KGDB (uart 1) interrupt is routed to IP[6] */
andi t1, s0, CAUSEF_IP6
beqz t1, 1f
nop # delay slot
jal sb1250_kgdb_interrupt
move a0, sp
j ret_from_irq
nop # delay slot
1:
#endif
and t1, s0, CAUSEF_IP2
beqz t1, 4f
nop
/*
* Default...we've hit an IP[2] interrupt, which means we've got to
* check the 1250 interrupt registers to figure out what to do
* Need to detect which CPU we're on, now that smp_affinity is supported.
*/
PTR_LA v0, CKSEG1 + A_IMR_CPU0_BASE
#ifdef CONFIG_SMP
lw t1, TI_CPU($28)
sll t1, IMR_REGISTER_SPACING_SHIFT
addu v0, t1
#endif
ld s0, R_IMR_INTERRUPT_STATUS_BASE(v0) /* read IP[2] status */
beqz s0, 4f /* No interrupts. Return */
move a1, sp
3: dclz s1, s0 /* Find the next interrupt */
dsubu a0, zero, s1
daddiu a0, a0, 63
jal do_IRQ
nop
4: j ret_from_irq
nop
.set pop
END(sb1250_irq_handler)
...@@ -2,6 +2,6 @@ ...@@ -2,6 +2,6 @@
# Makefile for the SNI specific part of the kernel # Makefile for the SNI specific part of the kernel
# #
obj-y += int-handler.o irq.o pcimt_scache.o reset.o setup.o obj-y += irq.o pcimt_scache.o reset.o setup.o
EXTRA_AFLAGS := $(CFLAGS) EXTRA_AFLAGS := $(CFLAGS)
/*
* SNI RM200 PCI specific interrupt handler code.
*
* Copyright (C) 1994, 95, 96, 97, 98, 1999, 2000, 01 by Ralf Baechle
*/
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/regdef.h>
#include <asm/sni.h>
#include <asm/stackframe.h>
/*
* The PCI ASIC has the nasty property that it may delay writes if it is busy.
* As a consequence from writes that have not graduated when we exit from the
* interrupt handler we might catch a spurious interrupt. To avoid this we
* force the PCI ASIC to graduate all writes by executing a read from the
* PCI bus.
*/
.set noreorder
.set noat
.align 5
NESTED(sni_rm200_pci_handle_int, PT_SIZE, sp)
SAVE_ALL
CLI
.set at
/* Blinken light ... */
lb t0, led_cache
addiu t0, 1
sb t0, led_cache
sb t0, PCIMT_CSLED # write only register
.data
led_cache: .byte 0
.text
mfc0 t0, CP0_STATUS
mfc0 t1, CP0_CAUSE
and t0, t1
andi t1, t0, 0x0800 # hardware interrupt 1
bnez t1, _hwint1
andi t1, t0, 0x4000 # hardware interrupt 4
bnez t1, _hwint4
andi t1, t0, 0x2000 # hardware interrupt 3
bnez t1, _hwint3
andi t1, t0, 0x1000 # hardware interrupt 2
bnez t1, _hwint2
andi t1, t0, 0x8000 # hardware interrupt 5
bnez t1, _hwint5
andi t1, t0, 0x0400 # hardware interrupt 0
bnez t1, _hwint0
nop
j restore_all # spurious interrupt
nop
##############################################################################
/* hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug
button interrupts. */
_hwint0: jal pciasic_hwint0
move a0, sp
j ret_from_irq
nop
/*
* hwint 1 deals with EISA and SCSI interrupts
*/
_hwint1: jal pciasic_hwint1
move a0, sp
j ret_from_irq
nop
/*
* This interrupt was used for the com1 console on the first prototypes;
* it's unsed otherwise
*/
_hwint2: jal pciasic_hwint2
move a0, sp
j ret_from_irq
nop
/*
* hwint 3 are the PCI interrupts A - D
*/
_hwint3: jal pciasic_hwint3
move a0, sp
j ret_from_irq
nop
/*
* hwint 4 is used for only the onboard PCnet 32.
*/
_hwint4: jal pciasic_hwint4
move a0, sp
j ret_from_irq
nop
/* hwint5 is the r4k count / compare interrupt */
_hwint5: jal pciasic_hwint5
move a0, sp
j ret_from_irq
nop
END(sni_rm200_pci_handle_int)
...@@ -19,8 +19,6 @@ ...@@ -19,8 +19,6 @@
DEFINE_SPINLOCK(pciasic_lock); DEFINE_SPINLOCK(pciasic_lock);
extern asmlinkage void sni_rm200_pci_handle_int(void);
static void enable_pciasic_irq(unsigned int irq) static void enable_pciasic_irq(unsigned int irq)
{ {
unsigned int mask = 1 << (irq - PCIMT_IRQ_INT2); unsigned int mask = 1 << (irq - PCIMT_IRQ_INT2);
...@@ -71,20 +69,20 @@ static struct hw_interrupt_type pciasic_irq_type = { ...@@ -71,20 +69,20 @@ static struct hw_interrupt_type pciasic_irq_type = {
* hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug * hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug
* button interrupts. Later ... * button interrupts. Later ...
*/ */
void pciasic_hwint0(struct pt_regs *regs) static void pciasic_hwint0(struct pt_regs *regs)
{ {
panic("Received int0 but no handler yet ..."); panic("Received int0 but no handler yet ...");
} }
/* This interrupt was used for the com1 console on the first prototypes. */ /* This interrupt was used for the com1 console on the first prototypes. */
void pciasic_hwint2(struct pt_regs *regs) static void pciasic_hwint2(struct pt_regs *regs)
{ {
/* I think this shouldn't happen on production machines. */ /* I think this shouldn't happen on production machines. */
panic("hwint2 and no handler yet"); panic("hwint2 and no handler yet");
} }
/* hwint5 is the r4k count / compare interrupt */ /* hwint5 is the r4k count / compare interrupt */
void pciasic_hwint5(struct pt_regs *regs) static void pciasic_hwint5(struct pt_regs *regs)
{ {
panic("hwint5 and no handler yet"); panic("hwint5 and no handler yet");
} }
...@@ -105,7 +103,7 @@ static unsigned int ls1bit8(unsigned int x) ...@@ -105,7 +103,7 @@ static unsigned int ls1bit8(unsigned int x)
* *
* The EISA_INT bit in CSITPEND is high active, all others are low active. * The EISA_INT bit in CSITPEND is high active, all others are low active.
*/ */
void pciasic_hwint1(struct pt_regs *regs) static void pciasic_hwint1(struct pt_regs *regs)
{ {
u8 pend = *(volatile char *)PCIMT_CSITPEND; u8 pend = *(volatile char *)PCIMT_CSITPEND;
unsigned long flags; unsigned long flags;
...@@ -135,7 +133,7 @@ void pciasic_hwint1(struct pt_regs *regs) ...@@ -135,7 +133,7 @@ void pciasic_hwint1(struct pt_regs *regs)
/* /*
* hwint 3 should deal with the PCI A - D interrupts, * hwint 3 should deal with the PCI A - D interrupts,
*/ */
void pciasic_hwint3(struct pt_regs *regs) static void pciasic_hwint3(struct pt_regs *regs)
{ {
u8 pend = *(volatile char *)PCIMT_CSITPEND; u8 pend = *(volatile char *)PCIMT_CSITPEND;
int irq; int irq;
...@@ -150,13 +148,34 @@ void pciasic_hwint3(struct pt_regs *regs) ...@@ -150,13 +148,34 @@ void pciasic_hwint3(struct pt_regs *regs)
/* /*
* hwint 4 is used for only the onboard PCnet 32. * hwint 4 is used for only the onboard PCnet 32.
*/ */
void pciasic_hwint4(struct pt_regs *regs) static void pciasic_hwint4(struct pt_regs *regs)
{ {
clear_c0_status(IE_IRQ4); clear_c0_status(IE_IRQ4);
do_IRQ(PCIMT_IRQ_ETHERNET, regs); do_IRQ(PCIMT_IRQ_ETHERNET, regs);
set_c0_status(IE_IRQ4); set_c0_status(IE_IRQ4);
} }
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending = read_c0_status() & read_c0_cause();
static unsigned char led_cache;
*(volatile unsigned char *) PCIMT_CSLED = ++led_cache;
if (pending & 0x0800)
pciasic_hwint1(regs);
else if (pending & 0x4000)
pciasic_hwint4(regs);
else if (pending & 0x2000)
pciasic_hwint3(regs);
else if (pending & 0x1000)
pciasic_hwint2(regs);
else if (pending & 0x8000)
pciasic_hwint5(regs);
else if (pending & 0x0400)
pciasic_hwint0(regs);
}
void __init init_pciasic(void) void __init init_pciasic(void)
{ {
unsigned long flags; unsigned long flags;
...@@ -176,8 +195,6 @@ void __init arch_init_irq(void) ...@@ -176,8 +195,6 @@ void __init arch_init_irq(void)
{ {
int i; int i;
set_except_vector(0, sni_rm200_pci_handle_int);
init_i8259_irqs(); /* Integrated i8259 */ init_i8259_irqs(); /* Integrated i8259 */
init_pciasic(); init_pciasic();
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
# unless it's something special (ie not a .c file). # unless it's something special (ie not a .c file).
# #
obj-y += tx4927_prom.o tx4927_setup.o tx4927_irq.o tx4927_irq_handler.o obj-y += tx4927_prom.o tx4927_setup.o tx4927_irq.o
obj-$(CONFIG_TOSHIBA_FPCIB0) += smsc_fdc37m81x.o obj-$(CONFIG_TOSHIBA_FPCIB0) += smsc_fdc37m81x.o
obj-$(CONFIG_KGDB) += tx4927_dbgio.o obj-$(CONFIG_KGDB) += tx4927_dbgio.o
This diff is collapsed.
This diff is collapsed.
...@@ -6,6 +6,6 @@ ...@@ -6,6 +6,6 @@
# unless it's something special (ie not a .c file). # unless it's something special (ie not a .c file).
# #
obj-y += prom.o setup.o irq.o irq_handler.o rtc_rx5c348.o obj-y += prom.o setup.o irq.o rtc_rx5c348.o
obj-$(CONFIG_KGDB) += dbgio.o obj-$(CONFIG_KGDB) += dbgio.o
...@@ -392,11 +392,8 @@ tx4938_irq_pic_end(unsigned int irq) ...@@ -392,11 +392,8 @@ tx4938_irq_pic_end(unsigned int irq)
void __init void __init
tx4938_irq_init(void) tx4938_irq_init(void)
{ {
extern asmlinkage void tx4938_irq_handler(void);
tx4938_irq_cp0_init(); tx4938_irq_cp0_init();
tx4938_irq_pic_init(); tx4938_irq_pic_init();
set_except_vector(0, tx4938_irq_handler);
return; return;
} }
...@@ -422,3 +419,21 @@ tx4938_irq_nested(void) ...@@ -422,3 +419,21 @@ tx4938_irq_nested(void)
wbflush(); wbflush();
return (sw_irq); return (sw_irq);
} }
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending = read_c0_cause() & read_c0_status();
if (pending & STATUSF_IP7)
do_IRQ(TX4938_IRQ_CPU_TIMER, regs);
else if (pending & STATUSF_IP2) {
int irq = tx4938_irq_nested();
if (irq)
do_IRQ(irq, regs);
else
spurious_interrupt(regs);
} else if (pending & STATUSF_IP1)
do_IRQ(TX4938_IRQ_USER1, regs);
else if (pending & STATUSF_IP0)
do_IRQ(TX4938_IRQ_USER0, regs);
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment