summaryrefslogtreecommitdiffstats
path: root/arch/alpha/kernel/irq.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-01-07 02:33:00 +0000
committer <ralf@linux-mips.org>1997-01-07 02:33:00 +0000
commitbeb116954b9b7f3bb56412b2494b562f02b864b1 (patch)
tree120e997879884e1b9d93b265221b939d2ef1ade1 /arch/alpha/kernel/irq.c
parent908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff)
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'arch/alpha/kernel/irq.c')
-rw-r--r--arch/alpha/kernel/irq.c725
1 files changed, 528 insertions, 197 deletions
diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c
index a59077539..a769a37be 100644
--- a/arch/alpha/kernel/irq.c
+++ b/arch/alpha/kernel/irq.c
@@ -17,6 +17,8 @@
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
+#include <linux/malloc.h>
+#include <linux/random.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -24,178 +26,249 @@
#include <asm/bitops.h>
#include <asm/dma.h>
-static unsigned char cache_21 = 0xff;
-static unsigned char cache_A1 = 0xff;
+extern void timer_interrupt(struct pt_regs * regs);
+
+#if NR_IRQS > 64
+# error Unable to handle more than 64 irq levels.
+#endif
+
+/* Reserved interrupts. These must NEVER be requested by any driver!
+ */
+#define IS_RESERVED_IRQ(irq) ((irq)==2) /* IRQ 2 used by hw cascade */
+
+/*
+ * Shadow-copy of masked interrupts.
+ * The bits are used as follows:
+ * 0.. 7 first (E)ISA PIC (irq level 0..7)
+ * 8..15 second (E)ISA PIC (irq level 8..15)
+ * Systems with PCI interrupt lines managed by GRU (e.g., Alcor, XLT):
+ * 16..47 PCI interrupts 0..31 (int at GRU_INT_MASK)
+ * Mikasa:
+ * 16..31 PCI interrupts 0..15 (short at I/O port 536)
+ * Other systems (not Mikasa) with 16 PCI interrupt lines:
+ * 16..23 PCI interrupts 0.. 7 (char at I/O port 26)
+ * 24..31 PCI interrupts 8..15 (char at I/O port 27)
+ * Systems with 17 PCI interrupt lines (e.g., Cabriolet and eb164):
+ * 16..32 PCI interrupts 0..31 (int at I/O port 804)
+ */
+static unsigned long irq_mask = ~0UL;
+
+
+/*
+ * Update the hardware with the irq mask passed in MASK. The function
+ * exploits the fact that it is known that only bit IRQ has changed.
+ */
+static void update_hw(unsigned long irq, unsigned long mask)
+{
+ switch (irq) {
+#if NR_IRQS == 48
+ default:
+ /* note inverted sense of mask bits: */
+ *(unsigned int *)GRU_INT_MASK = ~(mask >> 16); mb();
+ break;
+
+#elif NR_IRQS == 33
+ default:
+ outl(mask >> 16, 0x804);
+ break;
+
+#elif defined(CONFIG_ALPHA_MIKASA)
+ default:
+ outw(~(mask >> 16), 0x536); /* note invert */
+ break;
+
+#elif NR_IRQS == 32
+ case 16 ... 23:
+ outb(mask >> 16, 0x26);
+ break;
+
+ default:
+ outb(mask >> 24, 0x27);
+ break;
+#endif
+ /* handle ISA irqs last---fast devices belong on PCI... */
+
+ case 0 ... 7: /* ISA PIC1 */
+ outb(mask, 0x21);
+ break;
+
+ case 8 ...15: /* ISA PIC2 */
+ outb(mask >> 8, 0xA1);
+ break;
+ }
+}
+
+static inline void mask_irq(unsigned long irq)
+{
+ irq_mask |= (1UL << irq);
+ update_hw(irq, irq_mask);
+}
+
+static inline void unmask_irq(unsigned long irq)
+{
+ irq_mask &= ~(1UL << irq);
+ update_hw(irq, irq_mask);
+}
void disable_irq(unsigned int irq_nr)
{
unsigned long flags;
- unsigned char mask;
- mask = 1 << (irq_nr & 7);
save_flags(flags);
- if (irq_nr < 8) {
- cli();
- cache_21 |= mask;
- outb(cache_21,0x21);
- restore_flags(flags);
- return;
- }
cli();
- cache_A1 |= mask;
- outb(cache_A1,0xA1);
+ mask_irq(irq_nr);
restore_flags(flags);
}
void enable_irq(unsigned int irq_nr)
{
unsigned long flags;
- unsigned char mask;
- mask = ~(1 << (irq_nr & 7));
save_flags(flags);
- if (irq_nr < 8) {
- cli();
- cache_21 &= mask;
- outb(cache_21,0x21);
- restore_flags(flags);
- return;
- }
cli();
- cache_A1 &= mask;
- outb(cache_A1,0xA1);
+ unmask_irq(irq_nr);
restore_flags(flags);
}
/*
* Initial irq handlers.
*/
-struct irqaction {
- void (*handler)(int, struct pt_regs *);
- unsigned long flags;
- unsigned long mask;
- const char *name;
-};
-
-static struct irqaction irq_action[16] = {
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
-};
+static struct irqaction *irq_action[NR_IRQS];
int get_irq_list(char *buf)
{
int i, len = 0;
- struct irqaction * action = irq_action;
+ struct irqaction * action;
- for (i = 0 ; i < 16 ; i++, action++) {
- if (!action->handler)
+ for (i = 0 ; i < NR_IRQS ; i++) {
+ action = irq_action[i];
+ if (!action)
continue;
- len += sprintf(buf+len, "%2d: %8d %c %s\n",
+ len += sprintf(buf+len, "%2d: %8d %c %s",
i, kstat.interrupts[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;
}
static inline void ack_irq(int irq)
{
- /* ACK the interrupt making it the lowest priority */
- /* First the slave .. */
- if (irq > 7) {
- outb(0xE0 | (irq - 8), 0xa0);
- irq = 2;
- }
- /* .. then the master */
- outb(0xE0 | irq, 0x20);
-}
-
-static inline void mask_irq(int irq)
-{
- if (irq < 8) {
- cache_21 |= 1 << irq;
- outb(cache_21, 0x21);
- } else {
- cache_A1 |= 1 << (irq - 8);
- outb(cache_A1, 0xA1);
- }
-}
-
-static inline void unmask_irq(unsigned long irq)
-{
- if (irq < 8) {
- cache_21 &= ~(1 << irq);
- outb(cache_21, 0x21);
- } else {
- cache_A1 &= ~(1 << (irq - 8));
- outb(cache_A1, 0xA1);
+ if (irq < 16) {
+ /* ACK the interrupt making it the lowest priority */
+ /* First the slave .. */
+ if (irq > 7) {
+ outb(0xE0 | (irq - 8), 0xa0);
+ irq = 2;
+ }
+ /* .. then the master */
+ outb(0xE0 | irq, 0x20);
+#if defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
+ /* on ALCOR/XLT, need to dismiss interrupt via GRU */
+ *(int *)GRU_INT_CLEAR = 0x80000000; mb();
+ *(int *)GRU_INT_CLEAR = 0x00000000; mb();
+#endif /* ALCOR || XLT */
}
}
-int request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
- unsigned long irqflags, const char * devname)
+int request_irq(unsigned int irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags,
+ const char * devname,
+ void *dev_id)
{
- struct irqaction * action;
+ int shared = 0;
+ struct irqaction * action, **p;
unsigned long flags;
- if (irq > 15)
+ if (irq >= NR_IRQS)
+ return -EINVAL;
+ if (IS_RESERVED_IRQ(irq))
return -EINVAL;
- action = irq + irq_action;
- if (action->handler)
- return -EBUSY;
if (!handler)
return -EINVAL;
- save_flags(flags);
- cli();
+ p = irq_action + irq;
+ action = *p;
+ if (action) {
+ /* Can't share interrupts unless both agree to */
+ if (!(action->flags & irqflags & SA_SHIRQ))
+ return -EBUSY;
+
+ /* Can't share interrupts unless both are same type */
+ if ((action->flags ^ irqflags) & SA_INTERRUPT)
+ return -EBUSY;
+
+ /* add new interrupt at end of irq queue */
+ do {
+ p = &action->next;
+ action = *p;
+ } while (action);
+ shared = 1;
+ }
+
+ action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
+ GFP_KERNEL);
+ if (!action)
+ return -ENOMEM;
+
+ if (irqflags & SA_SAMPLE_RANDOM)
+ rand_initialize_irq(irq);
+
action->handler = handler;
action->flags = irqflags;
action->mask = 0;
action->name = devname;
- if (irq < 8) {
- if (irq) {
- cache_21 &= ~(1<<irq);
- outb(cache_21,0x21);
- }
- } else {
- cache_21 &= ~(1<<2);
- cache_A1 &= ~(1<<(irq-8));
- outb(cache_21,0x21);
- outb(cache_A1,0xA1);
- }
+ action->next = NULL;
+ action->dev_id = dev_id;
+
+ save_flags(flags);
+ cli();
+ *p = action;
+
+ if (!shared)
+ unmask_irq(irq);
+
restore_flags(flags);
return 0;
}
-
-void free_irq(unsigned int irq)
+
+void free_irq(unsigned int irq, void *dev_id)
{
- struct irqaction * action = irq + irq_action;
+ struct irqaction * action, **p;
unsigned long flags;
- if (irq > 15) {
- printk("Trying to free IRQ%d\n", irq);
+ if (irq >= NR_IRQS) {
+ printk("Trying to free IRQ%d\n",irq);
return;
}
- if (!action->handler) {
- printk("Trying to free free IRQ%d\n", irq);
+ if (IS_RESERVED_IRQ(irq)) {
+ printk("Trying to free reserved IRQ %d\n", irq);
return;
}
- save_flags(flags);
- cli();
- mask_irq(irq);
- action->handler = NULL;
- action->flags = 0;
- action->mask = 0;
- action->name = NULL;
- restore_flags(flags);
+ for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) {
+ if (action->dev_id != dev_id)
+ continue;
+
+ /* Found it - now free it */
+ save_flags(flags);
+ cli();
+ *p = action->next;
+ if (!irq[irq_action])
+ mask_irq(irq);
+ restore_flags(flags);
+ kfree(action);
+ return;
+ }
+ printk("Trying to free free IRQ%d\n",irq);
}
-static void handle_nmi(struct pt_regs * regs)
+static inline void handle_nmi(struct pt_regs * regs)
{
printk("Whee.. NMI received. Probable hardware error\n");
printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461));
@@ -203,65 +276,285 @@ static void handle_nmi(struct pt_regs * regs)
static void unexpected_irq(int irq, struct pt_regs * regs)
{
+ struct irqaction *action;
int i;
printk("IO device interrupt, irq = %d\n", irq);
printk("PC = %016lx PS=%04lx\n", regs->pc, regs->ps);
printk("Expecting: ");
for (i = 0; i < 16; i++)
- if (irq_action[i].handler)
- printk("[%s:%d] ", irq_action[i].name, i);
+ if ((action = irq_action[i]))
+ while (action->handler) {
+ printk("[%s:%d] ", action->name, i);
+ action = action->next;
+ }
printk("\n");
+#if defined(CONFIG_ALPHA_JENSEN)
printk("64=%02x, 60=%02x, 3fa=%02x 2fa=%02x\n",
inb(0x64), inb(0x60), inb(0x3fa), inb(0x2fa));
outb(0x0c, 0x3fc);
outb(0x0c, 0x2fc);
outb(0,0x61);
outb(0,0x461);
+#endif
}
static inline void handle_irq(int irq, struct pt_regs * regs)
{
- struct irqaction * action = irq + irq_action;
+ struct irqaction * action = irq_action[irq];
kstat.interrupts[irq]++;
- if (!action->handler) {
+ if (!action) {
unexpected_irq(irq, regs);
return;
}
- action->handler(irq, regs);
+ do {
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ } while (action);
}
-static void local_device_interrupt(unsigned long vector, struct pt_regs * regs)
+static inline void device_interrupt(int irq, int ack, struct pt_regs * regs)
{
- switch (vector) {
- /* com1: map to irq 4 */
- case 0x900:
- handle_irq(4, regs);
- return;
+ struct irqaction * action;
- /* com2: map to irq 3 */
- case 0x920:
- handle_irq(3, regs);
- return;
+ if ((unsigned) irq > NR_IRQS) {
+ printk("device_interrupt: unexpected interrupt %d\n", irq);
+ return;
+ }
- /* keyboard: map to irq 1 */
- case 0x980:
- handle_irq(1, regs);
- return;
+ kstat.interrupts[irq]++;
+ action = irq_action[irq];
+ /*
+ * For normal interrupts, we mask it out, and then ACK it.
+ * This way another (more timing-critical) interrupt can
+ * come through while we're doing this one.
+ *
+ * Note! A irq without a handler gets masked and acked, but
+ * never unmasked. The autoirq stuff depends on this (it looks
+ * at the masks before and after doing the probing).
+ */
+ mask_irq(ack);
+ ack_irq(ack);
+ if (!action)
+ return;
+ if (action->flags & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
+ do {
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ } while (action);
+ unmask_irq(ack);
+}
+
+#ifdef CONFIG_PCI
- /* mouse: map to irq 9 */
- case 0x990:
- handle_irq(9, regs);
+/*
+ * Handle ISA interrupt via the PICs.
+ */
+static inline void isa_device_interrupt(unsigned long vector,
+ struct pt_regs * regs)
+{
+#if defined(CONFIG_ALPHA_APECS)
+# define IACK_SC APECS_IACK_SC
+#elif defined(CONFIG_ALPHA_LCA)
+# define IACK_SC LCA_IACK_SC
+#elif defined(CONFIG_ALPHA_CIA)
+# define IACK_SC CIA_IACK_SC
+#else
+ /*
+ * This is bogus but necessary to get it to compile
+ * on all platforms. If you try to use this on any
+ * other than the intended platforms, you'll notice
+ * real fast...
+ */
+# define IACK_SC 1L
+#endif
+ int j;
+
+#if 1
+ /*
+ * Generate a PCI interrupt acknowledge cycle. The PIC will
+ * respond with the interrupt vector of the highest priority
+ * 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 &= 0xff;
+ if (j == 7) {
+ if (!(inb(0x20) & 0x80)) {
+ /* it's only a passive release... */
return;
- default:
- printk("Unknown local interrupt %lx\n", vector);
+ }
+ }
+ device_interrupt(j, j, regs);
+#else
+ unsigned long pic;
+
+ /*
+ * It seems to me that the probability of two or more *device*
+ * interrupts occurring at almost exactly the same time is
+ * pretty low. So why pay the price of checking for
+ * additional interrupts here if the common case can be
+ * handled so much easier?
+ */
+ /*
+ * The first read of gives you *all* interrupting lines.
+ * Therefore, read the mask register and and out those lines
+ * not enabled. Note that some documentation has 21 and a1
+ * write only. This is not true.
+ */
+ pic = inb(0x20) | (inb(0xA0) << 8); /* read isr */
+ pic &= ~irq_mask; /* apply mask */
+ pic &= 0xFFFB; /* mask out cascade & hibits */
+
+ while (pic) {
+ j = ffz(~pic);
+ pic &= pic - 1;
+ device_interrupt(j, j, regs);
+ }
+#endif
+}
+
+#if defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
+/* we have to conditionally compile this because of GRU_xxx symbols */
+static inline void alcor_and_xlt_device_interrupt(unsigned long vector,
+ struct pt_regs * regs)
+{
+ unsigned long pld;
+ unsigned int i;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ /* read the interrupt summary register of the GRU */
+ pld = (*(unsigned int *)GRU_INT_REQ) & GRU_INT_REQ_BITS;
+
+#if 0
+ printk("[0x%08lx/0x%04x]", pld, 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 == 31) {
+ isa_device_interrupt(vector, regs);
+ } else {
+ device_interrupt(16 + i, 16 + i, regs);
+ }
+ }
+ restore_flags(flags);
+}
+#endif /* ALCOR || XLT */
+
+static inline void cabriolet_and_eb66p_device_interrupt(unsigned long vector,
+ struct pt_regs * regs)
+{
+ unsigned long pld;
+ unsigned int i;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ /* read the interrupt summary registers */
+ pld = inb(0x804) | (inb(0x805) << 8) | (inb(0x806) << 16);
+
+#if 0
+ printk("[0x%04X/0x%04X]", pld, 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 == 4) {
+ isa_device_interrupt(vector, regs);
+ } else {
+ device_interrupt(16 + i, 16 + i, regs);
+ }
+ }
+ restore_flags(flags);
+}
+
+static inline void mikasa_device_interrupt(unsigned long vector,
+ struct pt_regs * regs)
+{
+ unsigned long pld;
+ unsigned int i;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ /* read the interrupt summary registers */
+ pld = (((unsigned long) (~inw(0x534)) & 0x0000ffffUL) << 16) |
+ (((unsigned long) inb(0xa0)) << 8) |
+ ((unsigned long) inb(0x20));
+
+#if 0
+ printk("[0x%08lx]", pld);
+#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 < 16) {
+ isa_device_interrupt(vector, regs);
+ } else {
+ device_interrupt(i, i, regs);
+ }
+ }
+ restore_flags(flags);
+}
+
+static inline void eb66_and_eb64p_device_interrupt(unsigned long vector,
+ struct pt_regs * regs)
+{
+ unsigned long pld;
+ unsigned int i;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ /* read the interrupt summary registers */
+ pld = inb(0x26) | (inb(0x27) << 8);
+ /*
+ * 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 == 5) {
+ isa_device_interrupt(vector, regs);
+ } else {
+ device_interrupt(16 + i, 16 + i, regs);
+ }
}
+ restore_flags(flags);
}
+#endif /* CONFIG_PCI */
+
/*
- * The vector is 0x8X0 for EISA interrupt X, and 0x9X0 for the local
- * motherboard interrupts.. This is for the Jensen.
+ * Jensen is special: the vector is 0x8X0 for EISA interrupt X, and
+ * 0x9X0 for the local motherboard interrupts..
*
* 0x660 - NMI
*
@@ -275,80 +568,73 @@ static void local_device_interrupt(unsigned long vector, struct pt_regs * regs)
* 0x980 - keyboard
* 0x990 - mouse
*
- * The PCI version is more sane: it doesn't have the local interrupts at
- * all, and has only normal PCI interrupts from devices. Happily it's easy
- * enough to do a sane mapping from the Jensen.. Note that this means
- * that we may have to do a hardware "ack" to a different interrupt than
- * we report to the rest of the world..
+ * PCI-based systems are more sane: they don't have the local
+ * interrupts at all, and have only normal PCI interrupts from
+ * devices. Happily it's easy enough to do a sane mapping from the
+ * Jensen.. Note that this means that we may have to do a hardware
+ * "ack" to a different interrupt than we report to the rest of the
+ * world.
*/
-static void device_interrupt(unsigned long vector, struct pt_regs * regs)
+static inline void srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
{
int irq, ack;
- struct irqaction * action;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
- if (vector == 0x660) {
- handle_nmi(regs);
- return;
- }
ack = irq = (vector - 0x800) >> 4;
-#ifndef CONFIG_PCI
- if (vector >= 0x900) {
- local_device_interrupt(vector, regs);
- return;
+
+#ifdef CONFIG_ALPHA_JENSEN
+ switch (vector) {
+ case 0x660: handle_nmi(regs); return;
+ /* local device interrupts: */
+ case 0x900: handle_irq(4, regs); return; /* com1 -> irq 4 */
+ case 0x920: handle_irq(3, regs); return; /* com2 -> irq 3 */
+ case 0x980: handle_irq(1, regs); return; /* kbd -> irq 1 */
+ case 0x990: handle_irq(9, regs); return; /* mouse -> irq 9 */
+ default:
+ if (vector > 0x900) {
+ printk("Unknown local interrupt %lx\n", vector);
+ }
}
- /* irq1 is supposed to be the keyboard, silly Jensen */
+ /* irq1 is supposed to be the keyboard, silly Jensen (is this really needed??) */
if (irq == 1)
irq = 7;
-#endif
- kstat.interrupts[irq]++;
- action = irq_action + irq;
- /* quick interrupts get executed with no extra overhead */
- if (action->flags & SA_INTERRUPT) {
- action->handler(irq, regs);
- ack_irq(ack);
- return;
- }
- /*
- * For normal interrupts, we mask it out, and then ACK it.
- * This way another (more timing-critical) interrupt can
- * come through while we're doing this one.
- *
- * Note! A irq without a handler gets masked and acked, but
- * never unmasked. The autoirq stuff depends on this (it looks
- * at the masks before and after doing the probing).
- */
- mask_irq(ack);
- ack_irq(ack);
- if (!action->handler)
- return;
- action->handler(irq, regs);
- unmask_irq(ack);
+#endif /* CONFIG_ALPHA_JENSEN */
+
+ device_interrupt(irq, ack, regs);
+
+ restore_flags(flags) ;
}
/*
* Start listening for interrupts..
*/
-unsigned int probe_irq_on(void)
+unsigned long probe_irq_on(void)
{
- unsigned int i, irqs = 0, irqmask;
+ struct irqaction * action;
+ unsigned long irqs = 0;
unsigned long delay;
+ unsigned int i;
- for (i = 15; i > 0; i--) {
- if (!irq_action[i].handler) {
+ for (i = NR_IRQS - 1; i > 0; i--) {
+ action = irq_action[i];
+ if (!action) {
enable_irq(i);
irqs |= (1 << i);
}
}
-
- /* wait for spurious interrupts to mask themselves out again */
+ /*
+ * Wait about 100ms for spurious interrupts to mask themselves
+ * out again...
+ */
for (delay = jiffies + HZ/10; delay > jiffies; )
- /* about 100 ms delay */;
-
+ barrier();
+
/* now filter out any obviously spurious interrupts */
- irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int) cache_21;
- irqs &= ~irqmask;
- return irqs;
+ return irqs & ~irq_mask;
}
/*
@@ -356,23 +642,39 @@ unsigned int probe_irq_on(void)
* we have several candidates (but we return the lowest-numbered
* one).
*/
-int probe_irq_off(unsigned int irqs)
+int probe_irq_off(unsigned long irqs)
{
- unsigned int i, irqmask;
+ int i;
- irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
- irqs &= irqmask;
+ irqs &= irq_mask & ~1; /* always mask out irq 0---it's the unused timer */
+#ifdef CONFIG_ALPHA_P2K
+ irqs &= ~(1 << 8); /* mask out irq 8 since that's the unused RTC input to PIC */
+#endif
if (!irqs)
return 0;
i = ffz(~irqs);
- if (irqs != (1 << i))
+ if (irqs != (1UL << i))
i = -i;
return i;
}
-static void machine_check(unsigned long vector, unsigned long la_ptr, struct pt_regs * regs)
+static void machine_check(unsigned long vector, unsigned long la, struct pt_regs * regs)
{
+#if defined(CONFIG_ALPHA_LCA)
+ extern void lca_machine_check (unsigned long vector, unsigned long la,
+ struct pt_regs *regs);
+ lca_machine_check(vector, la, regs);
+#elif defined(CONFIG_ALPHA_APECS)
+ extern void apecs_machine_check(unsigned long vector, unsigned long la,
+ struct pt_regs * regs);
+ apecs_machine_check(vector, la, regs);
+#elif defined(CONFIG_ALPHA_CIA)
+ extern void cia_machine_check(unsigned long vector, unsigned long la,
+ struct pt_regs * regs);
+ cia_machine_check(vector, la, regs);
+#else
printk("Machine check\n");
+#endif
}
asmlinkage void do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr,
@@ -384,14 +686,26 @@ asmlinkage void do_entInt(unsigned long type, unsigned long vector, unsigned lon
printk("Interprocessor interrupt? You must be kidding\n");
break;
case 1:
- /* timer interrupt.. */
- handle_irq(0, &regs);
+ timer_interrupt(&regs);
return;
case 2:
machine_check(vector, la_ptr, &regs);
- break;
+ return;
case 3:
- device_interrupt(vector, &regs);
+#if defined(CONFIG_ALPHA_JENSEN) || defined(CONFIG_ALPHA_NONAME) || \
+ defined(CONFIG_ALPHA_P2K) || defined(CONFIG_ALPHA_SRM)
+ srm_device_interrupt(vector, &regs);
+#elif NR_IRQS == 48
+ alcor_and_xlt_device_interrupt(vector, &regs);
+#elif NR_IRQS == 33
+ cabriolet_and_eb66p_device_interrupt(vector, &regs);
+#elif defined(CONFIG_ALPHA_MIKASA)
+ mikasa_device_interrupt(vector, &regs);
+#elif NR_IRQS == 32
+ eb66_and_eb64p_device_interrupt(vector, &regs);
+#elif NR_IRQS == 16
+ isa_device_interrupt(vector, &regs);
+#endif
return;
case 4:
printk("Performance counter interrupt\n");
@@ -411,4 +725,21 @@ void init_IRQ(void)
dma_outb(0, DMA2_RESET_REG);
dma_outb(0, DMA1_CLR_MASK_REG);
dma_outb(0, DMA2_CLR_MASK_REG);
+#if NR_IRQS == 48
+ *(unsigned int *)GRU_INT_MASK = ~(irq_mask >> 16); mb();/* invert */
+ *(unsigned int *)GRU_INT_EDGE = 0UL; mb();/* all are level */
+ *(unsigned int *)GRU_INT_HILO = 0x80000000UL; mb();/* ISA only HI */
+ *(unsigned int *)GRU_INT_CLEAR = 0UL; mb();/* all clear */
+ enable_irq(16 + 31); /* enable (E)ISA PIC cascade */
+#elif NR_IRQS == 33
+ outl(irq_mask >> 16, 0x804);
+ enable_irq(16 + 4); /* enable SIO cascade */
+#elif defined(CONFIG_ALPHA_MIKASA)
+ outw(~(irq_mask >> 16), 0x536); /* note invert */
+#elif NR_IRQS == 32
+ outb(irq_mask >> 16, 0x26);
+ outb(irq_mask >> 24, 0x27);
+ enable_irq(16 + 5); /* enable SIO cascade */
+#endif
+ enable_irq(2); /* enable cascade */
}