summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeo Dagum <dagum@engr.sgi.com>2000-03-30 23:31:01 +0000
committerLeo Dagum <dagum@engr.sgi.com>2000-03-30 23:31:01 +0000
commitd95077b6fecee2fdc3936472bd747802c045359e (patch)
tree939c287cfafc9389bc13a9786b2df961bc82dd8c
parent4c0cda9278fa9ebc9b214e34cd28adce25e6c683 (diff)
Interrupts need to start at bit 7 in INT_PEND0 registers because bits [0..6]
are taken for various other sundry tasks. Also added QLOGICFC_SLOT5 kludge to bridge_startup(). I'll generalize this later, for now it means you have to have your isp2100 card in slot 5.
-rw-r--r--arch/mips64/sgi-ip27/ip27-irq.c57
1 files changed, 44 insertions, 13 deletions
diff --git a/arch/mips64/sgi-ip27/ip27-irq.c b/arch/mips64/sgi-ip27/ip27-irq.c
index 7d136db6f..f857773ed 100644
--- a/arch/mips64/sgi-ip27/ip27-irq.c
+++ b/arch/mips64/sgi-ip27/ip27-irq.c
@@ -1,4 +1,4 @@
-/* $Id: ip27-irq.c,v 1.8 2000/03/07 15:45:29 ralf Exp $
+/* $Id: ip27-irq.c,v 1.9 2000/03/14 01:39:27 ralf Exp $
*
* ip27-irq.c: Highlevel interrupt handling for IP27 architecture.
*
@@ -59,6 +59,13 @@ unsigned int local_bh_count[NR_CPUS];
unsigned int local_irq_count[NR_CPUS];
unsigned long spurious_count = 0;
+/*
+ * we need to map irq's up to at least bit 7 of the INT_MASK0_A register
+ * since bits 0-6 are pre-allocated for other purposes
+ */
+#define IRQ_TO_SWLEVEL(i) i + 7
+#define SWLEVEL_TO_IRQ(s) s - 7
+
void disable_irq(unsigned int irq_nr)
{
panic("disable_irq() called ...");
@@ -148,20 +155,24 @@ static int ms1bit(unsigned long x)
/* For now ... */
void ip27_do_irq(struct pt_regs *regs)
{
- int irq;
+ int irq, swlevel;
hubreg_t pend0, mask0;
/* copied from Irix intpend0() */
while (((pend0 = LOCAL_HUB_L(PI_INT_PEND0)) &
(mask0 = LOCAL_HUB_L(PI_INT_MASK0_A))) != 0) {
do {
- irq = ms1bit(pend0);
- LOCAL_HUB_S(PI_INT_MASK0_A, mask0 & ~(1 << irq));
- LOCAL_HUB_S(PI_INT_PEND_MOD, irq);
+ swlevel = ms1bit(pend0);
+ LOCAL_HUB_S(PI_INT_MASK0_A, mask0 & ~(1 << swlevel));
+ LOCAL_HUB_S(PI_INT_PEND_MOD, swlevel);
LOCAL_HUB_L(PI_INT_MASK0_A); /* Flush */
+ /* "map" swlevel to irq */
+ irq = SWLEVEL_TO_IRQ(swlevel);
do_IRQ(irq, regs);
+ /* reset INT_MASK0 register */
LOCAL_HUB_S(PI_INT_MASK0_A, mask0);
- pend0 ^= 1ULL << irq;
+ /* clear bit in pend0 */
+ pend0 ^= 1ULL << swlevel;
} while (pend0);
}
}
@@ -172,11 +183,12 @@ static unsigned int bridge_startup(unsigned int irq)
{
bridge_t *bridge = (bridge_t *) 0x9200000008000000;
bridgereg_t br;
- int pin;
+ int pin, swlevel;
/* FIIIIIXME ... Temporary kludge. This knows how interrupts are
setup in _my_ Origin. */
switch (irq) {
+ case QLOGICFC_SLOT5: pin = 5; break;
case IOC3_SERIAL_INT: pin = 3; break;
case IOC3_ETH_INT: pin = 2; break;
case SCSI1_INT: pin = 1; break;
@@ -184,13 +196,18 @@ static unsigned int bridge_startup(unsigned int irq)
default: panic("bridge_startup: whoops?");
}
+ /*
+ * "map" irq to a swlevel greater than 6 since the first 6 bits
+ * of INT_PEND0 are taken
+ */
+ swlevel = IRQ_TO_SWLEVEL(irq);
br = LOCAL_HUB_L(PI_INT_MASK0_A);
- LOCAL_HUB_S(PI_INT_MASK0_A, br | (1 << irq));
+ LOCAL_HUB_S(PI_INT_MASK0_A, br | (1 << swlevel));
LOCAL_HUB_L(PI_INT_MASK0_A); /* Flush */
- bridge->b_int_addr[pin].addr = 0x20000 | irq;
+ bridge->b_int_addr[pin].addr = 0x20000 | swlevel;
bridge->b_int_enable |= (1 << pin);
- if (irq < 2) {
+ if (irq < 2 || irq==5) {
bridgereg_t device;
#if 0
/*
@@ -208,22 +225,30 @@ static unsigned int bridge_startup(unsigned int irq)
device = bridge->b_device[irq].reg;
device |= BRIDGE_DEV_SWAP_DIR;
bridge->b_device[irq].reg = device;
+ /*
+ * Associate interrupt pin with device
+ * XXX This only works if b_int_device is initialized to 0!
+ */
+ device = bridge->b_int_device;
+ device |= (pin << (irq*3));
+ bridge->b_int_device = device;
}
bridge->b_widget.w_tflush; /* Flush */
return 0; /* Never anything pending. */
}
-/* Startup one of the (PCI ...) IRQs routes over a bridge. */
+/* Shutdown one of the (PCI ...) IRQs routes over a bridge. */
static unsigned int bridge_shutdown(unsigned int irq)
{
bridge_t *bridge = (bridge_t *) 0x9200000008000000;
bridgereg_t br;
- int pin;
+ int pin, swlevel;
/* FIIIIIXME ... Temporary kludge. This knows how interrupts are
setup in _my_ Origin. */
switch (irq) {
+ case QLOGICFC_SLOT5: pin = 5; break;
case IOC3_SERIAL_INT: pin = 3; break;
case IOC3_ETH_INT: pin = 2; break;
case SCSI1_INT: pin = 1; break;
@@ -231,8 +256,14 @@ static unsigned int bridge_shutdown(unsigned int irq)
default: panic("bridge_startup: whoops?");
}
+ /*
+ * map irq to a swlevel greater than 6 since the first 6 bits
+ * of INT_PEND0 are taken
+ */
+ swlevel = IRQ_TO_SWLEVEL(irq);
+ br = LOCAL_HUB_L(PI_INT_MASK0_A);
br = LOCAL_HUB_L(PI_INT_MASK0_A);
- LOCAL_HUB_S(PI_INT_MASK0_A, br & ~(1 << irq));
+ LOCAL_HUB_S(PI_INT_MASK0_A, br & ~(1 << swlevel));
LOCAL_HUB_L(PI_INT_MASK0_A); /* Flush */
bridge->b_int_enable &= ~(1 << pin);