patch-2.4.19 linux-2.4.19/arch/mips64/sgi-ip27/ip27-irq.c
Next file: linux-2.4.19/arch/mips64/sgi-ip27/ip27-pci-dma.c
Previous file: linux-2.4.19/arch/mips64/sgi-ip27/ip27-init.c
Back to the patch index
Back to the overall index
- Lines: 586
- Date:
Fri Aug 2 17:39:43 2002
- Orig file:
linux-2.4.18/arch/mips64/sgi-ip27/ip27-irq.c
- Orig date:
Sun Sep 9 10:43:02 2001
diff -urN linux-2.4.18/arch/mips64/sgi-ip27/ip27-irq.c linux-2.4.19/arch/mips64/sgi-ip27/ip27-irq.c
@@ -19,7 +19,6 @@
#include <linux/smp_lock.h>
#include <linux/kernel_stat.h>
#include <linux/delay.h>
-#include <linux/irq.h>
#include <asm/bitops.h>
#include <asm/bootinfo.h>
@@ -33,10 +32,13 @@
#include <asm/pci/bridge.h>
#include <asm/sn/sn0/hub.h>
#include <asm/sn/sn0/ip27.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/agent.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)
@@ -66,12 +68,12 @@
*/
extern asmlinkage void ip27_irq(void);
+extern void do_IRQ(int irq, struct pt_regs *regs);
+
extern int irq_to_bus[], irq_to_slot[], bus_to_cpu[];
int intr_connect_level(int cpu, int bit);
int intr_disconnect_level(int cpu, int bit);
-unsigned long spurious_count = 0;
-
/*
* 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.
@@ -122,90 +124,20 @@
return(-1);
}
-
-void disable_irq(unsigned int irq_nr)
-{
- panic("disable_irq() called ...");
-}
-
-void enable_irq(unsigned int irq_nr)
-{
- panic("enable_irq() called ...");
-}
-
-/* This is stupid for an Origin which can have thousands of IRQs ... */
-static struct irqaction *irq_action[NR_IRQS];
-
-int get_irq_list(char *buf)
-{
- int i, len = 0;
- struct irqaction * action;
-
- for (i = 0 ; i < NR_IRQS ; i++) {
- action = irq_action[i];
- if (!action)
- continue;
- len += sprintf(buf+len, "%2d: %8d %c %s", i, kstat.irqs[0][i],
- (action->flags & SA_INTERRUPT) ? '+' : ' ',
- action->name);
- for (action=action->next; action; action = action->next) {
- len += sprintf(buf+len, ",%s %s",
- (action->flags & SA_INTERRUPT)
- ? " +" : "",
- action->name);
- }
- len += sprintf(buf+len, "\n");
- }
- return len;
-}
-
-/*
- * do_IRQ handles all normal device IRQ's (the special SMP cross-CPU interrupts
- * have their own specific handlers).
- */
-static void do_IRQ(cpuid_t thiscpu, int irq, struct pt_regs * regs)
-{
- struct irqaction *action;
- int do_random;
-
- irq_enter(thiscpu, irq);
- kstat.irqs[thiscpu][irq]++;
-
- action = *(irq + irq_action);
- if (action) {
- if (!(action->flags & SA_INTERRUPT))
- __sti();
- do_random = 0;
- do {
- do_random |= action->flags;
- action->handler(irq, action->dev_id, regs);
- action = action->next;
- } while (action);
- if (do_random & SA_SAMPLE_RANDOM)
- add_interrupt_randomness(irq);
- __cli();
- }
- irq_exit(thiscpu, irq);
-
- if (softirq_pending(thiscpu))
- do_softirq();
-}
-
/*
* Find first bit set
*/
static int ms1bit(unsigned long x)
{
- int b;
+ int b = 0, s;
- if (x >> 32) b = 32, x >>= 32;
- else b = 0;
- if (x >> 16) b += 16, x >>= 16;
- if (x >> 8) b += 8, x >>= 8;
- if (x >> 4) b += 4, x >>= 4;
- if (x >> 2) b += 2, x >>= 2;
+ s = 16; if (x >> 16 == 0) s = 0; b += s; x >>= s;
+ s = 8; if (x >> 8 == 0) s = 0; b += s; x >>= s;
+ s = 4; if (x >> 4 == 0) s = 0; b += s; x >>= s;
+ s = 2; if (x >> 2 == 0) s = 0; b += s; x >>= s;
+ s = 1; if (x >> 1 == 0) s = 0; b += s;
- return b + (int) (x >> 1);
+ return b;
}
/*
@@ -239,7 +171,7 @@
LOCAL_HUB_CLR_INTR(swlevel);
/* "map" swlevel to irq */
irq = LEVEL_TO_IRQ(thiscpu, swlevel);
- do_IRQ(thiscpu, irq, regs);
+ do_IRQ(irq, regs);
/* clear bit in pend0 */
pend0 ^= 1ULL << swlevel;
} while(pend0);
@@ -252,7 +184,7 @@
/* Startup one of the (PCI ...) IRQs routes over a bridge. */
-static unsigned int bridge_startup(unsigned int irq)
+static unsigned int startup_bridge_irq(unsigned int irq)
{
bridgereg_t device;
bridge_t *bridge;
@@ -260,6 +192,9 @@
cpuid_t cpu;
nasid_t master = NASID_FROM_PCI_IRQ(irq);
+ if (irq < BASE_PCI_IRQ)
+ return 0;
+
bridge = (bridge_t *) NODE_SWIN_BASE(master, WID_FROM_PCI_IRQ(irq));
pin = SLOT_FROM_PCI_IRQ(irq);
cpu = IRQ_TO_CPU(irq);
@@ -292,12 +227,15 @@
}
/* Shutdown one of the (PCI ...) IRQs routes over a bridge. */
-static unsigned int bridge_shutdown(unsigned int irq)
+static unsigned int shutdown_bridge_irq(unsigned int irq)
{
bridge_t *bridge;
int pin, swlevel;
cpuid_t cpu;
+ if (irq < BASE_PCI_IRQ)
+ return 0;
+
bridge = (bridge_t *) NODE_SWIN_BASE(NASID_FROM_PCI_IRQ(irq),
WID_FROM_PCI_IRQ(irq));
DBG("bridge_shutdown: irq 0x%x\n", irq);
@@ -317,312 +255,64 @@
return 0; /* Never anything pending. */
}
-void irq_debug(void)
+static inline void enable_bridge_irq(unsigned int irq)
{
- bridge_t *bridge = (bridge_t *) 0x9200000008000000;
-
- printk("bridge->b_int_status = 0x%x\n", bridge->b_int_status);
- printk("bridge->b_int_enable = 0x%x\n", bridge->b_int_enable);
- printk("PI_INT_PEND0 = 0x%lx\n", LOCAL_HUB_L(PI_INT_PEND0));
- printk("PI_INT_MASK0_A = 0x%lx\n", LOCAL_HUB_L(PI_INT_MASK0_A));
+ /* All the braindamage happens magically for us in ip27_do_irq */
}
-int setup_irq(unsigned int irq, struct irqaction *new)
+static void disable_bridge_irq(unsigned int irq)
{
- int shared = 0;
- struct irqaction *old, **p;
- unsigned long flags;
-
- DBG("setup_irq: 0x%x\n", irq);
- if (irq >= NR_IRQS) {
- printk("IRQ array overflow %d\n", irq);
- while(1);
- }
- if (new->flags & SA_SAMPLE_RANDOM)
- rand_initialize_irq(irq);
-
- save_and_cli(flags);
- p = irq_action + irq;
- if ((old = *p) != NULL) {
- /* Can't share interrupts unless both agree to */
- if (!(old->flags & new->flags & SA_SHIRQ)) {
- restore_flags(flags);
- return -EBUSY;
- }
-
- /* Add new interrupt at end of irq queue */
- do {
- p = &old->next;
- old = *p;
- } while (old);
- shared = 1;
- }
-
- *p = new;
-
- if ((!shared) && (irq >= BASE_PCI_IRQ)) {
- bridge_startup(irq);
- }
- restore_flags(flags);
-
- return 0;
+ /* All the braindamage happens magically for us in ip27_do_irq */
}
-int request_irq(unsigned int irq,
- void (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags, const char * devname, void *dev_id)
+static void mask_and_ack_bridge_irq(unsigned int irq)
{
- int retval;
- struct irqaction *action;
-
- DBG("request_irq(): irq= 0x%x\n", irq);
- if (!handler)
- return -EINVAL;
-
- action = (struct irqaction *)kmalloc(sizeof(*action), GFP_KERNEL);
- if (!action)
- return -ENOMEM;
-
- action->handler = handler;
- action->flags = irqflags;
- action->mask = 0;
- action->name = devname;
- 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;
+ /* All the braindamage happens magically for us in ip27_do_irq */
}
-void free_irq(unsigned int irq, void *dev_id)
+static void end_bridge_irq (unsigned int irq)
{
- struct irqaction * action, **p;
- unsigned long flags;
-
- if (irq >= NR_IRQS) {
- printk("Trying to free IRQ%d\n", irq);
- return;
- }
- for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) {
- if (action->dev_id != dev_id)
- continue;
-
- /* Found it - now free it */
- save_and_cli(flags);
- *p = action->next;
- if (irq >= BASE_PCI_IRQ)
- bridge_shutdown(irq);
- restore_flags(flags);
- kfree(action);
- return;
- }
- printk("Trying to free free IRQ%d\n",irq);
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ enable_bridge_irq(irq);
}
-/* Useless ISA nonsense. */
-unsigned long probe_irq_on (void)
-{
- panic("probe_irq_on called!\n");
- return 0;
-}
+static struct hw_interrupt_type bridge_irq_type = {
+ "bridge",
+ startup_bridge_irq,
+ shutdown_bridge_irq,
+ enable_bridge_irq,
+ disable_bridge_irq,
+ mask_and_ack_bridge_irq,
+ end_bridge_irq
+};
-int probe_irq_off (unsigned long irqs)
+void irq_debug(void)
{
- return 0;
-}
+ bridge_t *bridge = (bridge_t *) 0x9200000008000000;
-void __init init_IRQ(void)
-{
- set_except_vector(0, ip27_irq);
+ printk("bridge->b_int_status = 0x%x\n", bridge->b_int_status);
+ printk("bridge->b_int_enable = 0x%x\n", bridge->b_int_enable);
+ printk("PI_INT_PEND0 = 0x%lx\n", LOCAL_HUB_L(PI_INT_PEND0));
+ printk("PI_INT_MASK0_A = 0x%lx\n", LOCAL_HUB_L(PI_INT_MASK0_A));
}
-#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)
+void __init init_IRQ(void)
{
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++) {
- 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);
+ set_except_vector(0, ip27_irq);
/*
- * Ok, finally..
+ * Right now the bridge irq is our kitchen sink interrupt type
*/
- 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;
+ for (i = 0; i <= NR_IRQS; i++) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].action = 0;
+ irq_desc[i].depth = 1;
+ irq_desc[i].handler = &bridge_irq_type;
}
- 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.
*/
@@ -697,6 +387,39 @@
/* Nothing, the return from intr will work for us */
}
+#ifdef CONFIG_SMP
+
+void core_send_ipi(int destid, unsigned int action)
+{
+ int irq;
+
+#if (CPUS_PER_NODE == 2)
+ switch (action) {
+ case SMP_RESCHEDULE_YOURSELF:
+ irq = CPU_RESCHED_A_IRQ;
+ break;
+ case SMP_CALL_FUNCTION:
+ irq = CPU_CALL_A_IRQ;
+ break;
+ default:
+ panic("sendintr");
+ }
+ irq += cputoslice(destid);
+
+ /*
+ * Convert the compact hub number to the NASID to get the correct
+ * part of the address space. Then set the interrupt bit associated
+ * with the CPU we want to send the interrupt to.
+ */
+ REMOTE_HUB_SEND_INTR(COMPACT_TO_NASID_NODEID(cputocnode(destid)),
+ FAST_IRQ_TO_LEVEL(irq));
+#else
+ << Bomb! Must redefine this for more than 2 CPUS. >>
+#endif
+}
+
+#endif
+
extern void smp_call_function_interrupt(void);
void install_cpuintr(int cpu)
@@ -715,16 +438,16 @@
if (request_irq(CPU_RESCHED_A_IRQ, handle_resched_intr,
0, "resched", 0))
- panic("intercpu intr unconnectible\n");
+ panic("intercpu intr unconnectible");
if (request_irq(CPU_RESCHED_B_IRQ, handle_resched_intr,
0, "resched", 0))
- panic("intercpu intr unconnectible\n");
+ panic("intercpu intr unconnectible");
if (request_irq(CPU_CALL_A_IRQ, smp_call_function_interrupt,
0, "callfunc", 0))
- panic("intercpu intr unconnectible\n");
+ panic("intercpu intr unconnectible");
if (request_irq(CPU_CALL_B_IRQ, smp_call_function_interrupt,
0, "callfunc", 0))
- panic("intercpu intr unconnectible\n");
+ panic("intercpu intr unconnectible");
for (j = 0; j < PERNODE_LEVELS; j++)
LEVEL_TO_IRQ(0, j) = -1;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)