summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/mips64/kernel/smp.c5
-rw-r--r--arch/mips64/sgi-ip27/ip27-irq.c119
-rw-r--r--include/asm-mips64/irq.h19
3 files changed, 106 insertions, 37 deletions
diff --git a/arch/mips64/kernel/smp.c b/arch/mips64/kernel/smp.c
index 94673e078..86b338c05 100644
--- a/arch/mips64/kernel/smp.c
+++ b/arch/mips64/kernel/smp.c
@@ -12,6 +12,7 @@
#include <asm/hardirq.h>
#include <asm/softirq.h>
#include <asm/mmu_context.h>
+#include <asm/irq.h>
#ifdef CONFIG_SGI_IP27
@@ -24,8 +25,6 @@
#define DORESCHED 0xab
#define DOCALL 0xbc
-#define IRQ_TO_SWLEVEL(i) i + 7 /* Delete this from here */
-
static void sendintr(int destid, unsigned char status)
{
int irq;
@@ -44,7 +43,7 @@ static void sendintr(int destid, unsigned char status)
* with the CPU we want to send the interrupt to.
*/
REMOTE_HUB_SEND_INTR(COMPACT_TO_NASID_NODEID(cputocnode(destid)),
- IRQ_TO_SWLEVEL(irq));
+ FAST_IRQ_TO_LEVEL(irq));
#else
<< Bomb! Must redefine this for more than 2 CPUS. >>
#endif
diff --git a/arch/mips64/sgi-ip27/ip27-irq.c b/arch/mips64/sgi-ip27/ip27-irq.c
index a9a7b7153..446e3df41 100644
--- a/arch/mips64/sgi-ip27/ip27-irq.c
+++ b/arch/mips64/sgi-ip27/ip27-irq.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 1999 - 2001 Kanoj Sarcar
*/
#include <linux/config.h>
#include <linux/init.h>
@@ -25,6 +26,7 @@
#include <asm/io.h>
#include <asm/mipsregs.h>
#include <asm/system.h>
+#include <asm/irq.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
@@ -67,11 +69,11 @@ int intr_disconnect_level(int cpu, int bit);
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.
+ * There is a single intpend register per node, and we want to have
+ * distinct levels for intercpu intrs for both cpus A and B on a node.
*/
-#define IRQ_TO_SWLEVEL(cpu, i) i + 7
-#define SWLEVEL_TO_IRQ(cpu, s) s - 7
+int node_level_to_irq[MAX_COMPACT_NODES][PERNODE_LEVELS];
+
/*
* use these macros to get the encoded nasid and widget id
* from the irq value
@@ -82,6 +84,41 @@ unsigned long spurious_count = 0;
#define WID_FROM_PCI_IRQ(i) bus_to_wid[IRQ_TO_BUS(i)]
#define SLOT_FROM_PCI_IRQ(i) irq_to_slot[i]
+static inline int alloc_level(cpuid_t cpunum, int irq)
+{
+ cnodeid_t nodenum = CPUID_TO_COMPACT_NODEID(cpunum);
+ int j = LEAST_LEVEL + 3; /* resched & crosscall entries taken */
+
+ while (++j < PERNODE_LEVELS) {
+ if (node_level_to_irq[nodenum][j] == -1) {
+ node_level_to_irq[nodenum][j] = irq;
+ return(j);
+ }
+ }
+ printk("Cpu %ld flooded with devices\n", cpunum);
+ while(1);
+ return(-1);
+}
+
+static inline int find_level(cpuid_t *cpunum, int irq)
+{
+ int j;
+ cnodeid_t nodenum = INVALID_CNODEID;
+
+ while (++nodenum < MAX_COMPACT_NODES) {
+ j = LEAST_LEVEL + 3; /* resched & crosscall entries taken */
+ while (++j < PERNODE_LEVELS)
+ if (node_level_to_irq[nodenum][j] == irq) {
+ *cpunum = 0; /* XXX Fixme */
+ return(j);
+ }
+ }
+ printk("Could not identify cpu/level for irq %d\n", irq);
+ while(1);
+ return(-1);
+}
+
+
void disable_irq(unsigned int irq_nr)
{
panic("disable_irq() called ...");
@@ -196,7 +233,7 @@ void ip27_do_irq(struct pt_regs *regs)
swlevel = ms1bit(pend0);
LOCAL_HUB_CLR_INTR(swlevel);
/* "map" swlevel to irq */
- irq = SWLEVEL_TO_IRQ(thiscpu, swlevel);
+ irq = LEVEL_TO_IRQ(thiscpu, swlevel);
do_IRQ(thiscpu, irq, regs);
/* clear bit in pend0 */
pend0 ^= 1ULL << swlevel;
@@ -227,7 +264,7 @@ static unsigned int bridge_startup(unsigned int irq)
* "map" irq to a swlevel greater than 6 since the first 6 bits
* of INT_PEND0 are taken
*/
- swlevel = IRQ_TO_SWLEVEL(cpu, irq);
+ swlevel = alloc_level(cpu, irq);
intr_connect_level(cpu, swlevel);
bridge->b_int_addr[pin].addr = (0x20000 | swlevel | (master << 8));
@@ -254,6 +291,7 @@ static unsigned int bridge_shutdown(unsigned int irq)
{
bridge_t *bridge;
int pin, swlevel;
+ cpuid_t cpu;
bridge = (bridge_t *) NODE_SWIN_BASE(NASID_FROM_PCI_IRQ(irq),
WID_FROM_PCI_IRQ(irq));
@@ -264,8 +302,9 @@ static unsigned int bridge_shutdown(unsigned int irq)
* map irq to a swlevel greater than 6 since the first 6 bits
* of INT_PEND0 are taken
*/
- swlevel = IRQ_TO_SWLEVEL(cpu, irq);
- intr_disconnect_level(smp_processor_id(), swlevel);
+ swlevel = find_level(&cpu, irq);
+ intr_disconnect_level(cpu, swlevel);
+ LEVEL_TO_IRQ(cpu, swlevel) = -1;
bridge->b_int_enable &= ~(1 << pin);
bridge->b_widget.w_tflush; /* Flush */
@@ -423,7 +462,6 @@ static void show(char * str)
printk(" ]\nStack dumps:");
for(i = 0; i < smp_num_cpus; i++) {
- unsigned long esp;
if (i == cpu)
continue;
printk("\nCPU %d:",i);
@@ -661,37 +699,50 @@ void install_cpuintr(int cpu)
#ifdef CONFIG_SMP
#if (CPUS_PER_NODE == 2)
static int done = 0;
- int irq;
/*
* This is a hack till we have a pernode irqlist. Currently,
* just have the master cpu set up the handlers for the per
* cpu irqs.
*/
+ if (done == 0) {
+ int j;
+
+ if (request_irq(CPU_RESCHED_A_IRQ, handle_resched_intr,
+ 0, "resched", 0))
+ panic("intercpu intr unconnectible\n");
+ if (request_irq(CPU_RESCHED_B_IRQ, handle_resched_intr,
+ 0, "resched", 0))
+ panic("intercpu intr unconnectible\n");
+ if (request_irq(CPU_CALL_A_IRQ, smp_call_function_interrupt,
+ 0, "callfunc", 0))
+ panic("intercpu intr unconnectible\n");
+ if (request_irq(CPU_CALL_B_IRQ, smp_call_function_interrupt,
+ 0, "callfunc", 0))
+ panic("intercpu intr unconnectible\n");
+
+ for (j = 0; j < PERNODE_LEVELS; j++)
+ LEVEL_TO_IRQ(0, j) = -1;
+ LEVEL_TO_IRQ(0, FAST_IRQ_TO_LEVEL(CPU_RESCHED_A_IRQ)) =
+ CPU_RESCHED_A_IRQ;
+ LEVEL_TO_IRQ(0, FAST_IRQ_TO_LEVEL(CPU_RESCHED_B_IRQ)) =
+ CPU_RESCHED_B_IRQ;
+ LEVEL_TO_IRQ(0, FAST_IRQ_TO_LEVEL(CPU_CALL_A_IRQ)) =
+ CPU_CALL_A_IRQ;
+ LEVEL_TO_IRQ(0, FAST_IRQ_TO_LEVEL(CPU_CALL_B_IRQ)) =
+ CPU_CALL_B_IRQ;
+ for (j = 1; j < MAX_COMPACT_NODES; j++)
+ memcpy(&node_level_to_irq[j][0],
+ &node_level_to_irq[0][0],
+ sizeof(node_level_to_irq[0][0])*PERNODE_LEVELS);
+
+ done = 1;
+ }
- irq = CPU_RESCHED_A_IRQ + cputoslice(cpu);
- intr_connect_level(cpu, IRQ_TO_SWLEVEL(cpu, irq));
- if (done == 0)
- if (request_irq(irq, handle_resched_intr, 0, "resched", 0))
- panic("intercpu intr unconnectible\n");
- irq = CPU_CALL_A_IRQ + cputoslice(cpu);
- intr_connect_level(cpu, IRQ_TO_SWLEVEL(cpu, irq));
- if (done == 0)
- if (request_irq(irq, smp_call_function_interrupt, 0,
- "callfunc", 0))
- panic("intercpu intr unconnectible\n");
- /* HACK STARTS */
- if (done)
- return;
- irq = CPU_RESCHED_A_IRQ + cputoslice(cpu) + 1;
- if (request_irq(irq, handle_resched_intr, 0, "resched", 0))
- panic("intercpu intr unconnectible\n");
- irq = CPU_CALL_A_IRQ + cputoslice(cpu) + 1;
- if (request_irq(irq, smp_call_function_interrupt, 0,
- "callfunc", 0))
- panic("intercpu intr unconnectible\n");
- done = 1;
- /* HACK ENDS */
+ intr_connect_level(cpu, FAST_IRQ_TO_LEVEL(CPU_RESCHED_A_IRQ +
+ cputoslice(cpu)));
+ intr_connect_level(cpu, FAST_IRQ_TO_LEVEL(CPU_CALL_A_IRQ +
+ cputoslice(cpu)));
#else /* CPUS_PER_NODE */
#error Must redefine this for more than 2 CPUS.
#endif /* CPUS_PER_NODE */
@@ -700,7 +751,9 @@ void install_cpuintr(int cpu)
void install_tlbintr(int cpu)
{
+#if 0
int intr_bit = N_INTPEND_BITS + TLB_INTR_A + cputoslice(cpu);
intr_connect_level(cpu, intr_bit);
+#endif
}
diff --git a/include/asm-mips64/irq.h b/include/asm-mips64/irq.h
index 719667e0f..b1db38fa3 100644
--- a/include/asm-mips64/irq.h
+++ b/include/asm-mips64/irq.h
@@ -6,15 +6,32 @@
* Copyright (C) 1994 by Waldorf GMBH, written by Ralf Baechle
* Copyright (C) 1995, 96, 97, 98, 1999, 2000 by Ralf Baechle
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2001 Kanoj Sarcar
*/
#ifndef _ASM_IRQ_H
#define _ASM_IRQ_H
#include <linux/config.h>
+#include <asm/sn/arch.h>
#define NR_IRQS 256
-#define TIMER_IRQ 0
+/*
+ * Number of levels in INT_PEND0. Can be set to 128 if we also
+ * consider INT_PEND1.
+ */
+#define PERNODE_LEVELS 64
+
+extern int node_level_to_irq[MAX_COMPACT_NODES][PERNODE_LEVELS];
+
+/*
+ * 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 LEAST_LEVEL 7
+#define FAST_IRQ_TO_LEVEL(i) ((i) + LEAST_LEVEL)
+#define LEVEL_TO_IRQ(c, l) \
+ (node_level_to_irq[CPUID_TO_COMPACT_NODEID(c)][(l)])
#ifdef CONFIG_I8259
static inline int irq_cannonicalize(int irq)