patch-2.1.16 linux/arch/ppc/kernel/irq.c
Next file: linux/arch/ppc/kernel/ld.script-user
Previous file: linux/arch/ppc/kernel/include/elf/ppc.h
Back to the patch index
Back to the overall index
- Lines: 504
- Date:
Wed Dec 18 10:49:52 1996
- Orig file:
v2.1.15/linux/arch/ppc/kernel/irq.c
- Orig date:
Mon Jul 8 11:27:42 1996
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 1992 Linus Torvalds
* Adapted from arch/i386 by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
*
* This file contains the code used by various IRQ handling routines:
* asking for different IRQ's should be done through these routines
@@ -30,6 +31,24 @@
#include <asm/irq.h>
#include <asm/bitops.h>
+inline int get_irq_list(char *);
+void check_irq(void);
+void BeBox_CPU1(void);
+void BeBox_state(void);
+int BeBox_irq(void);
+void show_BeBox_state(void);
+void BeBox_enable_irq(int );
+void BeBox_disable_irq(int );
+void BeBox_init_IRQ(void);
+void _do_bottom_half(void);
+static _NOP(void);
+static _delay(void);
+void hard_disk_LED(int state);
+
+
+#define SHOW_IRQ
+#undef SHOW_IRQ
+
/*
* For the BeBox, interrupt numbers are 0..15 for 8259 PIC interrupts
* and 16..31 for other BeBox motherboard type interrupts.
@@ -52,7 +71,8 @@
} else
{
mask = 1 << (irq_nr & 7);
- if (irq_nr < 8) {
+ if (irq_nr < 8)
+ {
cache_21 |= mask;
outb(cache_21,0x21);
} else
@@ -120,150 +140,202 @@
{ NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
};
-int get_irq_list(char *buf)
-{
- int i, len = 0;
- struct irq_action * action = irq_action;
- 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);
- }
- return len;
-}
-
-asmlinkage void handle_IRQ(struct pt_regs *regs)
+inline int get_irq_list(char *buf)
{
- int irq, _irq, s;
+ int i, len = 0;
+ struct irq_action * action = irq_action;
+
+ for (i = 0; i < 32; 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);
+ }
+ return len;
+}
+
+inline void
+process_IRQ(int irq, int _irq, struct pt_regs *regs)
+{
+ struct irq_action *action;
+ intr_count++;
+ if (irq < 16)
+ {
+ /* Mask interrupt */
+ if (irq > 7)
+ {
+ cache_A1 |= (1<<(irq-8));
+ outb(cache_A1, 0xA1);
+ } else
+ {
+ cache_21 |= (1<<irq);
+ outb(cache_21, 0x21);
+ }
+ }
+ action = irq + irq_action;
+ kstat.interrupts[irq]++;
+ /* TEMP */
+ /* On the Nobis, the keyboard interrupt "edge" gets lost - why? */
+ if (irq == 0)
+ {
+ static int count;
+ if (++count == 500)
+ {
+ if (inb(0x64) & 0x01)
+ {
struct irq_action *action;
- intr_count++;
- if (!isBeBox[0] || ((irq = BeBox_irq()) < 16))
- {
- /* 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;
- kstat.interrupts[irq]++;
- if (action->handler)
- {
- action->handler(irq, action->dev_id, regs);
- } 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);
- }
- if (irq < 16)
- {
- 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
+ action = irq_action + 1; /* Keyboard */
+ printk("Reset KBD, KBSTAT = %x, ELCR = %x/%x, MASK = %x/%x\n",
+ inb(0x64), inb(0x4D0), inb(0x4D1), cache_21, cache_A1);
+ action->handler(1, action->dev_id, regs);
+ }
+ count = 0;
+ }
+ }
+ if (action->handler)
+ {
+ action->handler(irq, action->dev_id, regs);
+ } else
+ {
+ printk("Bogus interrupt %d/%x, pc %x regs %x\n",
+ irq, _irq,regs->nip,regs);
+#if 0
+ printk("BeBox[] = %x/%x\n", isBeBox[0], isBeBox[1]);
+ show_BeBox_state();
+ cnpause();
+#endif
+ }
+ if (_disable_interrupts() && !action->notified)
+ {
+ action->notified = 1;
+ printk("*** WARNING! %s handler [IRQ %d] turned interrupts on!\n",
+ action->name, irq);
+ }
+ if (irq < 16)
+ {
+ /* Issue EOI to interrupt controller */
+ if (irq > 7)
+ {
+ outb(0xE0|(irq-8), 0xA0);
+ outb(0xE2, 0x20);
+ } else
+ {
+ outb(0xE0|irq, 0x20);
+ }
+ 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
+ {
+ BeBox_enable_irq(irq);
+ }
+ intr_count--;
+}
+
+asmlinkage inline void handle_IRQ(struct pt_regs *regs)
+{
+ int irq, _irq, s;
+ struct irq_action *action;
+ static int _ints;
+
+ if (!isBeBox[0] || ((irq = BeBox_irq()) < 16))
+ {
+ /* 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;
+ }
+ }
+ process_IRQ(irq, _irq, regs);
+
+ /* Sometimes, the cascaded IRQ controller get's "stuck" */
+ if ((irq == 0) && (_ints++ == 100))
+ {
+ _ints = 0;
+ outb(0x0A, 0xA0); _irq = inb(0xA0);
+ if (_irq & ~cache_A1)
+ { /* Figure out which IRQs are present */
+ _irq &= ~cache_A1;
+ for (irq = 0; irq < 7; irq++)
+ {
+ if (_irq & (1<<irq))
{
- BeBox_enable_irq(irq);
+#if 0
+ printk("Dropped IRQ #%d\n", irq+8);
+#endif
+ process_IRQ(irq+8, _irq, regs);
}
- intr_count--;
+ }
+ }
+ }
}
/*
- * This routine gets called when the SCSI times out on an operation.
- * I don't know why this happens, but every so often it does and it
- * seems to be a problem with the interrupt controller [state]. It
- * happens a lot when there is also network activity (both devices
- * are on the PCI bus with interrupts on the cascaded controller).
- * Re-initializing the interrupt controller [which might lose some
- * pending edge detected interrupts] seems to fix it.
+ * Display current IRQ state
*/
-check_irq()
+
+void
+show_irq_state(void)
+{
+ unsigned char state_21, state_A1;
+ outb(0x0A, 0x20); state_21 = inb(0x20);
+ outb(0x0A, 0xA0); state_A1 = inb(0xA0);
+ printk("IRQ State = %x/%x, Edge = %x/%x, Processor = %d\n", state_21, state_A1, inb(0x4D0), inb(0x4D1), _Processor);
+}
+
+/*
+ * Initialize interrupt controllers to a well-known state.
+ */
+
+static void
+reset_int_controllers(void)
{
- 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);
- outb(0x0C, 0xA0); _a0 = inb(0xA0);
-#if 0
- printk("IRQ 0x20 = %x, 0x21 = %x/%x, 0xA0 = %x, 0xA1 = %x/%x\n",
- _20, _21, cache_21, _a0, _a1, cache_A1);
-#endif
- /* Reset interrupt controller - see if this fixes it! */
/* Initialize interrupt controllers */
outb(0x11, 0x20); /* Start init sequence */
outb(0x40, 0x21); /* Vector base */
outb(0x04, 0x21); /* Cascade (slave) on IRQ2 */
outb(0x01, 0x21); /* Select 8086 mode */
outb(0xFF, 0x21); /* Mask all */
- outb(0x00, 0x4D0); /* All edge triggered */
outb(0x11, 0xA0); /* Start init sequence */
outb(0x48, 0xA1); /* Vector base */
outb(0x02, 0xA1); /* Cascade (slave) on IRQ2 */
outb(0x01, 0xA1); /* Select 8086 mode */
outb(0xFF, 0xA1); /* Mask all */
+#if 0
+ outb(0x00, 0x4D0); /* All edge triggered */
outb(0xCF, 0x4D1); /* Trigger mode */
+#endif
outb(cache_A1, 0xA1);
outb(cache_21, 0x21);
enable_irq(2); /* Enable cascade interrupt */
- _enable_interrupts(s);
}
int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags, const char * devname, void *dev_id)
+ unsigned long irqflags, const char * devname, void *dev_id)
{
struct irq_action * action;
unsigned long flags;
-#if 0
-_printk("Request IRQ #%d, Handler: %x\n", irq, handler);
+#ifdef SHOW_IRQ
+if (irq) printk("Request IRQ #%d, Handler: %x\n", irq, handler);
#endif
if (irq > 15)
{
@@ -374,24 +446,33 @@
void init_IRQ(void)
{
- int i;
+ int i;
- /* set the clock to 100 Hz */
- outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
- outb_p(LATCH & 0xff , 0x40); /* LSB */
- outb(LATCH >> 8 , 0x40); /* MSB */
- if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL))
- printk("Unable to get IRQ2 for cascade\n");
- request_region(0x20,0x20,"pic1");
- request_region(0xa0,0x20,"pic2");
-
- /* Set up PCI interrupts */
- route_PCI_interrupts();
-
- if (isBeBox[0])
- {
- BeBox_init_IRQ();
- }
+ if ((_get_PVR()>>16) == 1) /* PPC 601 */
+ { /* Nobis? */
+ reset_int_controllers();
+ }
+#define TIMER0_COUNT 0x40
+#define TIMER_CONTROL 0x43
+ /* set the clock to 100 Hz */
+ outb_p(0x34,TIMER_CONTROL); /* binary, mode 2, LSB/MSB, ch 0 */
+ outb_p(LATCH & 0xff , TIMER0_COUNT); /* LSB */
+ outb(LATCH >> 8 , TIMER0_COUNT); /* MSB */
+ if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL))
+ printk("Unable to get IRQ2 for cascade\n");
+ request_region(0x20,0x20,"pic1");
+ request_region(0xa0,0x20,"pic2");
+
+ /* Make sure IRQ2 (cascade) interrupt is "level" based */
+ outb(inb(0x4D0)|0x04, 0x4D0); /* IRQ2 level based */
+
+ /* Set up PCI interrupts */
+ route_PCI_interrupts();
+
+ if (isBeBox[0])
+ {
+ BeBox_init_IRQ();
+ }
}
/*
@@ -399,11 +480,18 @@
* is called whenever an interrupt needs non-interrupt-time service.
*/
-_do_bottom_half()
+void _do_bottom_half(void)
{
- _enable_interrupts(1);
- do_bottom_half();
- _disable_interrupts();
+ _enable_interrupts(1);
+ do_bottom_half();
+ _disable_interrupts();
+}
+
+void hard_disk_LED(int state)
+{
+ if (_Processor == _PROC_IBM) {
+ outb(state, IBM_HDD_LED);
+ }
}
@@ -416,6 +504,11 @@
#define INT_SOURCE (volatile unsigned long *)(BeBox_IO_page+0x2F0)
#define CPU_RESET (volatile unsigned long *)(BeBox_IO_page+0x4F0)
+#define _CPU0_INT_MASK (volatile unsigned long *)(0xA0000000+0x0F0)
+#define _CPU1_INT_MASK (volatile unsigned long *)(0xA0000000+0x1F0)
+#define _INT_SOURCE (volatile unsigned long *)(0xA0000000+0x2F0)
+#define _CPU_RESET (volatile unsigned long *)(0xA0000000+0x4F0)
+
#define CPU_HRESET 0x20000000
#define CPU_SRESET 0x40000000
@@ -454,12 +547,12 @@
volatile int CPU1_trace;
static
-_NOP()
+_NOP(void)
{
}
static
-_delay()
+_delay(void)
{
int i;
for (i = 0; i < 100; i++) _NOP();
@@ -486,12 +579,6 @@
_delay();
}
printk("CPU #1 running!\n");
-#if 0
-/* Temp - for SCSI */
- *(unsigned char *)0x81000038 = 0x00;
- *(unsigned char *)0x8080103C = 0xFF;
- *(unsigned char *)0x8080100D = 0x32;
-#endif
}
void
@@ -516,6 +603,16 @@
_enable_interrupts(s);
}
+void
+show_BeBox_state(void)
+{
+ 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;
+ 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);
+}
+
int
BeBox_irq(void)
{
@@ -542,12 +639,12 @@
return (0);
}
-BeBox_state()
+void BeBox_state(void)
{
printk("Int state = %x, CPU0 mask = %x, CPU1 mask = %x\n", *INT_SOURCE, *CPU0_INT_MASK, *CPU1_INT_MASK);
}
-BeBox_CPU1()
+void BeBox_CPU1(void)
{
CPU1_alive++;
while (1) ;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov