patch-2.3.99-pre9 linux/arch/mips64/sgi-ip27/ip27-irq.c
Next file: linux/arch/mips64/sgi-ip27/ip27-klconfig.c
Previous file: linux/arch/mips64/sgi-ip27/ip27-irq-glue.S
Back to the patch index
Back to the overall index
- Lines: 733
- Date:
Mon May 15 12:10:26 2000
- Orig file:
v2.3.99-pre8/linux/arch/mips64/sgi-ip27/ip27-irq.c
- Orig date:
Thu Mar 2 14:36:22 2000
diff -u --recursive --new-file v2.3.99-pre8/linux/arch/mips64/sgi-ip27/ip27-irq.c linux/arch/mips64/sgi-ip27/ip27-irq.c
@@ -1,14 +1,14 @@
-/* $Id: ip27-irq.c,v 1.6 2000/02/10 05:58:56 dagum 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.
*
* Copyright (C) 1999 Ralf Baechle (ralf@gnu.org)
* Copyright (C) 1999 Silicon Graphics, Inc.
*/
+#include <linux/config.h>
#include <linux/init.h>
#include <linux/errno.h>
-#include <linux/kernel_stat.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/types.h>
@@ -17,8 +17,9 @@
#include <linux/timex.h>
#include <linux/malloc.h>
#include <linux/random.h>
-#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/kernel_stat.h>
+#include <linux/delay.h>
#include <asm/bitops.h>
#include <asm/bootinfo.h>
@@ -33,14 +34,58 @@
#include <asm/sn/sn0/hub.h>
#include <asm/sn/sn0/ip27.h>
#include <asm/sn/arch.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/intr_public.h>
+
+#undef DEBUG_IRQ
+#ifdef DEBUG_IRQ
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+
+/*
+ * Linux has a controller-independent x86 interrupt architecture.
+ * every controller has a 'controller-template', that is used
+ * by the main code to do the right thing. Each driver-visible
+ * interrupt source is transparently wired to the apropriate
+ * controller. Thus drivers need not be aware of the
+ * interrupt-controller.
+ *
+ * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
+ * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
+ * (IO-APICs assumed to be messaging to Pentium local-APICs)
+ *
+ * the code is designed to be easily extended with new/different
+ * interrupt controllers, without having to do assembly magic.
+ */
+
+irq_cpustat_t irq_stat [NR_CPUS];
extern asmlinkage void ip27_irq(void);
int (*irq_cannonicalize)(int irq);
+int intr_connect_level(cpuid_t cpu, int bit);
+int intr_disconnect_level(cpuid_t cpu, int bit);
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
+/*
+ * use these macros to get the encoded nasid, widget id, and real irq
+ * from the irq value
+ */
+#define NASID_FROM_IRQ(i) ((i >> 16)&(0xff))
+#define WID_FROM_IRQ(i) ((i >> 8)&(0xff))
+#define IRQ_FROM_IRQ(i) ((i)&(0xff))
+
void disable_irq(unsigned int irq_nr)
{
panic("disable_irq() called ...");
@@ -87,7 +132,7 @@
int do_random, cpu;
cpu = smp_processor_id();
- irq_enter(cpu);
+ irq_enter(cpu, irq);
kstat.irqs[cpu][irq]++;
action = *(irq + irq_action);
@@ -105,7 +150,7 @@
add_interrupt_randomness(irq);
__cli();
}
- irq_exit(cpu);
+ irq_exit(cpu, irq);
/* unmasking and bottom half handling is done magically for us. */
}
@@ -130,20 +175,26 @@
/* For now ... */
void ip27_do_irq(struct pt_regs *regs)
{
- int irq;
+ int irq, swlevel;
hubreg_t pend0, mask0;
+ int pi_int_mask0 = ((cputoslice(smp_processor_id()) == 0) ?
+ PI_INT_MASK0_A : PI_INT_MASK0_B);
/* copied from Irix intpend0() */
while (((pend0 = LOCAL_HUB_L(PI_INT_PEND0)) &
- (mask0 = LOCAL_HUB_L(PI_INT_MASK0_A))) != 0) {
+ (mask0 = LOCAL_HUB_L(pi_int_mask0))) != 0) {
+ pend0 &= mask0;
do {
- irq = ms1bit(pend0);
- LOCAL_HUB_S(PI_INT_MASK0_A, mask0 & ~(1 << irq));
- LOCAL_HUB_S(PI_INT_PEND_MOD, irq);
- LOCAL_HUB_L(PI_INT_MASK0_A); /* Flush */
+ swlevel = ms1bit(pend0);
+ LOCAL_HUB_S(pi_int_mask0, mask0 & ~(1 << swlevel));
+ LOCAL_HUB_CLR_INTR(swlevel);
+ /* "map" swlevel to irq */
+ irq = SWLEVEL_TO_IRQ(swlevel);
do_IRQ(irq, regs);
- LOCAL_HUB_S(PI_INT_MASK0_A, mask0);
- pend0 ^= 1ULL << irq;
+ /* reset INT_MASK0 register */
+ LOCAL_HUB_S(pi_int_mask0, mask0);
+ /* clear bit in pend0 */
+ pend0 ^= 1ULL << swlevel;
} while (pend0);
}
}
@@ -152,96 +203,141 @@
/* Startup one of the (PCI ...) IRQs routes over a bridge. */
static unsigned int bridge_startup(unsigned int irq)
{
- bridge_t *bridge = (bridge_t *) 0x9200000008000000;
- bridgereg_t br;
- int pin;
+ bridge_t *bridge;
+ int pin, swlevel;
+ int real_irq = IRQ_FROM_IRQ(irq);
+
+ DBG("bridge_startup(): irq= 0x%x real_irq= %d\n", irq, real_irq);
+ bridge = (bridge_t *) NODE_SWIN_BASE(NASID_FROM_IRQ(irq), WID_FROM_IRQ(irq));
+
+ /* FIIIIIXME ... Temporary kludge. This knows how interrupts are
+ setup in _my_ Origin. */
+
+ if (irq != real_irq) /* pci device interrupt */
+ switch (real_irq) {
+ case IRQ_FROM_IRQ(IOC3_ETH_INT): pin = 2; break;
+ default: pin = real_irq; break;
+ }
+ else
+ switch (real_irq) {
+ case CPU_RESCHED_A_IRQ:
+ case CPU_RESCHED_B_IRQ:
+ case CPU_CALL_A_IRQ:
+ case CPU_CALL_B_IRQ:
+ return 0;
+ default: panic("bridge_startup: whoops? %d\n", irq);
+ }
+
+ /*
+ * "map" irq to a swlevel greater than 6 since the first 6 bits
+ * of INT_PEND0 are taken
+ */
+ swlevel = IRQ_TO_SWLEVEL(real_irq);
+ intr_connect_level(smp_processor_id(), swlevel);
+
+ bridge->b_int_addr[pin].addr = 0x20000 | swlevel;
+ bridge->b_int_enable |= (1 << pin);
+ /* set more stuff in int_enable reg */
+ bridge->b_int_enable |= 0x7ffffe00;
- /* FIIIIIXME ... Temporary kludge. This knows how interrupts are
- setup in _my_ Origin. */
- switch (irq) {
- case IOC3_SERIAL_INT: pin = 3; break;
- case IOC3_ETH_INT: pin = 2; break;
- case SCSI1_INT: pin = 1; break;
- case SCSI0_INT: pin = 0; break;
- default: panic("bridge_startup: whoops?");
- }
-
- br = LOCAL_HUB_L(PI_INT_MASK0_A);
- LOCAL_HUB_S(PI_INT_MASK0_A, br | (1 << irq));
- LOCAL_HUB_L(PI_INT_MASK0_A); /* Flush */
-
- bridge->b_int_addr[pin].addr = 0x20000 | irq;
- bridge->b_int_enable |= (1 << pin);
- if (irq < 2) {
- bridgereg_t device;
+ if (real_irq < 2 || real_irq==4 || real_irq==5) {
+ bridgereg_t device;
#if 0
- /*
- * Allocate enough RRBs on the bridge for the DMAs.
- * Right now allocating 2 RRBs on the normal channel
- * and 2 on the virtual channel for slot 0 on the bus.
- * And same for slot 1, to get ioc3 eth working.
- */
- Not touching b_even_resp /* boot doesn't go far */
- bridge->b_even_resp = 0xdd99cc88; /* boot doesn't go far */
- bridge->b_even_resp = 0xcccc8888; /* breaks eth0 */
- bridge->b_even_resp = 0xcc88; /* breaks eth0 */
+ /*
+ * Allocate enough RRBs on the bridge for the DMAs.
+ * Right now allocating 2 RRBs on the normal channel
+ * and 2 on the virtual channel for slot 0 on the bus.
+ * And same for slot 1, to get ioc3 eth working.
+ */
+ Not touching b_even_resp /* boot doesn't go far */
+ bridge->b_even_resp = 0xdd99cc88; /* boot doesn't go far */
+ bridge->b_even_resp = 0xcccc8888; /* breaks eth0 */
+ bridge->b_even_resp = 0xcc88; /* breaks eth0 */
#endif
- /* Turn on bridge swapping */
- device = bridge->b_device[irq].reg;
- device |= BRIDGE_DEV_SWAP_DIR;
- bridge->b_device[irq].reg = device;
- }
- bridge->b_widget.w_tflush; /* Flush */
+ /* Turn on bridge swapping */
+ device = bridge->b_device[real_irq].reg;
+ device |= BRIDGE_DEV_SWAP_DIR;
+ bridge->b_device[real_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 << (real_irq*3));
+ bridge->b_int_device = device;
+ }
+ bridge->b_widget.w_tflush; /* Flush */
- return 0; /* Never anything pending. */
+ 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;
+ bridge_t *bridge;
+ int pin, swlevel;
+ int real_irq = IRQ_FROM_IRQ(irq);
+ struct irqaction **p;
+
+ bridge = (bridge_t *) NODE_SWIN_BASE(NASID_FROM_IRQ(irq), WID_FROM_IRQ(irq));
+ DBG("bridge_shutdown: irq 0x%x\n", irq);
+ /* FIIIIIXME ... Temporary kludge. This knows how interrupts are
+ setup in _my_ Origin. */
+
+ if (irq != real_irq) /* pci device interrupt */
+ switch (real_irq) {
+ case IRQ_FROM_IRQ(IOC3_ETH_INT): pin = 2; break;
+ default: pin = real_irq; break;
+ }
+ else
+ switch (real_irq) {
+ case CPU_RESCHED_A_IRQ:
+ case CPU_RESCHED_B_IRQ:
+ case CPU_CALL_A_IRQ:
+ case CPU_CALL_B_IRQ:
+ return 0;
+ 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(real_irq);
+ intr_disconnect_level(smp_processor_id(), swlevel);
- /* FIIIIIXME ... Temporary kludge. This knows how interrupts are
- setup in _my_ Origin. */
- switch (irq) {
- case IOC3_SERIAL_INT: pin = 3; break;
- case IOC3_ETH_INT: pin = 2; break;
- case SCSI1_INT: pin = 1; break;
- case SCSI0_INT: pin = 0; break;
- default: panic("bridge_startup: whoops?");
- }
-
- br = LOCAL_HUB_L(PI_INT_MASK0_A);
- LOCAL_HUB_S(PI_INT_MASK0_A, br & ~(1 << irq));
- LOCAL_HUB_L(PI_INT_MASK0_A); /* Flush */
+ bridge->b_int_enable &= ~(1 << pin);
+ bridge->b_widget.w_tflush; /* Flush */
- bridge->b_int_enable &= ~(1 << pin);
- bridge->b_widget.w_tflush; /* Flush */
-
- return 0; /* Never anything pending. */
+ return 0; /* Never anything pending. */
}
static void bridge_init(void)
{
- bridge_t *bridge = (bridge_t *) 0x9200000008000000;
-
- /* Hmm... IRIX sets additional bits in the address which are
- documented as reserved in the bridge docs ... */
- bridge->b_int_mode = 0x0; /* Don't clear ints */
+ bridge_t *bridge;
+ nasid_t nasid;
+ char wid;
+ int bus;
+
+ nasid = get_nasid();
+
+ for (bus=0; bus<num_bridges; bus++) {
+ bridge = (bridge_t *) NODE_SWIN_BASE(bus_to_nid[bus],bus_to_wid[bus]);
+ /* Hmm... IRIX sets additional bits in the address which are
+ documented as reserved in the bridge docs ... */
+ bridge->b_int_mode = 0x0; /* Don't clear ints */
#if 0
- bridge->b_wid_int_upper = 0x000a8000; /* Ints to node 0 */
- bridge->b_wid_int_lower = 0x01000090;
- bridge->b_dir_map = 0xa00000; /* DMA */
+ bridge->b_wid_int_upper = 0x000a8000; /* Ints to node 0 */
+ bridge->b_wid_int_lower = 0x01000090;
+ bridge->b_dir_map = 0xa00000; /* DMA */
#endif /* shouldn't lower= 0x01800090 ??? */
- bridge->b_wid_int_upper = 0x00098000; /* Ints to node 0 */
- bridge->b_wid_int_lower = 0x01800090;
- bridge->b_dir_map = 0x900000; /* DMA */
-
- bridge->b_int_enable = 0;
- bridge->b_widget.w_tflush; /* Flush */
- set_cp0_status(SRB_DEV0 | SRB_DEV1, SRB_DEV0 | SRB_DEV1);
+ bridge->b_wid_int_upper = 0x000a8000; /* Ints to widget A */
+ bridge->b_wid_int_lower = 0x01800090;
+ bridge->b_dir_map = 0xa00000; /* DMA */
+
+ bridge->b_int_enable = 0;
+ bridge->b_widget.w_tflush; /* Flush */
+ }
}
void irq_debug(void)
@@ -254,17 +350,18 @@
printk("PI_INT_MASK0_A = 0x%x\n", LOCAL_HUB_L(PI_INT_MASK0_A));
}
-int setup_irq(int irq, struct irqaction *new)
+int setup_irq(unsigned int irq, struct irqaction *new)
{
int shared = 0;
struct irqaction *old, **p;
unsigned long flags;
+ DBG("setup_irq: 0x%x\n", irq);
if (new->flags & SA_SAMPLE_RANDOM)
rand_initialize_irq(irq);
save_and_cli(flags);
- p = irq_action + irq;
+ p = irq_action + IRQ_FROM_IRQ(irq);
if ((old = *p) != NULL) {
/* Can't share interrupts unless both agree to */
if (!(old->flags & new->flags & SA_SHIRQ)) {
@@ -297,7 +394,8 @@
int retval;
struct irqaction *action;
- if (irq > 9)
+ DBG("request_irq(): irq= 0x%x\n", irq);
+ if (IRQ_FROM_IRQ(irq) > 9)
return -EINVAL;
if (!handler)
return -EINVAL;
@@ -313,7 +411,9 @@
action->next = NULL;
action->dev_id = dev_id;
+ DBG("request_irq(): %s devid= 0x%x\n", devname, dev_id);
retval = setup_irq(irq, action);
+ DBG("request_irq(): retval= %d\n", retval);
if (retval)
kfree(action);
return retval;
@@ -324,11 +424,11 @@
struct irqaction * action, **p;
unsigned long flags;
- if (irq > 9) {
+ if (IRQ_FROM_IRQ(irq) > 9) {
printk("Trying to free IRQ%d\n", irq);
return;
}
- for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) {
+ for (p = IRQ_FROM_IRQ(irq) + irq_action; (action = *p) != NULL; p = &action->next) {
if (action->dev_id != dev_id)
continue;
@@ -347,6 +447,7 @@
/* Useless ISA nonsense. */
unsigned long probe_irq_on (void)
{
+ panic("probe_irq_on called!\n");
return 0;
}
@@ -366,4 +467,313 @@
bridge_init();
set_except_vector(0, ip27_irq);
+}
+
+
+#ifdef CONFIG_SMP
+
+/*
+ * This following are the global intr on off routines, copied almost
+ * entirely from i386 code.
+ */
+
+int global_irq_holder = NO_PROC_ID;
+spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED;
+
+extern void show_stack(unsigned long* esp);
+
+static void show(char * str)
+{
+ int i;
+ int cpu = smp_processor_id();
+
+ printk("\n%s, CPU %d:\n", str, cpu);
+ printk("irq: %d [",irqs_running());
+ for(i=0;i < smp_num_cpus;i++)
+ printk(" %d",local_irq_count(i));
+ printk(" ]\nbh: %d [",spin_is_locked(&global_bh_lock) ? 1 : 0);
+ for(i=0;i < smp_num_cpus;i++)
+ printk(" %d",local_bh_count(i));
+
+ printk(" ]\nStack dumps:");
+ for(i = 0; i < smp_num_cpus; i++) {
+ unsigned long esp;
+ if (i == cpu)
+ continue;
+ printk("\nCPU %d:",i);
+ printk("Code not developed yet\n");
+ /* show_stack(0); */
+ }
+ printk("\nCPU %d:",cpu);
+ printk("Code not developed yet\n");
+ /* show_stack(NULL); */
+ printk("\n");
+}
+
+#define MAXCOUNT 100000000
+#define SYNC_OTHER_CORES(x) udelay(x+1)
+
+static inline void wait_on_irq(int cpu)
+{
+ int count = MAXCOUNT;
+
+ for (;;) {
+
+ /*
+ * Wait until all interrupts are gone. Wait
+ * for bottom half handlers unless we're
+ * already executing in one..
+ */
+ if (!irqs_running())
+ if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock))
+ break;
+
+ /* Duh, we have to loop. Release the lock to avoid deadlocks */
+ spin_unlock(&global_irq_lock);
+
+ for (;;) {
+ if (!--count) {
+ show("wait_on_irq");
+ count = ~0;
+ }
+ __sti();
+ SYNC_OTHER_CORES(cpu);
+ __cli();
+ if (irqs_running())
+ continue;
+ if (spin_is_locked(&global_irq_lock))
+ continue;
+ if (!local_bh_count(cpu) && spin_is_locked(&global_bh_lock))
+ continue;
+ if (spin_trylock(&global_irq_lock))
+ break;
+ }
+ }
+}
+
+void synchronize_irq(void)
+{
+ if (irqs_running()) {
+ /* Stupid approach */
+ cli();
+ sti();
+ }
+}
+
+static inline void get_irqlock(int cpu)
+{
+ if (!spin_trylock(&global_irq_lock)) {
+ /* do we already hold the lock? */
+ if ((unsigned char) cpu == global_irq_holder)
+ return;
+ /* Uhhuh.. Somebody else got it. Wait.. */
+ spin_lock(&global_irq_lock);
+ }
+ /*
+ * We also to make sure that nobody else is running
+ * in an interrupt context.
+ */
+ wait_on_irq(cpu);
+
+ /*
+ * Ok, finally..
+ */
+ global_irq_holder = cpu;
+}
+
+void __global_cli(void)
+{
+ unsigned int flags;
+
+ __save_flags(flags);
+ if (flags & ST0_IE) {
+ int cpu = smp_processor_id();
+ __cli();
+ if (!local_irq_count(cpu))
+ get_irqlock(cpu);
+ }
+}
+
+void __global_sti(void)
+{
+ int cpu = smp_processor_id();
+
+ if (!local_irq_count(cpu))
+ release_irqlock(cpu);
+ __sti();
+}
+
+/*
+ * SMP flags value to restore to:
+ * 0 - global cli
+ * 1 - global sti
+ * 2 - local cli
+ * 3 - local sti
+ */
+unsigned long __global_save_flags(void)
+{
+ int retval;
+ int local_enabled;
+ unsigned long flags;
+ int cpu = smp_processor_id();
+
+ __save_flags(flags);
+ local_enabled = (flags & ST0_IE);
+ /* default to local */
+ retval = 2 + local_enabled;
+
+ /* check for global flags if we're not in an interrupt */
+ if (!local_irq_count(cpu)) {
+ if (local_enabled)
+ retval = 1;
+ if (global_irq_holder == cpu)
+ retval = 0;
+ }
+ return retval;
+}
+
+void __global_restore_flags(unsigned long flags)
+{
+ switch (flags) {
+ case 0:
+ __global_cli();
+ break;
+ case 1:
+ __global_sti();
+ break;
+ case 2:
+ __cli();
+ break;
+ case 3:
+ __sti();
+ break;
+ default:
+ printk("global_restore_flags: %08lx\n", flags);
+ }
+}
+
+#endif /* CONFIG_SMP */
+
+/*
+ * Get values that vary depending on which CPU and bit we're operating on.
+ */
+static hub_intmasks_t *intr_get_ptrs(cpuid_t cpu, int bit, int *new_bit,
+ hubreg_t **intpend_masks, int *ip)
+{
+ hub_intmasks_t *hub_intmasks;
+
+ hub_intmasks = &cpu_data[cpu].p_intmasks;
+ if (bit < N_INTPEND_BITS) {
+ *intpend_masks = hub_intmasks->intpend0_masks;
+ *ip = 0;
+ *new_bit = bit;
+ } else {
+ *intpend_masks = hub_intmasks->intpend1_masks;
+ *ip = 1;
+ *new_bit = bit - N_INTPEND_BITS;
+ }
+ return hub_intmasks;
+}
+
+int intr_connect_level(cpuid_t cpu, int bit)
+{
+ int ip;
+ int slice = cputoslice(cpu);
+ volatile hubreg_t *mask_reg;
+ hubreg_t *intpend_masks;
+ nasid_t nasid = COMPACT_TO_NASID_NODEID(cputocnode(cpu));
+
+ (void)intr_get_ptrs(cpu, bit, &bit, &intpend_masks, &ip);
+
+ /* Make sure it's not already pending when we connect it. */
+ REMOTE_HUB_CLR_INTR(nasid, bit + ip * N_INTPEND_BITS);
+
+ intpend_masks[0] |= (1ULL << (u64)bit);
+
+ if (ip == 0) {
+ mask_reg = REMOTE_HUB_ADDR(nasid, PI_INT_MASK0_A +
+ PI_INT_MASK_OFFSET * slice);
+ } else {
+ mask_reg = REMOTE_HUB_ADDR(nasid, PI_INT_MASK1_A +
+ PI_INT_MASK_OFFSET * slice);
+ }
+ HUB_S(mask_reg, intpend_masks[0]);
+ return(0);
+}
+
+int intr_disconnect_level(cpuid_t cpu, int bit)
+{
+ int ip;
+ int slice = cputoslice(cpu);
+ volatile hubreg_t *mask_reg;
+ hubreg_t *intpend_masks;
+ nasid_t nasid = COMPACT_TO_NASID_NODEID(cputocnode(cpu));
+
+ (void)intr_get_ptrs(cpu, bit, &bit, &intpend_masks, &ip);
+ intpend_masks[0] &= ~(1ULL << (u64)bit);
+ if (ip == 0) {
+ mask_reg = REMOTE_HUB_ADDR(nasid, PI_INT_MASK0_A +
+ PI_INT_MASK_OFFSET * slice);
+ } else {
+ mask_reg = REMOTE_HUB_ADDR(nasid, PI_INT_MASK1_A +
+ PI_INT_MASK_OFFSET * slice);
+ }
+ HUB_S(mask_reg, intpend_masks[0]);
+ return(0);
+}
+
+
+void handle_resched_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ /* Nothing, the return from intr will work for us */
+}
+
+void install_cpuintr(cpuid_t cpu)
+{
+ int irq;
+ extern void smp_call_function_interrupt(void);
+ static int done = 0;
+
+ /*
+ * 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.
+ */
+
+#ifdef CONFIG_SMP
+#if (CPUS_PER_NODE == 2)
+ irq = CPU_RESCHED_A_IRQ + cputoslice(cpu);
+ intr_connect_level(cpu, IRQ_TO_SWLEVEL(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(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 */
+#else /* CPUS_PER_NODE */
+ << Bomb! Must redefine this for more than 2 CPUS. >>
+#endif /* CPUS_PER_NODE */
+#endif /* CONFIG_SMP */
+}
+
+void install_tlbintr(cpuid_t cpu)
+{
+ int intr_bit = N_INTPEND_BITS + TLB_INTR_A + cputoslice(cpu);
+
+ intr_connect_level(cpu, intr_bit);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)