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

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