patch-1.3.22 linux/arch/alpha/kernel/irq.c
Next file: linux/arch/alpha/kernel/lca.c
Previous file: linux/arch/alpha/kernel/entry.S
Back to the patch index
Back to the overall index
- Lines: 611
- Date:
Tue Aug 29 10:15:48 1995
- Orig file:
v1.3.21/linux/arch/alpha/kernel/irq.c
- Orig date:
Fri Jun 16 22:02:54 1995
diff -u --recursive --new-file v1.3.21/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c
@@ -27,23 +27,53 @@
static unsigned char cache_21 = 0xff;
static unsigned char cache_A1 = 0xff;
+#if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
+ static unsigned char cache_804 = 0xef;
+ static unsigned char cache_805 = 0xff;
+ static unsigned char cache_806 = 0xff;
+# define NUM_IRQS 33
+#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
+ static unsigned char cache_26 = 0xdf;
+ static unsigned char cache_27 = 0xff;
+# define NUM_IRQS 32
+#else
+# define NUM_IRQS 16
+#endif
+
void disable_irq(unsigned int irq_nr)
{
unsigned long flags;
unsigned char mask;
- mask = 1 << (irq_nr & 7);
save_flags(flags);
+ cli();
+ mask = 1 << (irq_nr & 7);
+
if (irq_nr < 8) {
- cli();
cache_21 |= mask;
outb(cache_21,0x21);
- restore_flags(flags);
- return;
+ } else if (irq_nr < 16) {
+ cache_A1 |= mask;
+ outb(cache_A1,0xA1);
+#if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
+ } else if (irq_nr < 24) {
+ cache_804 |= mask;
+ outb(cache_804, 0x804);
+ } else if (irq_nr < 32) {
+ cache_805 |= mask;
+ outb(cache_805, 0x805);
+ } else {
+ cache_806 |= mask;
+ outb(cache_806, 0x806);
+#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
+ } else if (irq_nr < 24) {
+ cache_26 |= mask;
+ outb(cache_26, 0x26);
+ } else {
+ cache_27 |= mask;
+ outb(cache_27, 0x27);
+#endif
}
- cli();
- cache_A1 |= mask;
- outb(cache_A1,0xA1);
restore_flags(flags);
}
@@ -54,16 +84,33 @@
mask = ~(1 << (irq_nr & 7));
save_flags(flags);
+ cli();
+
if (irq_nr < 8) {
- cli();
cache_21 &= mask;
outb(cache_21,0x21);
- restore_flags(flags);
- return;
+ } else if (irq_nr < 16) {
+ cache_A1 &= mask;
+ outb(cache_A1,0xA1);
+#if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
+ } else if (irq_nr < 24) {
+ cache_804 &= mask;
+ outb(cache_804, 0x804);
+ } else if (irq_nr < 32) {
+ cache_805 &= mask;
+ outb(cache_805, 0x805);
+ } else {
+ cache_806 &= mask;
+ outb(cache_806, 0x806);
+#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
+ } else if if (irq_nr < 24) {
+ cache_26 &= mask;
+ outb(cache_26, 0x26);
+ } else {
+ cache_27 &= mask;
+ outb(cache_27, 0x27);
+#endif
}
- cli();
- cache_A1 &= mask;
- outb(cache_A1,0xA1);
restore_flags(flags);
}
@@ -77,23 +124,14 @@
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[NUM_IRQS];
int get_irq_list(char *buf)
{
int i, len = 0;
struct irqaction * action = irq_action;
- for (i = 0 ; i < 16 ; i++, action++) {
+ for (i = 0 ; i < NUM_IRQS ; i++, action++) {
if (!action->handler)
continue;
len += sprintf(buf+len, "%2d: %8d %c %s\n",
@@ -106,35 +144,78 @@
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;
+ 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);
}
- /* .. then the master */
- outb(0xE0 | irq, 0x20);
}
static inline void mask_irq(int irq)
{
+ unsigned char mask;
+
+ mask = 1 << (irq & 7);
if (irq < 8) {
- cache_21 |= 1 << irq;
+ cache_21 |= mask;
outb(cache_21, 0x21);
- } else {
- cache_A1 |= 1 << (irq - 8);
+ } else if (irq < 16) {
+ cache_A1 |= mask;
outb(cache_A1, 0xA1);
+#if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
+ } else if (irq < 24) {
+ cache_804 |= mask;
+ outb(cache_804, 0x804);
+ } else if (irq < 32) {
+ cache_805 |= mask;
+ outb(cache_805, 0x805);
+ } else {
+ cache_806 |= mask;
+ outb(cache_806, 0x806);
+#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB66P)
+ } else if (irq < 24) {
+ cache_26 |= mask;
+ outb(cache_26, 0x26);
+ } else {
+ cache_27 |= mask;
+ outb(cache_27, 0x27);
+#endif
}
}
static inline void unmask_irq(unsigned long irq)
{
+ unsigned char mask = ~(1 << (irq & 7));
+
if (irq < 8) {
- cache_21 &= ~(1 << irq);
+ cache_21 &= mask;
outb(cache_21, 0x21);
- } else {
- cache_A1 &= ~(1 << (irq - 8));
+ } else if (irq < 16) {
+ cache_A1 &= mask;
outb(cache_A1, 0xA1);
+#if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
+ } else if (irq < 24) {
+ cache_804 &= mask;
+ outb(cache_804, 0x804);
+ } else if (irq < 32) {
+ cache_805 &= mask;
+ outb(cache_805, 0x805);
+ } else {
+ cache_806 &= mask;
+ outb(cache_806, 0x806);
+#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB66P)
+ } else if (irq < 24) {
+ cache_26 &= mask;
+ outb(cache_26, 0x26);
+ } else {
+ cache_27 &= mask;
+ outb(cache_27, 0x27);
+#endif
}
}
@@ -144,7 +225,7 @@
struct irqaction * action;
unsigned long flags;
- if (irq > 15)
+ if (irq >= NUM_IRQS)
return -EINVAL;
action = irq + irq_action;
if (action->handler)
@@ -157,16 +238,9 @@
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);
+ enable_irq(irq);
+ if (irq >= 8 && irq < 16) {
+ enable_irq(2); /* ensure cascade is enabled too */
}
restore_flags(flags);
return 0;
@@ -177,7 +251,7 @@
struct irqaction * action = irq + irq_action;
unsigned long flags;
- if (irq > 15) {
+ if (irq >= NUM_IRQS) {
printk("Trying to free IRQ%d\n", irq);
return;
}
@@ -195,7 +269,7 @@
restore_flags(flags);
}
-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));
@@ -232,40 +306,126 @@
action->handler(irq, regs);
}
-#ifndef CONFIG_PCI
+static inline void device_interrupt(int irq, int ack, struct pt_regs * regs)
+{
+ struct irqaction * action;
+
+ if ((unsigned) irq > NUM_IRQS) {
+ printk("device_interrupt: unexpected interrupt %d\n", irq);
+ return;
+ }
+
+ 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);
+}
+
+/*
+ * Handle ISA interrupt via the PICs.
+ */
+static inline void isa_device_interrupt(unsigned long vector,
+ struct pt_regs * regs)
+{
+ unsigned long pic;
+ int j;
+ /*
+ * 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 &= ~((cache_A1 << 8) | cache_21); /* apply mask */
+ pic &= 0xFFFB; /* mask out cascade */
+
+ while (pic) {
+ j = ffz(~pic);
+ pic &= pic - 1;
+ device_interrupt(j, j, regs);
+ }
+}
-static void local_device_interrupt(unsigned long vector, struct pt_regs * regs)
+static inline void cabriolet_and_eb66p_device_interrupt(unsigned long vector,
+ struct pt_regs * regs)
{
- switch (vector) {
- /* com1: map to irq 4 */
- case 0x900:
- handle_irq(4, regs);
- return;
+ unsigned long pld;
+ unsigned int i;
+ unsigned long flags;
- /* com2: map to irq 3 */
- case 0x920:
- handle_irq(3, regs);
- return;
+ save_flags(flags);
+ cli();
- /* keyboard: map to irq 1 */
- case 0x980:
- handle_irq(1, regs);
- return;
+ /* read the interrupt summary registers */
+ pld = inb(0x804) | (inb(0x805) << 8) | (inb(0x806) << 16);
- /* mouse: map to irq 9 */
- case 0x990:
- handle_irq(9, regs);
- return;
- default:
- printk("Unknown local interrupt %lx\n", vector);
+ /*
+ * 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);
}
-#endif /* !CONFIG_PCI */
+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);
+}
/*
- * 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
*
@@ -279,66 +439,55 @@
* 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;
- 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);
}
+#if NUM_IRQS > 64
+# error Number of irqs limited to 64 due to interrupt-probing.
+#endif
+
/*
* Start listening for interrupts..
*/
-unsigned int probe_irq_on(void)
+unsigned long probe_irq_on(void)
{
- unsigned int i, irqs = 0, irqmask;
+ unsigned long irqs = 0, irqmask;
unsigned long delay;
+ unsigned int i;
- for (i = 15; i > 0; i--) {
+ for (i = NUM_IRQS - 1; i > 0; i--) {
if (!irq_action[i].handler) {
enable_irq(i);
irqs |= (1 << i);
@@ -350,7 +499,15 @@
/* about 100 ms delay */;
/* now filter out any obviously spurious interrupts */
- irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int) cache_21;
+ irqmask = (((unsigned long)cache_A1)<<8) | (unsigned long) cache_21;
+#if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
+ irqmask |= ((((unsigned long)cache_804)<<16) |
+ (((unsigned long)cache_805)<<24) |
+ (((unsigned long)cache_806)<<24));
+#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
+ irqmask |= ((((unsigned long)cache_26)<<16) |
+ (((unsigned long)cache_27)<<24);
+#endif
irqs &= ~irqmask;
return irqs;
}
@@ -360,27 +517,41 @@
* 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;
+ unsigned long irqmask;
+ int i;
irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
+#if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
+ irqmask |= ((((unsigned long)cache_804)<<16) |
+ (((unsigned long)cache_805)<<24) |
+ (((unsigned long)cache_806)<<24));
+#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
+ irqmask |= ((((unsigned long)cache_26)<<16) |
+ (((unsigned long)cache_27)<<24);
+#endif
irqs &= irqmask;
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);
+#else
printk("Machine check\n");
-#ifdef LCA_MEM_ESR
- printk("esr=%lx, ear=%lx, ioc_stat0=%lx, ioc_stat1=%lx\n",
- *(unsigned long*)LCA_MEM_ESR, *(unsigned long*)LCA_MEM_EAR,
- *(unsigned long*)LCA_IOC_STAT0, *(unsigned long*)LCA_IOC_STAT1);
#endif
}
@@ -400,7 +571,13 @@
machine_check(vector, la_ptr, ®s);
break;
case 3:
- device_interrupt(vector, ®s);
+#if defined(CONFIG_ALPHA_JENSEN) || defined(CONFIG_ALPHA_NONAME)
+ srm_device_interrupt(vector, ®s);
+#elif defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
+ cabriolet_and_eb66p_device_interrupt(vector, ®s);
+#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
+ eb66_and_eb64p_device_interrupt(vector, ®s);
+#endif
return;
case 4:
printk("Performance counter interrupt\n");
@@ -420,4 +597,12 @@
dma_outb(0, DMA2_RESET_REG);
dma_outb(0, DMA1_CLR_MASK_REG);
dma_outb(0, DMA2_CLR_MASK_REG);
+#if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
+ outb(cache_804, 0x804);
+ outb(cache_805, 0x805);
+ outb(cache_806, 0x806);
+#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
+ outb(cache_26, 0x26);
+ outb(cache_27, 0x27);
+#endif
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this