patch-pre2.0.8 linux/arch/ppc/kernel/irq.c
Next file: linux/arch/ppc/kernel/ksyms.c
Previous file: linux/arch/ppc/kernel/include/elf/ppc.h
Back to the patch index
Back to the overall index
- Lines: 672
- Date:
Mon May 27 12:00:58 1996
- Orig file:
pre2.0.7/linux/arch/ppc/kernel/irq.c
- Orig date:
Fri Mar 1 07:50:38 1996
diff -u --recursive --new-file pre2.0.7/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
@@ -24,14 +24,19 @@
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
-#include <linux/malloc.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bitops.h>
-#define CR0_NE 32
+/*
+ * For the BeBox, interrupt numbers are 0..15 for 8259 PIC interrupts
+ * and 16..31 for other BeBox motherboard type interrupts.
+ */
+
+unsigned long isBeBox[];
+unsigned char *BeBox_IO_page;
static unsigned char cache_21 = 0xff;
static unsigned char cache_A1 = 0xff;
@@ -41,15 +46,21 @@
unsigned char mask;
int s = _disable_interrupts();
- mask = 1 << (irq_nr & 7);
- if (irq_nr < 8) {
- cache_21 |= mask;
- outb(cache_21,0x21);
- _enable_interrupts(s);
- return;
+ if (isBeBox[0] && (irq_nr >= 16))
+ {
+ BeBox_disable_irq(irq_nr);
+ } else
+ {
+ mask = 1 << (irq_nr & 7);
+ if (irq_nr < 8) {
+ cache_21 |= mask;
+ outb(cache_21,0x21);
+ } else
+ {
+ cache_A1 |= mask;
+ outb(cache_A1,0xA1);
+ }
}
- cache_A1 |= mask;
- outb(cache_A1,0xA1);
_enable_interrupts(s);
}
@@ -58,104 +69,143 @@
unsigned char mask;
int s = _disable_interrupts();
- mask = ~(1 << (irq_nr & 7));
- if (irq_nr < 8) {
- cache_21 &= mask;
- outb(cache_21,0x21);
+ if (isBeBox[0] && (irq_nr >= 16))
+ {
+ BeBox_enable_irq(irq_nr);
_enable_interrupts(s);
return;
+ } else
+ {
+ mask = ~(1 << (irq_nr & 7));
+ if (irq_nr < 8) {
+ cache_21 &= mask;
+ outb(cache_21,0x21);
+ } else
+ {
+ cache_A1 &= mask;
+ outb(cache_A1,0xA1);
+ }
}
- cache_A1 &= mask;
- outb(cache_A1,0xA1);
_enable_interrupts(s);
}
/*
* Irq handlers.
*/
-static struct irqaction timer_irq = { NULL, 0, 0, NULL, NULL, NULL};
-static struct irqaction cascade_irq = { NULL, 0, 0, NULL, NULL, NULL};
-static struct irqaction math_irq = { NULL, 0, 0, NULL, NULL, NULL};
-
-static struct irqaction *irq_action[16] = {
- NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL
+struct irq_action {
+ void (*handler)(int, void *dev, struct pt_regs *);
+ unsigned long flags;
+ unsigned long mask;
+ const char *name;
+ int notified;
+ void *dev_id;
+};
+
+static struct irq_action irq_action[32] = {
+ { 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 },
+ { 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 }
};
int get_irq_list(char *buf)
{
int i, len = 0;
- struct irqaction * action;
+ struct irq_action * action = irq_action;
- for (i = 0 ; i < 16 ; i++) {
- action = *(i + irq_action);
- if (!action)
- continue;
- len += sprintf(buf+len, "%2d: %8d %c %s",
+ for (i = 0; i < 132; i++, action++) {
+ if (!action->handler)
+ continue;
+ len += sprintf(buf+len, "%2d: %8d %c %s\n",
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;
}
asmlinkage void handle_IRQ(struct pt_regs *regs)
{
- int irq, s;
- struct irqaction * action;
+ int irq, _irq, s;
+ struct irq_action *action;
intr_count++;
- /* Figure out IRQ#, etc. */
- outb(0x0C, 0x20); /* Poll interrupt controller */
- irq = inb(0x20);
- irq &= 0x07; /* Caution! */
- if (irq == 2)
- { /* Cascaded interrupt -> IRQ8..IRQ15 */
- outb(0x0C, 0xA0);
- irq = inb(0xA0) & 0x07;
- irq += 8;
- }
- /* Mask interrupt & Issue EOI to interrupt controller */
- if (irq > 7)
- {
- outb(cache_A1 | (1<<(irq-7)), 0xA1);
- outb(0x20, 0xA0);
- /* Need to ack cascade controller as well */
- outb(0x20, 0x20);
- } else
+ if (!isBeBox[0] || ((irq = BeBox_irq()) < 16))
{
- outb(cache_21 | (1<<irq), 0x21);
- outb(0x20, 0x20);
+ /* Figure out IRQ#, etc. */
+ outb(0x0C, 0x20); /* Poll interrupt controller */
+ irq = _irq = inb(0x20);
+ irq &= 0x07; /* Caution! */
+ if (irq == 2)
+ { /* Cascaded interrupt -> IRQ8..IRQ15 */
+ outb(0x0C, 0xA0);
+ irq = (_irq = inb(0xA0)) & 0x07;
+ irq += 8;
+ }
+ /* Mask interrupt & Issue EOI to interrupt controller */
+ if (irq > 7)
+ {
+ cache_A1 |= (1<<(irq-8));
+ outb(cache_A1, 0xA1);
+#if 0
+ outb(0x20, 0xA0);
+ /* Need to ack cascade controller as well */
+ outb(0x20, 0x20);
+#else
+ outb(0x60|(irq-8), 0xA0); /* Specific EOI */
+ /* Need to ack cascade controller as well */
+ outb(0x62, 0x20);
+#endif
+ } else
+ {
+ cache_21 |= (1<<irq);
+ outb(cache_21, 0x21);
+ outb(0x20, 0x20);
+ }
}
- action = *(irq + irq_action);
+ action = irq + irq_action;
kstat.interrupts[irq]++;
- while (action) {
- if (action->handler)
- {
+ if (action->handler)
+ {
action->handler(irq, action->dev_id, regs);
- } else
- {
- _printk("Bogus interrupt #%d\n", irq);
- }
- action = action->next;
+ } else
+ {
+ printk("Bogus interrupt #%d/%x, PC: %x\n", irq, _irq, regs->nip);
}
if (_disable_interrupts() && !action->notified)
{
action->notified = 1;
printk("*** WARNING! %s handler [IRQ %d] turned interrupts on!\n", action->name, irq);
}
- /* Re-enable interrupt */
- if (irq > 7)
+ if (irq < 16)
{
- outb(cache_A1, 0xA1);
+ if (!(action->flags & SA_ONESHOT))
+ {
+ /* Re-enable interrupt */
+ if (irq > 7)
+ {
+ cache_A1 &= ~(1<<(irq-8));
+ outb(cache_A1, 0xA1);
+ } else
+ {
+ cache_21 &= ~(1<<irq);
+ outb(cache_21, 0x21);
+ }
+ }
} else
{
- outb(cache_21, 0x21);
+ BeBox_enable_irq(irq);
}
intr_count--;
}
@@ -169,10 +219,15 @@
* Re-initializing the interrupt controller [which might lose some
* pending edge detected interrupts] seems to fix it.
*/
-void check_irq(void )
+check_irq()
{
- int s = _disable_interrupts();
+ int s;
unsigned char _a0, _a1, _20, _21;
+ if (isBeBox[0])
+ {
+ return;
+ }
+ s = _disable_interrupts();
_a1 = inb(0xA1);
_21 = inb(0x21);
outb(0x0C, 0x20); _20 = inb(0x20);
@@ -201,15 +256,10 @@
_enable_interrupts(s);
}
-#define SA_PROBE SA_ONESHOT
-
-int request_irq(unsigned int irq,
- void (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags,
- const char * devname,
- void *dev_id)
+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, *tmp = NULL;
+ struct irq_action * action;
unsigned long flags;
#if 0
@@ -217,77 +267,33 @@
cnpause();
#endif
if (irq > 15)
- return -EINVAL;
- if (!handler)
- return -EINVAL;
- action = *(irq + irq_action);
- if (action) {
- if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
- for (tmp = action; tmp->next; tmp = tmp->next);
- } else {
- return -EBUSY;
- }
- if ((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
- printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq);
- return -EBUSY;
- }
+ {
+ if (!isBeBox[0] || (irq > 31))
+ return -EINVAL;
}
+ action = irq + irq_action;
+ if (action->handler)
+ return -EBUSY;
+ if (!handler)
+ return -EINVAL;
save_flags(flags);
cli();
- if (irq == 2)
- action = &cascade_irq;
- else if (irq == 13)
- action = &math_irq;
- else if (irq == TIMER_IRQ)
- action = &timer_irq;
- else
- action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
-
- if (!action) {
- restore_flags(flags);
- return -ENOMEM;
- }
-
action->handler = handler;
action->flags = irqflags;
action->mask = 0;
action->name = devname;
- action->next = NULL;
action->dev_id = dev_id;
-
- if (tmp) {
- tmp->next = action;
- } else {
- *(irq + irq_action) = action;
-#if 0
- if (!(action->flags & SA_PROBE)) { /* SA_ONESHOT is used by probing */
- if (action->flags & SA_INTERRUPT)
- set_intr_gate(0x20+irq,fast_interrupt[irq]);
- else
- set_intr_gate(0x20+irq,interrupt[irq]);
- }
-#endif
- if (irq < 8) {
- 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);
restore_flags(flags);
return 0;
}
void free_irq(unsigned int irq, void *dev_id)
{
- struct irqaction * action = *(irq + irq_action);
- struct irqaction * tmp = NULL;
+ struct irq_action * action = irq + irq_action;
unsigned long flags;
- if (irq > 15) {
+ if (irq > 31) {
printk("Trying to free IRQ%d\n",irq);
return;
}
@@ -295,51 +301,27 @@
printk("Trying to free free IRQ%d\n",irq);
return;
}
- if (dev_id) {
- for (; action; action = action->next) {
- if (action->dev_id == dev_id) break;
- tmp = action;
- }
- if (!action) {
- printk("Trying to free free shared IRQ%d\n",irq);
- return;
- }
- } else if (action->flags & SA_SHIRQ) {
- printk("Trying to free shared IRQ%d with NULL device ID\n", irq);
- return;
- }
+ disable_irq(irq);
save_flags(flags);
cli();
- if (action && tmp) {
- tmp->next = action->next;
- } else {
- *(irq + irq_action) = action->next;
- }
-
- if ((irq == 2) || (irq == 13) | (irq == TIMER_IRQ))
- memset(action, 0, sizeof(struct irqaction));
- else
- kfree_s(action, sizeof(struct irqaction));
-
- if (!(*(irq + irq_action))) {
- if (irq < 8) {
- cache_21 |= 1 << irq;
- outb(cache_21,0x21);
- } else {
- cache_A1 |= 1 << (irq-8);
- outb(cache_A1,0xA1);
- }
-#if 0
- set_intr_gate(0x20+irq,bad_interrupt[irq]);
-#endif
- }
-
+ action->handler = NULL;
+ action->flags = 0;
+ action->mask = 0;
+ action->name = NULL;
+ action->dev_id = NULL;
restore_flags(flags);
}
-static void no_action(int cpl, void *dev_id, struct pt_regs * regs) { }
+#define SA_PROBE SA_ONESHOT
+
+static void no_action(int irq, void *dev, struct pt_regs * regs)
+{
+#ifdef DEBUG
+ printk("Probe got IRQ: %d\n", irq);
+#endif
+}
-unsigned /*int*/ long probe_irq_on (void)
+unsigned long probe_irq_on (void)
{
unsigned int i, irqs = 0, irqmask;
unsigned long delay;
@@ -369,7 +351,7 @@
return irqs;
}
-int probe_irq_off (unsigned /*int*/ long irqs)
+int probe_irq_off (unsigned long irqs)
{
unsigned int i, irqmask;
@@ -390,16 +372,9 @@
i = -i;
return i;
}
-
+
void init_IRQ(void)
{
- unsigned long *vme2_ie = (unsigned long *)0xFEFF006C;
- unsigned long *vme2_ic = (unsigned long *)0xFEFF0074;
- unsigned long *vme2_il2 = (unsigned long *)0xFEFF007C;
- unsigned long *vme2_ioc = (unsigned long *)0xFEFF0088;
- unsigned char *vme2pci_ic = (unsigned char *)0x80802050;
- unsigned char *ibc_pirq = (unsigned char *)0x80800860;
- unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
int i;
/* set the clock to 100 Hz */
@@ -410,33 +385,171 @@
printk("Unable to get IRQ2 for cascade\n");
request_region(0x20,0x20,"pic1");
request_region(0xa0,0x20,"pic2");
-#if 0
- /* Enable SIG0 */
- *vme2_ie = (*vme2_ie & 0xFFFBFFFF) | 0x00040000;
- /* Clear any pending interrupts */
- *vme2_ic = 0xFFFFFFFF;
- /* SIG0 -> Level 5 */
- *vme2_il2 = (*vme2_il2 & 0xFFFFF0FF) | 0x00000500;
- /* Master interrupt enable */
- *vme2_ioc |= 0x00800000;
+
+ /* Set up PCI interrupts */
+ route_PCI_interrupts();
+
+ if (isBeBox[0])
+ {
+ BeBox_init_IRQ();
+ }
+}
+
+/*
+ * Wrapper for "bottom 1/2" of interrupt processing. This routine
+ * is called whenever an interrupt needs non-interrupt-time service.
+ */
+
+_do_bottom_half()
+{
+ _enable_interrupts(1);
+ do_bottom_half();
+ _disable_interrupts();
+}
+
+
+/*
+ * Support for interrupts on the BeBox
+ */
+
+#define CPU0_INT_MASK (volatile unsigned long *)(BeBox_IO_page+0x0F0)
+#define CPU1_INT_MASK (volatile unsigned long *)(BeBox_IO_page+0x1F0)
+#define INT_SOURCE (volatile unsigned long *)(BeBox_IO_page+0x2F0)
+#define CPU_RESET (volatile unsigned long *)(BeBox_IO_page+0x4F0)
+
+#define CPU_HRESET 0x20000000
+#define CPU_SRESET 0x40000000
+
+#define SCSI_IRQ 16
+
+#define INT_SCSI (1<<21)
+#define INT_8259 (1<<5)
+
+/*
+ * Map of pseudo IRQs to actual bits
+ * Note: We give out IRQ #16..31 for all interrupt sources which are
+ * not found in the 8259 PIC.
+ */
+
+unsigned long BeBox_IRQ_map[] =
+ {
+ INT_SCSI, /* 16 - SCSI */
+ 0x00000000, /* 17 - Unused */
+ 0x00000000, /* 18 - Unused */
+ 0x00000000, /* 19 - Unused */
+ 0x00000000, /* 20 - Unused */
+ 0x00000000, /* 21 - Unused */
+ 0x00000000, /* 22 - Unused */
+ 0x00000000, /* 23 - Unused */
+ 0x00000000, /* 24 - Unused */
+ 0x00000000, /* 25 - Unused */
+ 0x00000000, /* 26 - Unused */
+ 0x00000000, /* 27 - Unused */
+ 0x00000000, /* 28 - Unused */
+ 0x00000000, /* 29 - Unused */
+ 0x00000000, /* 30 - Unused */
+ 0x00000000, /* 31 - Unused */
+ };
+
+volatile int CPU1_alive;
+volatile int CPU1_trace;
+
+static
+_NOP()
+{
+}
+
+static
+_delay()
+{
+ int i;
+ for (i = 0; i < 100; i++) _NOP();
+}
+
+void
+BeBox_init_IRQ(void)
+{
+ int tmr;
+ volatile extern long BeBox_CPU1_vector;
+ *CPU0_INT_MASK = 0x0FFFFFFC; /* Clear all bits? */
+ *CPU0_INT_MASK = 0x80000003 | INT_8259;
+ *CPU1_INT_MASK = 0x0FFFFFFC;
+printk("Start CPU #1 - CPU Status: %x\n", *CPU_RESET);
+ BeBox_CPU1_vector = 0x0100; /* Reset */
+ tmr = 0;
+ while (CPU1_alive == 0)
+ {
+ if (++tmr == 1000)
+ {
+printk("CPU #1 not there? - CPU Status: %x, Trace: %x\n", *CPU_RESET, CPU1_trace);
+ break;
+ }
+ _delay();
+ }
+printk("CPU #1 running!\n");
+#if 0
+/* Temp - for SCSI */
+ *(unsigned char *)0x81000038 = 0x00;
+ *(unsigned char *)0x8080103C = 0xFF;
+ *(unsigned char *)0x8080100D = 0x32;
#endif
- /* Enable interrupts from VMECHIP */
- *vme2pci_ic |= 0x08;
- /* Route PCI interrupts */
- ibc_pirq[0] = 0x0A; /* PIRQ0 -> ISA10 */
- ibc_pirq[1] = 0x0B; /* PIRQ1 -> ISA11 */
- ibc_pirq[2] = 0x0E; /* PIRQ2 -> ISA14 */
- ibc_pirq[3] = 0x0F; /* PIRQ3 -> ISA15 */
- /* Enable PCI interrupts */
- *ibc_pcicon |= 0x20;
-}
+}
+
+void
+BeBox_disable_irq(int irq)
+{
+ /* Note: this clears the particular bit */
+ *CPU0_INT_MASK = BeBox_IRQ_map[irq-16];
+}
-PCI_irq(int irq)
+void
+BeBox_enable_irq(int irq)
{
- static short _irq[] = {10, 11, 14, 15};
- int res = _irq[(irq-1)&0x03];
+ int s = _disable_interrupts();
+ /* Sets a single bit */
#if 0
- _printk("PCI IRQ #%d = %d\n", irq, res);
+printk("BeBox IRQ Mask = %x", *CPU0_INT_MASK);
+#endif
+ *CPU0_INT_MASK = 0x80000000 | BeBox_IRQ_map[irq-16];
+#if 0
+printk("/%x\n", *CPU0_INT_MASK);
#endif
- return (res);
+ _enable_interrupts(s);
+}
+
+int
+BeBox_irq(void)
+{
+ int i;
+ unsigned long cpu0_int_mask;
+ unsigned long int_state;
+ cpu0_int_mask = (*CPU0_INT_MASK & 0x0FFFFFFC) & ~INT_8259;
+ int_state = cpu0_int_mask & *INT_SOURCE;
+ if (int_state)
+ { /* Determine the pseudo-interrupt # */
+#if 0
+ printk("Ints[%x] = %x, Mask[%x] = %x/%x, State = %x\n", INT_SOURCE, *INT_SOURCE, CPU0_INT_MASK, *CPU0_INT_MASK, cpu0_int_mask, int_state);
+#endif
+ for (i = 0; i < 16; i++)
+ {
+ if (BeBox_IRQ_map[i] & int_state)
+ {
+ return (i+16);
+ }
+ }
+printk("Ints[%x] = %x, Mask[%x] = %x/%x, State = %x\n", INT_SOURCE, *INT_SOURCE, CPU0_INT_MASK, *CPU0_INT_MASK, cpu0_int_mask, int_state);
+printk("Can't find BeBox IRQ!\n");
+ }
+ return (0);
+}
+
+BeBox_state()
+{
+ printk("Int state = %x, CPU0 mask = %x, CPU1 mask = %x\n", *INT_SOURCE, *CPU0_INT_MASK, *CPU1_INT_MASK);
+}
+
+BeBox_CPU1()
+{
+ CPU1_alive++;
+ while (1) ;
}
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