diff options
-rw-r--r-- | arch/mips64/kernel/smp.c | 5 | ||||
-rw-r--r-- | arch/mips64/sgi-ip27/ip27-irq.c | 119 | ||||
-rw-r--r-- | include/asm-mips64/irq.h | 19 |
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) |