patch-2.1.92 linux/arch/alpha/kernel/irq.c
Next file: linux/arch/alpha/kernel/lca.c
Previous file: linux/arch/alpha/kernel/head.S
Back to the patch index
Back to the overall index
- Lines: 1330
- Date:
Mon Mar 30 00:21:39 1998
- Orig file:
v2.1.91/linux/arch/alpha/kernel/irq.c
- Orig date:
Tue Mar 10 10:03:30 1998
diff -u --recursive --new-file v2.1.91/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c
@@ -30,6 +30,10 @@
#define vulp volatile unsigned long *
#define vuip volatile unsigned int *
+extern void timer_interrupt(struct pt_regs * regs);
+extern void cserve_update_hw(unsigned long, unsigned long);
+extern void handle_ipi(struct pt_regs *);
+
#define RTC_IRQ 8
#ifdef CONFIG_RTC
#define TIMER_IRQ 0 /* timer is the pit */
@@ -45,12 +49,15 @@
#if defined(CONFIG_ALPHA_P2K)
/* always mask out unused timer irq 0 and RTC irq 8 */
# define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~0x101UL)
-#elif defined(CONFIG_ALPHA_ALCOR)
+#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
/* always mask out unused timer irq 0, "irqs" 20-30, and the EISA cascade: */
# define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~0xfff000000001UL)
#elif defined(CONFIG_ALPHA_RUFFIAN)
/* must leave timer irq 0 in the mask */
# define PROBE_MASK ((1UL << NR_IRQS) - 1)
+#elif NR_IRQS == 64
+ /* always mask out unused timer irq 0: */
+# define PROBE_MASK (~1UL)
#else
/* always mask out unused timer irq 0: */
# define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~1UL)
@@ -119,7 +126,7 @@
{
/* The "irq" argument is really the mask bit number */
switch (irq) {
- default: /* 16 ... 23 */
+ case 16 ... 23:
outb(mask >> 16, 0x53d);
break;
case 8 ... 15:
@@ -135,7 +142,7 @@
noritake_update_hw(unsigned long irq, unsigned long mask)
{
switch (irq) {
- default: /* 32 ... 47 */
+ case 32 ... 47:
outw(~(mask >> 32), 0x54c);
break;
case 16 ... 31:
@@ -155,7 +162,7 @@
miata_update_hw(unsigned long irq, unsigned long mask)
{
switch (irq) {
- default: /* 16 ... 47 */
+ case 16 ... 47:
/* Make CERTAIN none of the bogus ints get enabled... */
*(vulp)PYXIS_INT_MASK =
~((long)mask >> 16) & ~0x4000000000000e3bUL;
@@ -178,7 +185,7 @@
alcor_and_xlt_update_hw(unsigned long irq, unsigned long mask)
{
switch (irq) {
- default: /* 16 ... 47 */
+ case 16 ... 47:
/* On Alcor, at least, lines 20..30 are not connected and can
generate spurrious interrupts if we turn them on while IRQ
probing. So explicitly mask them out. */
@@ -202,7 +209,7 @@
mikasa_update_hw(unsigned long irq, unsigned long mask)
{
switch (irq) {
- default: /* 16 ... 31 */
+ case 16 ... 31:
outw(~(mask >> 16), 0x536); /* note invert */
break;
case 8 ... 15: /* ISA PIC2 */
@@ -214,7 +221,7 @@
}
}
-#ifdef CONFIG_ALPHA_RUFFIAN
+#if defined(CONFIG_ALPHA_RUFFIAN)
static inline void
ruffian_update_hw(unsigned long irq, unsigned long mask)
{
@@ -223,8 +230,7 @@
/* Note inverted sense of mask bits: */
/* Make CERTAIN none of the bogus ints get enabled... */
*(vulp)PYXIS_INT_MASK =
- ~((long)mask >> 16) & 0x00000000ffffffbfUL;
- mb();
+ ~((long)mask >> 16) & 0x00000000ffffffbfUL; mb();
/* ... and read it back to make sure it got written. */
*(vulp)PYXIS_INT_MASK;
break;
@@ -236,20 +242,23 @@
break;
}
}
-#endif
+#endif /* RUFFIAN */
-#ifdef CONFIG_ALPHA_SX164
+#if defined(CONFIG_ALPHA_SX164)
static inline void
sx164_update_hw(unsigned long irq, unsigned long mask)
{
switch (irq) {
case 16 ... 39:
- /* Make CERTAIN none of the bogus ints get enabled */
+#if defined(CONFIG_ALPHA_SRM)
+ cserve_update_hw(irq, mask);
+#else
+ /* make CERTAIN none of the bogus ints get enabled */
*(vulp)PYXIS_INT_MASK =
- ~((long)mask >> 16) & ~0x000000000000003bUL;
- mb();
+ ~((long)mask >> 16) & ~0x000000000000003bUL; mb();
/* ... and read it back to make sure it got written. */
*(vulp)PYXIS_INT_MASK;
+#endif /* SRM */
break;
case 8 ... 15: /* ISA PIC2 */
outb(mask >> 8, 0xA1);
@@ -258,20 +267,23 @@
outb(mask, 0x21);
break;
}
-}
-#endif
-/* Unlabeled mechanisms based on the number of irqs. Someone should
- probably document and name these. */
+}
+#endif /* SX164 */
+#if defined(CONFIG_ALPHA_DP264)
static inline void
-update_hw_33(unsigned long irq, unsigned long mask)
+dp264_update_hw(unsigned long irq, unsigned long mask)
{
switch (irq) {
- default: /* 16 ... 32 */
- outl(mask >> 16, 0x804);
+ case 16 ... 63:
+ /* make CERTAIN none of the bogus ints get enabled */
+ /* HACK ALERT! only CPU#0 is used currently */
+ *(vulp)TSUNAMI_CSR_DIM0 =
+ ~(mask) & ~0x0000000000000000UL; mb();
+ /* ... and read it back to make sure it got written. */
+ *(vulp)TSUNAMI_CSR_DIM0;
break;
-
case 8 ... 15: /* ISA PIC2 */
outb(mask >> 8, 0xA1);
break;
@@ -280,16 +292,24 @@
break;
}
}
+#endif /* DP264 */
+#if defined(CONFIG_ALPHA_RAWHIDE)
static inline void
-update_hw_32(unsigned long irq, unsigned long mask)
+rawhide_update_hw(unsigned long irq, unsigned long mask)
{
switch (irq) {
- default: /* 24 ... 31 */
- outb(mask >> 24, 0x27);
+ case 16 ... 39: /* PCI bus 0 with EISA bridge */
+ *(vuip)MCPCIA_INT_MASK0(0) =
+ (~((mask) >> 16) & 0x00ffffffU) | 0x00ff0000U; mb();
+ /* ... and read it back to make sure it got written. */
+ *(vuip)MCPCIA_INT_MASK0(0);
break;
- case 16 ... 23:
- outb(mask >> 16, 0x26);
+ case 40 ... 63: /* PCI bus 1 with builtin NCR810 SCSI */
+ *(vuip)MCPCIA_INT_MASK0(1) =
+ (~((mask) >> 40) & 0x00ffffffU) | 0x00fe0000U; mb();
+ /* ... and read it back to make sure it got written. */
+ *(vuip)MCPCIA_INT_MASK0(1);
break;
case 8 ... 15: /* ISA PIC2 */
outb(mask >> 8, 0xA1);
@@ -299,12 +319,29 @@
break;
}
}
+#endif /* RAWHIDE */
+/*
+ * HW update code for the following platforms:
+ *
+ * CABRIOLET (AlphaPC64)
+ * EB66P
+ * EB164
+ * PC164
+ * LX164
+ */
static inline void
-update_hw_16(unsigned long irq, unsigned long mask)
+update_hw_35(unsigned long irq, unsigned long mask)
{
switch (irq) {
- default: /* 8 ... 15, ISA PIC2 */
+ case 16 ... 34:
+#if defined(CONFIG_ALPHA_SRM)
+ cserve_update_hw(irq, mask);
+#else /* SRM */
+ outl(irq_mask >> 16, 0x804);
+#endif /* SRM */
+ break;
+ case 8 ... 15: /* ISA PIC2 */
outb(mask >> 8, 0xA1);
break;
case 0 ... 7: /* ISA PIC1 */
@@ -313,42 +350,38 @@
}
}
-#if (defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164)) \
- && defined(CONFIG_ALPHA_SRM)
-/*
- * On the pc164, we cannot take over the IRQs from the SRM,
- * so we call down to do our dirty work. Too bad the SRM
- * isn't consistent across platforms otherwise we could do
- * this always.
- */
-
-extern void cserve_ena(unsigned long);
-extern void cserve_dis(unsigned long);
-
-static inline void mask_irq(unsigned long irq)
+static inline void
+update_hw_32(unsigned long irq, unsigned long mask)
{
- irq_mask |= (1UL << irq);
- cserve_dis(irq - 16);
+ switch (irq) {
+ case 24 ... 31:
+ outb(mask >> 24, 0x27);
+ break;
+ case 16 ... 23:
+ outb(mask >> 16, 0x26);
+ break;
+ case 8 ... 15: /* ISA PIC2 */
+ outb(mask >> 8, 0xA1);
+ break;
+ case 0 ... 7: /* ISA PIC1 */
+ outb(mask, 0x21);
+ break;
}
-
-static inline void unmask_irq(unsigned long irq)
-{
- irq_mask &= ~(1UL << irq);
- cserve_ena(irq - 16);
}
-/* Since we are calling down to PALcode, no need to diddle IPL. */
-void disable_irq(unsigned int irq_nr)
+static inline void
+update_hw_16(unsigned long irq, unsigned long mask)
{
- mask_irq(IRQ_TO_MASK(irq_nr));
+ switch (irq) {
+ case 8 ... 15: /* ISA PIC2 */
+ outb(mask >> 8, 0xA1);
+ break;
+ case 0 ... 7: /* ISA PIC1 */
+ outb(mask, 0x21);
+ break;
}
-
-void enable_irq(unsigned int irq_nr)
-{
- unmask_irq(IRQ_TO_MASK(irq_nr));
}
-#else
/*
* We manipulate the hardware ourselves.
*/
@@ -369,9 +402,18 @@
sx164_update_hw(irq, mask);
#elif defined(CONFIG_ALPHA_RUFFIAN)
ruffian_update_hw(irq, mask);
-#elif NR_IRQS == 33
- update_hw_33(irq, mask);
-#elif NR_IRQS == 32
+#elif defined(CONFIG_ALPHA_DP264)
+ dp264_update_hw(irq, mask);
+#elif defined(CONFIG_ALPHA_RAWHIDE)
+ rawhide_update_hw(irq, mask);
+#elif defined(CONFIG_ALPHA_CABRIOLET) || \
+ defined(CONFIG_ALPHA_EB66P) || \
+ defined(CONFIG_ALPHA_EB164) || \
+ defined(CONFIG_ALPHA_PC164) || \
+ defined(CONFIG_ALPHA_LX164)
+ update_hw_35(irq, mask);
+#elif defined(CONFIG_ALPHA_EB66) || \
+ defined(CONFIG_ALPHA_EB64P)
update_hw_32(irq, mask);
#elif NR_IRQS == 16
update_hw_16(irq, mask);
@@ -396,8 +438,7 @@
{
unsigned long flags;
- save_flags(flags);
- cli();
+ save_and_cli(flags);
mask_irq(IRQ_TO_MASK(irq_nr));
restore_flags(flags);
}
@@ -406,12 +447,10 @@
{
unsigned long flags;
- save_flags(flags);
- cli();
+ save_and_cli(flags);
unmask_irq(IRQ_TO_MASK(irq_nr));
restore_flags(flags);
}
-#endif /* (PC164 || LX164) && SRM */
/*
* Initial irq handlers.
@@ -423,13 +462,14 @@
{
int i, len = 0;
struct irqaction * action;
+ int cpu = smp_processor_id();
for (i = 0; i < NR_IRQS; i++) {
action = irq_action[i];
if (!action)
continue;
len += sprintf(buf+len, "%2d: %10u %c %s",
- i, kstat.irqs[0][i],
+ i, kstat.irqs[cpu][i],
(action->flags & SA_INTERRUPT) ? '+' : ' ',
action->name);
for (action=action->next; action; action = action->next) {
@@ -463,16 +503,18 @@
#elif defined(CONFIG_ALPHA_RUFFIAN)
if (irq < 16) {
/* Ack PYXIS ISA interrupt. */
- *(vulp)PYXIS_INT_REQ = 1 << 7;
- mb();
+ *(vulp)PYXIS_INT_REQ = 1L << 7; mb();
+ /* ... and read it back to make sure it got written. */
+ *(vulp)PYXIS_INT_REQ;
if (irq > 7) {
outb(0x20, 0xa0);
}
outb(0x20, 0x20);
} else {
- /* Ack PYXIS interrupt. */
+ /* Ack PYXIS PCI interrupt. */
*(vulp)PYXIS_INT_REQ = (1UL << (irq - 16));
- mb();
+ /* ... and read it back to make sure it got written. */
+ *(vulp)PYXIS_INT_REQ;
}
#else
if (irq < 16) {
@@ -488,7 +530,7 @@
/* on ALCOR/XLT, need to dismiss interrupt via GRU */
*(vuip)GRU_INT_CLEAR = 0x80000000; mb();
*(vuip)GRU_INT_CLEAR = 0x00000000; mb();
-#endif
+#endif /* ALCOR || XLT */
}
#endif
}
@@ -556,8 +598,7 @@
action->next = NULL;
action->dev_id = dev_id;
- save_flags(flags);
- cli();
+ save_and_cli(flags);
*p = action;
if (!shared)
@@ -585,8 +626,7 @@
continue;
/* Found it - now free it */
- save_flags(flags);
- cli();
+ save_and_cli(flags);
*p = action->next;
if (!irq[irq_action])
mask_irq(IRQ_TO_MASK(irq));
@@ -607,7 +647,277 @@
unsigned int local_bh_count[NR_CPUS];
#ifdef __SMP__
-#error "Me no hablo Alpha SMP"
+/* Who has global_irq_lock. */
+unsigned char global_irq_holder = NO_PROC_ID;
+
+/* This protects IRQ's. */
+spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED;
+
+/* Global IRQ locking depth. */
+atomic_t global_irq_count = ATOMIC_INIT(0);
+
+/* This protects BH software state (masks, things like that). */
+atomic_t global_bh_lock = ATOMIC_INIT(0);
+atomic_t global_bh_count = ATOMIC_INIT(0);
+
+static unsigned long previous_irqholder = NO_PROC_ID;
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; }
+
+static inline void wait_on_irq(int cpu, unsigned long where)
+{
+ int stuck = INIT_STUCK;
+ int local_count = local_irq_count[cpu];
+
+ /* Are we the only one in an interrupt context? */
+ while (local_count != atomic_read(&global_irq_count)) {
+ /*
+ * No such luck. Now we need to release the lock,
+ * _and_ release our interrupt context, because
+ * otherwise we'd have dead-locks and live-locks
+ * and other fun things.
+ */
+ atomic_sub(local_count, &global_irq_count);
+ spin_unlock(&global_irq_lock);
+
+ /*
+ * Wait for everybody else to go away and release
+ * their things before trying to get the lock again.
+ */
+ for (;;) {
+ STUCK;
+ if (atomic_read(&global_irq_count))
+ continue;
+ if (global_irq_lock.lock)
+ continue;
+ if (spin_trylock(&global_irq_lock))
+ break;
+ }
+ atomic_add(local_count, &global_irq_count);
+ }
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 10000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;}
+
+static inline void get_irqlock(int cpu, unsigned long where)
+{
+ int stuck = INIT_STUCK;
+
+ if (!spin_trylock(&global_irq_lock)) {
+ /* do we already hold the lock? */
+ if ((unsigned char) cpu == global_irq_holder) {
+#if 0
+ printk("get_irqlock: already held at %08lx\n",
+ previous_irqholder);
+#endif
+ return;
+ }
+ /* Uhhuh.. Somebody else got it. Wait.. */
+ do {
+ do {
+ STUCK;
+ barrier();
+ } while (global_irq_lock.lock);
+ } while (!spin_trylock(&global_irq_lock));
+ }
+ /*
+ * Ok, we got the lock bit.
+ * But that's actually just the easy part.. Now
+ * we need to make sure that nobody else is running
+ * in an interrupt context.
+ */
+ wait_on_irq(cpu, where);
+
+ /*
+ * Finally.
+ */
+ global_irq_holder = cpu;
+ previous_irqholder = where;
+}
+
+void __global_cli(void)
+{
+ int cpu = smp_processor_id();
+ unsigned long where;
+
+ __asm__("mov $26, %0" : "=r" (where));
+ __cli();
+
+ if (!local_irq_count[cpu])
+ get_irqlock(smp_processor_id(), where);
+}
+
+void __global_sti(void)
+{
+ int cpu = smp_processor_id();
+
+ if (!local_irq_count[cpu])
+ release_irqlock(smp_processor_id());
+
+ __sti();
+}
+
+#if 0
+unsigned long __global_save_flags(void)
+{
+ return global_irq_holder == (unsigned char) smp_processor_id();
+}
+#endif
+
+void __global_restore_flags(unsigned long flags)
+{
+ if (flags & 1) {
+ __global_cli();
+ } else {
+ /* release_irqlock() */
+ if (global_irq_holder == smp_processor_id()) {
+ global_irq_holder = NO_PROC_ID;
+ spin_unlock(&global_irq_lock);
+ }
+ if (!(flags & 2))
+ __sti();
+ }
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 200000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",irq,cpu,global_irq_holder); stuck = INIT_STUCK;}
+
+#undef VERBOSE_IRQLOCK_DEBUGGING
+
+void irq_enter(int cpu, int irq)
+{
+#ifdef VERBOSE_IRQLOCK_DEBUGGING
+ extern void smp_show_backtrace_all_cpus(void);
+#endif
+ int stuck = INIT_STUCK;
+
+ hardirq_enter(cpu);
+ barrier();
+ while (global_irq_lock.lock) {
+ if ((unsigned char) cpu == global_irq_holder) {
+ int globl_locked = global_irq_lock.lock;
+ int globl_icount = atomic_read(&global_irq_count);
+ int local_count = local_irq_count[cpu];
+
+ /* It is very important that we load the state variables
+ * before we do the first call to printk() as printk()
+ * could end up changing them...
+ */
+
+#if 0
+ printk("CPU[%d]: BAD! Local IRQ's enabled,"
+ " global disabled interrupt\n", cpu);
+#endif
+ printk("CPU[%d]: where [%08lx] glocked[%d] gicnt[%d]"
+ " licnt[%d]\n",
+ cpu, previous_irqholder, globl_locked,
+ globl_icount, local_count);
+#ifdef VERBOSE_IRQLOCK_DEBUGGING
+ printk("Performing backtrace on all cpus,"
+ " write this down!\n");
+ smp_show_backtrace_all_cpus();
+#endif
+ break;
+ }
+ STUCK;
+ barrier();
+ }
+}
+
+void irq_exit(int cpu, int irq)
+{
+ hardirq_exit(cpu);
+ release_irqlock(cpu);
+}
+
+static void show(char * str)
+{
+#if 0
+ int i;
+ unsigned long *stack;
+#endif
+ int cpu = smp_processor_id();
+
+ printk("\n%s, CPU %d:\n", str, cpu);
+ printk("irq: %d [%d %d]\n",
+ atomic_read(&global_irq_count), local_irq_count[0],
+ local_irq_count[1]);
+ printk("bh: %d [%d %d]\n",
+ atomic_read(&global_bh_count), local_bh_count[0],
+ local_bh_count[1]);
+#if 0
+ stack = (unsigned long *) &str;
+ for (i = 40; i ; i--) {
+ unsigned long x = *++stack;
+ if (x > (unsigned long) &init_task_union &&
+ x < (unsigned long) &vsprintf) {
+ printk("<[%08lx]> ", x);
+ }
+ }
+#endif
+}
+
+#define MAXCOUNT 100000000
+
+static inline void wait_on_bh(void)
+{
+ int count = MAXCOUNT;
+ do {
+ if (!--count) {
+ show("wait_on_bh");
+ count = ~0;
+ }
+ /* nothing .. wait for the other bh's to go away */
+ } while (atomic_read(&global_bh_count) != 0);
+}
+
+/*
+ * This is called when we want to synchronize with
+ * bottom half handlers. We need to wait until
+ * no other CPU is executing any bottom half handler.
+ *
+ * Don't wait if we're already running in an interrupt
+ * context or are inside a bh handler.
+ */
+void synchronize_bh(void)
+{
+ if (atomic_read(&global_bh_count)) {
+ int cpu = smp_processor_id();
+ if (!local_irq_count[cpu] && !local_bh_count[cpu]) {
+ wait_on_bh();
+ }
+ }
+}
+
+/* There has to be a better way. */
+void synchronize_irq(void)
+{
+ int cpu = smp_processor_id();
+ int local_count = local_irq_count[cpu];
+
+ if (local_count != atomic_read(&global_irq_count)) {
+ unsigned long flags;
+
+ /* An infamously unpopular approach. */
+ save_and_cli(flags);
+ restore_flags(flags);
+ }
+}
+
#else
#define irq_enter(cpu, irq) (++local_irq_count[cpu])
#define irq_exit(cpu, irq) (--local_irq_count[cpu])
@@ -647,7 +957,7 @@
int cpu = smp_processor_id();
irq_enter(cpu, irq);
- kstat.irqs[0][irq] += 1;
+ kstat.irqs[cpu][irq] += 1;
if (!action) {
unexpected_irq(irq, regs);
} else {
@@ -670,8 +980,9 @@
}
irq_enter(cpu, irq);
- kstat.irqs[0][irq] += 1;
+ kstat.irqs[cpu][irq] += 1;
action = irq_action[irq];
+
/*
* For normal interrupts, we mask it out, and then ACK it.
* This way another (more timing-critical) interrupt can
@@ -691,6 +1002,10 @@
action = action->next;
} while (action);
unmask_irq(ack);
+ } else {
+#if 1
+ printk("device_interrupt: unexpected interrupt %d\n", irq);
+#endif
}
irq_exit(cpu, irq);
}
@@ -711,6 +1026,8 @@
# define IACK_SC CIA_IACK_SC
#elif defined(CONFIG_ALPHA_PYXIS)
# define IACK_SC PYXIS_IACK_SC
+#elif defined(CONFIG_ALPHA_TSUNAMI)
+# define IACK_SC TSUNAMI_PCI0_IACK_SC
#else
/*
* This is bogus but necessary to get it to compile
@@ -729,7 +1046,7 @@
* interrupt that is pending. The PALcode sets up the
* interrupts vectors such that irq level L generates vector L.
*/
- j = *(volatile int *) IACK_SC;
+ j = *(vuip) IACK_SC;
j &= 0xff;
if (j == 7) {
if (!(inb(0x20) & 0x80)) {
@@ -775,10 +1092,9 @@
unsigned int i;
unsigned long flags;
- save_flags(flags);
- cli();
+ save_and_cli(flags);
- /* read the interrupt summary register of the GRU */
+ /* Read the interrupt summary register of the GRU */
pld = (*(vuip)GRU_INT_REQ) & GRU_INT_REQ_BITS;
#if 0
@@ -810,10 +1126,9 @@
unsigned int i;
unsigned long flags;
- save_flags(flags);
- cli();
+ save_and_cli(flags);
- /* read the interrupt summary registers */
+ /* Read the interrupt summary registers */
pld = inb(0x804) | (inb(0x805) << 8) | (inb(0x806) << 16);
#if 0
@@ -843,10 +1158,9 @@
unsigned int i;
unsigned long flags;
- save_flags(flags);
- cli();
+ save_and_cli(flags);
- /* read the interrupt summary registers */
+ /* Read the interrupt summary registers */
pld = (((unsigned long) (~inw(0x534)) & 0x0000ffffUL) << 16) |
(((unsigned long) inb(0xa0)) << 8) |
((unsigned long) inb(0x20));
@@ -878,10 +1192,9 @@
unsigned int i;
unsigned long flags;
- save_flags(flags);
- cli();
+ save_and_cli(flags);
- /* read the interrupt summary registers */
+ /* Read the interrupt summary registers */
pld = inb(0x26) | (inb(0x27) << 8);
/*
* Now, for every possible bit set, work through
@@ -909,30 +1222,34 @@
unsigned int i;
unsigned long flags;
- save_flags(flags);
- cli();
+ save_and_cli(flags);
- /* read the interrupt summary register of PYXIS */
- pld = (*(vulp)PYXIS_INT_REQ);
+ /* Read the interrupt summary register of PYXIS */
+ pld = *(vulp)PYXIS_INT_REQ;
#if 0
printk("[0x%08lx/0x%08lx/0x%04x]", pld,
*(vulp)PYXIS_INT_MASK, inb(0x20) | (inb(0xA0) << 8));
#endif
- /* For now, AND off any bits we are not interested in. */
-#if defined(CONFIG_ALPHA_MIATA)
- /* HALT (2), timer (6), ISA Bridge (7), 21142/3 (8),
- then all the PCI slots/INTXs (12-31). */
+#ifdef CONFIG_ALPHA_MIATA
+ /*
+ * For now, AND off any bits we are not interested in:
+ * HALT (2), timer (6), ISA Bridge (7), 21142/3 (8)
+ * then all the PCI slots/INTXs (12-31).
+ */
/* Maybe HALT should only be used for SRM console boots? */
pld &= 0x00000000fffff1c4UL;
#endif
-#if defined(CONFIG_ALPHA_SX164)
- /* HALT (2), timer (6), ISA Bridge (7),
- then all the PCI slots/INTXs (8-23). */
- /* HALT should only be used for SRM console boots. */
+#ifdef CONFIG_ALPHA_SX164
+ /*
+ * For now, AND off any bits we are not interested in:
+ * HALT (2), timer (6), ISA Bridge (7)
+ * then all the PCI slots/INTXs (8-23)
+ */
+ /* Maybe HALT should only be used for SRM console boots? */
pld &= 0x0000000000ffffc0UL;
-#endif
+#endif /* SX164 */
/*
* Now for every possible bit set, work through them and call
@@ -962,10 +1279,9 @@
unsigned int i;
unsigned long flags;
- save_flags(flags);
- cli();
+ save_and_cli(flags);
- /* read the interrupt summary registers of NORITAKE */
+ /* Read the interrupt summary registers of NORITAKE */
pld = ((unsigned long) inw(0x54c) << 32) |
((unsigned long) inw(0x54a) << 16) |
((unsigned long) inb(0xa0) << 8) |
@@ -991,16 +1307,76 @@
restore_flags(flags);
}
+#if defined(CONFIG_ALPHA_DP264)
+/* we have to conditionally compile this because of TSUNAMI_xxx symbols */
+static inline void dp264_device_interrupt(unsigned long vector,
+ struct pt_regs * regs)
+{
+ unsigned long pld, tmp;
+ unsigned int i;
+ unsigned long flags;
+
+ __save_and_cli(flags);
+
+ /* Read the interrupt summary register of TSUNAMI */
+ pld = (*(vulp)TSUNAMI_CSR_DIR0);
+
+#if 0
+ printk("[0x%08lx/0x%08lx/0x%04x]", pld,
+ *(vulp)TSUNAMI_CSR_DIM0,
+ inb(0x20) | (inb(0xA0) << 8));
+#endif
+
+ /*
+ * Now for every possible bit set, work through them and call
+ * the appropriate interrupt handler.
+ */
+ while (pld) {
+ i = ffz(~pld);
+ pld &= pld - 1; /* clear least bit set */
+ if (i == 55) {
+ isa_device_interrupt(vector, regs);
+ } else { /* if not timer int */
+ device_interrupt(16 + i, 16 + i, regs);
+ }
+#if 0
+ *(vulp)TSUNAMI_CSR_DIR0 = 1UL << i; mb();
+ tmp = *(vulp)TSUNAMI_CSR_DIR0;
+#endif
+ }
+ __restore_flags(flags);
+}
+#endif /* DP264 */
+
+#if defined(CONFIG_ALPHA_RAWHIDE)
+/* we have to conditionally compile this because of MCPCIA_xxx symbols */
+static inline void rawhide_device_interrupt(unsigned long vector,
+ struct pt_regs * regs)
+{
+#if 0
+ unsigned long pld;
+ unsigned int i;
+ unsigned long flags;
+
+ __save_and_cli(flags);
+
+ /* PLACEHOLDER, perhaps never used if we always do SRM */
+
+ __restore_flags(flags);
+#endif
+}
+#endif /* RAWHIDE */
+
#if defined(CONFIG_ALPHA_RUFFIAN)
static inline void
ruffian_device_interrupt(unsigned long vector, struct pt_regs *regs)
+
{
unsigned long pld;
unsigned int i;
unsigned long flags;
- save_flags(flags);
- cli();
+ save_and_cli(flags);
/* Read the interrupt summary register of PYXIS */
pld = *(vulp)PYXIS_INT_REQ;
@@ -1010,16 +1386,16 @@
* then all the PCI slots/INTXs (12-31)
* flash(5) :DWH:
*/
- pld &= 0x00000000ffffff9fUL;
+ pld &= 0x00000000ffffff9fUL;/* was ffff7f */
/*
* Now for every possible bit set, work through them and call
* the appropriate interrupt handler.
*/
+
while (pld) {
i = ffz(~pld);
pld &= pld - 1; /* clear least bit set */
-
if (i == 7) {
/* Copy this bit from isa_device_interrupt cause
we need to hook into int 0 for the timer. I
@@ -1041,19 +1417,57 @@
} else {
device_interrupt(j, j, regs);
}
- } else {
+ } else { /* if not timer int */
device_interrupt(16 + i, 16 + i, regs);
}
- *(vulp)PYXIS_INT_REQ = 1UL << i;
- mb();
- *(vulp)PYXIS_INT_REQ;
+ *(vulp)PYXIS_INT_REQ = 1UL << i; mb();
+ *(vulp)PYXIS_INT_REQ; /* read to force the write */
}
-
restore_flags(flags);
}
#endif /* RUFFIAN */
+static inline void takara_device_interrupt(unsigned long vector,
+ struct pt_regs * regs)
+{
+ unsigned long flags;
+ unsigned intstatus;
+
+ save_and_cli(flags);
+
+ /*
+ * The PALcode will have passed us vectors 0x800 or 0x810,
+ * which are fairly arbitrary values and serve only to tell
+ * us whether an interrupt has come in on IRQ0 or IRQ1. If
+ * it's IRQ1 it's a PCI interrupt; if it's IRQ0, it's
+ * probably ISA, but PCI interrupts can come through IRQ0
+ * as well if the interrupt controller isn't in accelerated
+ * mode.
+ *
+ * OTOH, the accelerator thing doesn't seem to be working
+ * overly well, so what we'll do instead is try directly
+ * examining the Master Interrupt Register to see if it's a
+ * PCI interrupt, and if _not_ then we'll pass it on to the
+ * ISA handler.
+ */
+
+ intstatus = inw(0x500) & 15;
+ if (intstatus) {
+ /*
+ * This is a PCI interrupt. Check each bit and
+ * despatch an interrupt if it's set.
+ */
+ if (intstatus & 8) device_interrupt(16+3, 16+3, regs);
+ if (intstatus & 4) device_interrupt(16+2, 16+2, regs);
+ if (intstatus & 2) device_interrupt(16+1, 16+1, regs);
+ if (intstatus & 1) device_interrupt(16+0, 16+0, regs);
+ } else
+ isa_device_interrupt (vector, regs);
+
+ restore_flags(flags);
+}
+
#endif /* CONFIG_PCI */
/*
@@ -1085,9 +1499,11 @@
int irq, ack;
unsigned long flags;
- save_flags(flags);
- cli();
+ __save_and_cli(flags);
+#ifdef __SMP__
+if (smp_processor_id()) printk("srm_device_interrupt on other CPU\n");
+#endif
ack = irq = (vector - 0x800) >> 4;
@@ -1131,9 +1547,9 @@
#ifdef CONFIG_ALPHA_NORITAKE
/*
- * I really hate to do this, but the NORITAKE SRM console reports
- * PCI vectors *lower* than I expected from the bit numbering in
- * the documentation.
+ * I really hate to do this, too, but the NORITAKE SRM console also
+ * reports PCI vectors *lower* than I expected from the bit numbers
+ * in the documentation.
* But I really don't want to change the fixup code for allocation
* of IRQs, nor the irq_mask maintenance stuff, both of which look
* nice and clean now.
@@ -1153,9 +1569,41 @@
#endif
#endif /* CONFIG_ALPHA_SABLE */
+#ifdef CONFIG_ALPHA_DP264
+ /*
+ * the DP264 SRM console reports PCI interrupts with a vector
+ * 0x100 *higher* than one might expect, as PCI IRQ 0 (ie bit 0)
+ * shows up as IRQ 16, etc, etc. We adjust it down by 16 to have
+ * it line up with the actual bit numbers from the DIM registers,
+ * which is how we manage the interrupts/mask. Sigh...
+ */
+ if (irq >= 32)
+ ack = irq = irq - 16;
+#endif /* DP264 */
+
+#ifdef CONFIG_ALPHA_RAWHIDE
+ /*
+ * the RAWHIDE SRM console reports PCI interrupts with a vector
+ * 0x80 *higher* than one might expect, as PCI IRQ 0 (ie bit 0)
+ * shows up as IRQ 24, etc, etc. We adjust it down by 8 to have
+ * it line up with the actual bit numbers from the REQ registers,
+ * which is how we manage the interrupts/mask. Sigh...
+ *
+ * also, PCI #1 interrupts are offset some more... :-(
+ */
+ if (irq == 52)
+ ack = irq = 56; /* SCSI on PCI 1 is special */
+ else {
+ if (irq >= 24) /* adjust all PCI interrupts down 8 */
+ ack = irq = irq - 8;
+ if (irq >= 48) /* adjust PCI bus 1 interrupts down another 8 */
+ ack = irq = irq - 8;
+ }
+#endif /* RAWHIDE */
+
device_interrupt(irq, ack, regs);
- restore_flags(flags);
+ __restore_flags(flags);
}
/*
@@ -1218,6 +1666,10 @@
struct pt_regs * regs);
extern void t2_machine_check(unsigned long vector, unsigned long la,
struct pt_regs * regs);
+extern void tsunami_machine_check(unsigned long vector, unsigned long la,
+ struct pt_regs * regs);
+extern void mcpcia_machine_check(unsigned long vector, unsigned long la,
+ struct pt_regs * regs);
static void
machine_check(unsigned long vector, unsigned long la, struct pt_regs *regs)
@@ -1232,6 +1684,10 @@
pyxis_machine_check(vector, la, regs);
#elif defined(CONFIG_ALPHA_T2)
t2_machine_check(vector, la, regs);
+#elif defined(CONFIG_ALPHA_TSUNAMI)
+ tsunami_machine_check(vector, la, regs);
+#elif defined(CONFIG_ALPHA_MCPCIA)
+ mcpcia_machine_check(vector, la, regs);
#else
printk("Machine check\n");
#endif
@@ -1244,7 +1700,14 @@
{
switch (type) {
case 0:
+#ifdef __SMP__
+/* irq_enter(smp_processor_id(), 0); ??????? */
+ handle_ipi(®s);
+/* irq_exit(smp_processor_id(), 0); ??????? */
+ return;
+#else /* __SMP__ */
printk("Interprocessor interrupt? You must be kidding\n");
+#endif /* __SMP__ */
break;
case 1:
handle_irq(RTC_IRQ, ®s);
@@ -1253,23 +1716,38 @@
machine_check(vector, la_ptr, ®s);
return;
case 3:
-#if defined(CONFIG_ALPHA_JENSEN) || defined(CONFIG_ALPHA_NONAME) || \
- defined(CONFIG_ALPHA_P2K) || defined(CONFIG_ALPHA_SRM)
+#if defined(CONFIG_ALPHA_JENSEN) || \
+ defined(CONFIG_ALPHA_NONAME) || \
+ defined(CONFIG_ALPHA_P2K) || \
+ defined(CONFIG_ALPHA_SRM)
srm_device_interrupt(vector, ®s);
-#elif defined(CONFIG_ALPHA_MIATA) || defined(CONFIG_ALPHA_SX164)
+#elif defined(CONFIG_ALPHA_MIATA) || \
+ defined(CONFIG_ALPHA_SX164)
miata_device_interrupt(vector, ®s);
#elif defined(CONFIG_ALPHA_NORITAKE)
noritake_device_interrupt(vector, ®s);
-#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
+#elif defined(CONFIG_ALPHA_ALCOR) || \
+ defined(CONFIG_ALPHA_XLT)
alcor_and_xlt_device_interrupt(vector, ®s);
-#elif defined(CONFIG_ALPHA_RUFFIAN)
- ruffian_device_interrupt(vector, ®s);
+#elif defined(CONFIG_ALPHA_CABRIOLET) || \
+ defined(CONFIG_ALPHA_EB66P) || \
+ defined(CONFIG_ALPHA_EB164) || \
+ defined(CONFIG_ALPHA_PC164) || \
+ defined(CONFIG_ALPHA_LX164)
+ cabriolet_and_eb66p_device_interrupt(vector, ®s);
#elif defined(CONFIG_ALPHA_MIKASA)
mikasa_device_interrupt(vector, ®s);
-#elif NR_IRQS == 33
- cabriolet_and_eb66p_device_interrupt(vector, ®s);
-#elif NR_IRQS == 32
+#elif defined(CONFIG_ALPHA_EB66) || \
+ defined(CONFIG_ALPHA_EB64P)
eb66_and_eb64p_device_interrupt(vector, ®s);
+#elif defined(CONFIG_ALPHA_RUFFIAN)
+ ruffian_device_interrupt(vector, ®s);
+#elif defined(CONFIG_ALPHA_DP264)
+ dp264_device_interrupt(vector, ®s);
+#elif defined(CONFIG_ALPHA_RAWHIDE)
+ rawhide_device_interrupt(vector, ®s);
+#elif defined(CONFIG_ALPHA_TAKARA)
+ takara_device_interrupt(vector, ®s);
#elif NR_IRQS == 16
isa_device_interrupt(vector, ®s);
#endif
@@ -1293,22 +1771,21 @@
outb(0x44, 0x535); /* enable cascades in master */
}
-#ifdef CONFIG_ALPHA_SX164
+#if defined(CONFIG_ALPHA_SX164)
static inline void sx164_init_IRQ(void)
{
+#if !defined(CONFIG_ALPHA_SRM)
/* note invert on MASK bits */
*(vulp)PYXIS_INT_MASK = ~((long)irq_mask >> 16); mb();
-#if 0
- *(vulp)PYXIS_INT_HILO = 0x000000B2UL; mb(); /* ISA/NMI HI */
- *(vulp)PYXIS_RT_COUNT = 0UL; mb(); /* clear count */
-#endif
+ *(vulp)PYXIS_INT_MASK;
+#endif /* !SRM */
enable_irq(16 + 6); /* enable timer */
enable_irq(16 + 7); /* enable ISA PIC cascade */
enable_irq(2); /* enable cascade */
}
#endif /* SX164 */
-#ifdef CONFIG_ALPHA_RUFFIAN
+#if defined(CONFIG_ALPHA_RUFFIAN)
static inline void ruffian_init_IRQ(void)
{
/* invert 6&7 for i82371 */
@@ -1343,19 +1820,19 @@
}
#endif /* RUFFIAN */
-
#ifdef CONFIG_ALPHA_MIATA
static inline void miata_init_IRQ(void)
{
/* note invert on MASK bits */
*(vulp)PYXIS_INT_MASK = ~((long)irq_mask >> 16); mb(); /* invert */
+#if 0
+ /* these break on MiataGL so we'll try not to do it at all */
*(vulp)PYXIS_INT_HILO = 0x000000B2UL; mb(); /* ISA/NMI HI */
*(vulp)PYXIS_RT_COUNT = 0UL; mb(); /* clear count */
- *(vulp)PYXIS_INT_REQ = 0x4000000000000000UL; mb(); /* clear upper timer */
-#if 0
- *(vulp)PYXIS_INT_ROUTE = 0UL; mb(); /* all are level */
- *(vulp)PYXIS_INT_CNFG = 0UL; mb(); /* all clear */
#endif
+ /* clear upper timer */
+ *(vulp)PYXIS_INT_REQ = 0x4000000000000000UL; mb();
+
enable_irq(16 + 2); /* enable HALT switch - SRM only? */
enable_irq(16 + 6); /* enable timer */
enable_irq(16 + 7); /* enable ISA PIC cascade */
@@ -1381,7 +1858,7 @@
enable_irq(16 + 31); /* enable (E)ISA PIC cascade */
enable_irq(2); /* enable cascade */
}
-#endif
+#endif /* ALCOR || XLT */
static inline void mikasa_init_IRQ(void)
{
@@ -1389,9 +1866,56 @@
enable_irq(2); /* enable cascade */
}
-static inline void init_IRQ_33(void)
+#if defined(CONFIG_ALPHA_DP264)
+static inline void dp264_init_IRQ(void)
+{
+ /* note invert on MASK bits */
+ *(vulp)TSUNAMI_CSR_DIM0 =
+ ~(irq_mask) & ~0x0000000000000000UL; mb();
+ *(vulp)TSUNAMI_CSR_DIM0;
+ enable_irq(55); /* enable CYPRESS interrupt controller (ISA) */
+ enable_irq(2);
+}
+#endif /* DP264 */
+
+#if defined(CONFIG_ALPHA_RAWHIDE)
+static inline void rawhide_init_IRQ(void)
+{
+ /* HACK ALERT! only PCI busses 0 and 1 are used currently,
+ and routing is only to CPU #1*/
+
+ *(vuip)MCPCIA_INT_MASK0(0) =
+ (~((irq_mask) >> 16) & 0x00ffffffU) | 0x00ff0000U; mb();
+ /* ... and read it back to make sure it got written. */
+ *(vuip)MCPCIA_INT_MASK0(0);
+
+ *(vuip)MCPCIA_INT_MASK0(1) =
+ (~((irq_mask) >> 40) & 0x00ffffffU) | 0x00fe0000U; mb();
+ /* ... and read it back to make sure it got written. */
+ *(vuip)MCPCIA_INT_MASK0(1);
+ enable_irq(2);
+}
+#endif /* RAWHIDE */
+
+static inline void takara_init_IRQ(void)
+{
+ unsigned int ctlreg = inl(0x500);
+
+ ctlreg &= ~0x8000; /* return to non-accelerated mode */
+ outw(ctlreg >> 16, 0x502);
+ outw(ctlreg & 0xFFFF, 0x500);
+ ctlreg = 0x05107c00; /* enable the PCI interrupt register */
+ printk("Setting to 0x%08x\n", ctlreg);
+ outw(ctlreg >> 16, 0x502);
+ outw(ctlreg & 0xFFFF, 0x500);
+ enable_irq(2);
+}
+
+static inline void init_IRQ_35(void)
{
+#if !defined(CONFIG_ALPHA_SRM)
outl(irq_mask >> 16, 0x804);
+#endif /* !SRM */
enable_irq(16 + 4); /* enable SIO cascade */
enable_irq(2); /* enable cascade */
}
@@ -1413,13 +1937,20 @@
init_IRQ(void)
{
wrent(entInt, 0);
- dma_outb(0, DMA1_RESET_REG);
- dma_outb(0, DMA2_RESET_REG);
-#ifndef CONFIG_ALPHA_SX164
- dma_outb(0, DMA1_CLR_MASK_REG);
- /* We need to figure out why this fails on the SX164. */
- dma_outb(0, DMA2_CLR_MASK_REG);
-#endif
+
+/* FIXME FIXME FIXME FIXME FIXME */
+#if !defined(CONFIG_ALPHA_DP264)
+ /* we need to figure out why these fail on the DP264 */
+ outb(0, DMA1_RESET_REG);
+ outb(0, DMA2_RESET_REG);
+#endif /* !DP264 */
+/* FIXME FIXME FIXME FIXME FIXME */
+#if !defined(CONFIG_ALPHA_SX164) && !defined(CONFIG_ALPHA_DP264)
+ outb(0, DMA1_CLR_MASK_REG);
+ /* we need to figure out why this fails on the SX164 */
+ outb(0, DMA2_CLR_MASK_REG);
+#endif /* !SX164 && !DP264 */
+/* end FIXMEs */
#if defined(CONFIG_ALPHA_SABLE)
sable_init_IRQ();
@@ -1431,17 +1962,21 @@
noritake_init_IRQ();
#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
alcor_and_xlt_init_IRQ();
-#elif (defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164)) \
- && defined(CONFIG_ALPHA_SRM)
- /* Disable all the PCI interrupts? Otherwise, everthing was
- done by SRM already. */
#elif defined(CONFIG_ALPHA_MIKASA)
mikasa_init_IRQ();
+#elif defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P) || \
+ defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164) || \
+ defined(CONFIG_ALPHA_EB164)
+ init_IRQ_35();
#elif defined(CONFIG_ALPHA_RUFFIAN)
ruffian_init_IRQ();
-#elif NR_IRQS == 33
- init_IRQ_33();
-#elif NR_IRQS == 32
+#elif defined(CONFIG_ALPHA_DP264)
+ dp264_init_IRQ();
+#elif defined(CONFIG_ALPHA_RAWHIDE)
+ rawhide_init_IRQ();
+#elif defined(CONFIG_ALPHA_TAKARA)
+ takara_init_IRQ();
+#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
init_IRQ_32();
#elif NR_IRQS == 16
init_IRQ_16();
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov