patch-2.1.53 linux/arch/ppc/kernel/irq.c
Next file: linux/arch/ppc/kernel/openpic.c
Previous file: linux/arch/ppc/kernel/idle.c
Back to the patch index
Back to the overall index
- Lines: 339
- Date:
Thu Sep 4 12:54:48 1997
- Orig file:
v2.1.52/linux/arch/ppc/kernel/irq.c
- Orig date:
Mon Aug 18 18:19:44 1997
diff -u --recursive --new-file v2.1.52/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
@@ -28,18 +28,30 @@
#include <linux/config.h>
#include <linux/init.h>
#include <linux/malloc.h>
+#include <linux/openpic.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/openpic.h>
+#include <asm/hydra.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bitops.h>
#undef SHOW_IRQ
+#define OPENPIC_DEBUG
unsigned lost_interrupts = 0;
-
unsigned int local_irq_count[NR_CPUS];
-static struct irqaction irq_action[32];
+static struct irqaction irq_action[NR_IRQS];
+static int spurious_interrupts = 0;
+int __ppc_bh_counter;
+static unsigned int cached_irq_mask = 0xffffffff;
+static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
+
+#define cached_21 (((char *)(&cached_irq_mask))[3])
+#define cached_A1 (((char *)(&cached_irq_mask))[2])
/*
* These are set to the appropriate functions by init_IRQ()
@@ -47,11 +59,6 @@
void (*mask_and_ack_irq)(int irq_nr);
void (*set_irq_mask)(int irq_nr);
-static unsigned int cached_irq_mask = 0xffffffff;
-#define cached_21 (((char *)(&cached_irq_mask))[3])
-#define cached_A1 (((char *)(&cached_irq_mask))[2])
-static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
-int __ppc_bh_counter;
/* prep */
#define PREP_IRQ_MASK (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21
@@ -65,7 +72,10 @@
#define KEYBOARD_IRQ 20 /* irq number for command-power interrupt */
#define PMAC_IRQ_MASK (~ld_le32(IRQ_ENABLE))
-void prep_mask_and_ack_irq(int irq_nr)
+/* chrp */
+volatile struct Hydra *Hydra = NULL;
+
+void i8259_mask_and_ack_irq(int irq_nr)
{
spin_lock(&irq_controller_lock);
cached_irq_mask |= 1 << irq_nr;
@@ -94,7 +104,16 @@
spin_unlock(&irq_controller_lock);
}
-void prep_set_irq_mask(int irq_nr)
+void chrp_mask_and_ack_irq(int irq_nr)
+{
+ /* spinlocks are done by i8259_mask_and_ack() - Cort */
+ if (is_8259_irq(irq_nr))
+ i8259_mask_and_ack_irq(irq_nr);
+ openpic_eoi(0);
+}
+
+
+void i8259_set_irq_mask(int irq_nr)
{
if (irq_nr > 7) {
outb(cached_A1,0xA1);
@@ -116,6 +135,21 @@
lost_interrupts |= (1UL<<irq_nr);
}
+void chrp_set_irq_mask(int irq_nr)
+{
+ if (is_8259_irq(irq_nr)) {
+ i8259_set_irq_mask(irq_nr);
+ } else
+ {
+ /* disable? */
+ if ( cached_irq_mask & (1UL<<irq_nr) )
+ openpic_disable_irq(irq_to_openpic(irq_nr));
+ /* enable */
+ else
+ openpic_disable_irq(irq_to_openpic(irq_nr));
+ }
+}
+
/*
* These have to be protected by the spinlock
* before being called.
@@ -171,6 +205,8 @@
len+=sprintf(buf+len, "IPI: %8lu received\n",
ipi_count);
#endif
+ len += sprintf(buf+len, "99: %10u spurious or short\n",
+ spurious_interrupts);
return len;
}
@@ -184,13 +220,56 @@
hardirq_enter(cpu);
- if ( _machine == _MACH_Pmac )
+
+ /*
+ * I'll put this ugly mess of code into a function
+ * such as get_pending_irq() or some such clear thing
+ * so we don't have a switch in the irq code and
+ * the chrp code is merged a bit with the prep.
+ * -- Cort
+ */
+ switch ( _machine )
{
+ case _MACH_Pmac:
bits = ld_le32(IRQ_FLAG) | lost_interrupts;
lost_interrupts = 0;
- }
- else /* prep */
- {
+ for (irq = NR_IRQS - 1; irq >= 0; --irq)
+ if (bits & (1U << irq))
+ break;
+ break;
+ case _MACH_chrp:
+ irq = openpic_irq(0);
+ if (irq == IRQ_8259_CASCADE)
+ {
+ /*
+ * This magic address generates a PCI IACK cycle.
+ *
+ * This should go in the above mask/ack code soon. -- Cort
+ */
+ irq = (*(volatile unsigned char *)0xfec80000) & 0x0f;
+ }
+ else if (irq >= 64)
+ {
+ /*
+ * OpenPIC interrupts >64 will be used for other purposes
+ * like interprocessor interrupts and hardware errors
+ */
+#ifdef OPENPIC_DEBUG
+ printk("OpenPIC interrupt %d\n", irq);
+#endif
+ if (irq==99)
+ spurious_interrupts++;
+ }
+ else {
+ /*
+ * Here we should process IPI timer
+ * for now the interrupt is dismissed.
+ */
+ goto out;
+ }
+ break;
+ case _MACH_IBM:
+ case _MACH_Motorola:
#if 1
outb(0x0C, 0x20);
irq = inb(0x20) & 7;
@@ -221,13 +300,10 @@
}
/* ignore masked irqs */
bits &= ~cached_irq_mask;
-#endif
+#endif
+ break;
}
- for (irq = NR_IRQS - 1; irq >= 0; --irq)
- if (bits & (1U << irq))
- break;
-
if (irq < 0) {
printk("Bogus interrupt from PC = %lx\n", regs->nip);
goto out;
@@ -238,12 +314,12 @@
status = 0;
action = irq_action + irq;
kstat.interrupts[irq]++;
- if ( action )
+ if ( action && action->handler)
{
if (!(action->flags & SA_INTERRUPT))
__sti();
status |= action->flags;
- action->handler(irq, action->dev_id, regs);
+ action->handler(irq, action->dev_id, regs);
/*if (status & SA_SAMPLE_RANDOM)
add_interrupt_randomness(irq);*/
__cli(); /* in case the handler turned them on */
@@ -251,11 +327,13 @@
unmask_irq(irq);
spin_unlock(&irq_controller_lock);
} else {
+ if ( irq == 7 ) /* i8259 gives us irq 7 on 'short' intrs */
+ spurious_interrupts++;
disable_irq( irq );
}
/* make sure we don't miss any cascade intrs due to eoi-ing irq 2 */
- if ( (_machine != _MACH_Pmac)/*prep*/ && (irq > 7) )
+ if ( is_prep && (irq > 7) )
goto retry_cascade;
/* do_bottom_half is called if necessary from int_return in head.S */
out:
@@ -329,12 +407,37 @@
return 0;
}
+__initfunc(static void i8259_init(void))
+{
+ /* init master interrupt controller */
+ outb(0x11, 0x20); /* Start init sequence */
+ outb(0x40, 0x21); /* Vector base */
+ /*outb(0x04, 0x21);*/ /* edge tiggered, Cascade (slave) on IRQ2 */
+ outb(0x0C, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
+ outb(0x01, 0x21); /* Select 8086 mode */
+ outb(0xFF, 0x21); /* Mask all */
+
+ /* init slave interrupt controller */
+ outb(0x11, 0xA0); /* Start init sequence */
+ outb(0x48, 0xA1); /* Vector base */
+ /*outb(0x02, 0xA1);*/ /* edge triggered, Cascade (slave) on IRQ2 */
+ outb(0x0A, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
+ outb(0x01, 0xA1); /* Select 8086 mode */
+ outb(0xFF, 0xA1); /* Mask all */
+ outb(cached_A1, 0xA1);
+ outb(cached_21, 0x21);
+ if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL) != 0)
+ panic("Could not allocate cascade IRQ!");
+ enable_irq(2); /* Enable cascade interrupt */
+}
+
__initfunc(void init_IRQ(void))
{
extern void xmon_irq(int, void *, struct pt_regs *);
- if ( _machine == _MACH_Pmac )
+ switch (_machine)
{
+ case _MACH_Pmac:
mask_and_ack_irq = pmac_mask_and_ack_irq;
set_irq_mask = pmac_set_irq_mask;
@@ -342,28 +445,14 @@
#ifdef CONFIG_XMON
request_irq(KEYBOARD_IRQ, xmon_irq, 0, "NMI", 0);
#endif /* CONFIG_XMON */
- }
- else /* prep */
- {
- mask_and_ack_irq = prep_mask_and_ack_irq;
- set_irq_mask = prep_set_irq_mask;
+ break;
+ case _MACH_Motorola:
+ case _MACH_IBM:
+ mask_and_ack_irq = i8259_mask_and_ack_irq;
+ set_irq_mask = i8259_set_irq_mask;
- /* init master interrupt controller */
- outb(0x11, 0x20); /* Start init sequence */
- outb(0x40, 0x21); /* Vector base */
- /*outb(0x04, 0x21);*/ /* edge tiggered, Cascade (slave) on IRQ2 */
- outb(0x0C, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
- outb(0x01, 0x21); /* Select 8086 mode */
- outb(0xFF, 0x21); /* Mask all */
-
- /* init slave interrupt controller */
- outb(0x11, 0xA0); /* Start init sequence */
- outb(0x48, 0xA1); /* Vector base */
- /*outb(0x02, 0xA1);*/ /* edge triggered, Cascade (slave) on IRQ2 */
- outb(0x0A, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
- outb(0x01, 0xA1); /* Select 8086 mode */
- outb(0xFF, 0xA1); /* Mask all */
-
+ i8259_init();
+ route_pci_interrupts();
/*
* According to the Carolina spec from ibm irq's 0,1,2, and 8
* must be edge triggered. Also, the pci intrs must be level
@@ -389,17 +478,40 @@
* Sound on the Powerstack reportedly needs to be edge triggered
*/
if ( _machine == _MACH_Motorola )
- {}
+ {
+ /*irq_mode2 &= ~0x04L;
+ outb( irq_mode1 , 0x4d0 );
+ outb( irq_mode2 , 0x4d1 );*/
+ }
- /*outb( irq_mode1 , 0x4d0 );
- outb( irq_mode2 , 0x4d1 );*/
}
- outb(cached_A1, 0xA1);
- outb(cached_21, 0x21);
- if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL) != 0)
- panic("Could not allocate cascade IRQ!");
- enable_irq(2); /* Enable cascade interrupt */
-
- route_pci_interrupts();
+ break;
+ case _MACH_chrp:
+ mask_and_ack_irq = chrp_mask_and_ack_irq;
+ set_irq_mask = chrp_set_irq_mask;
+ if ((Hydra = find_hydra())) {
+ printk("Hydra Mac I/O at %p\n", Hydra);
+ out_le32(&Hydra->Feature_Control, HYDRA_FC_SCC_CELL_EN |
+ HYDRA_FC_SCSI_CELL_EN |
+ HYDRA_FC_SCCA_ENABLE |
+ HYDRA_FC_SCCB_ENABLE |
+ HYDRA_FC_ARB_BYPASS |
+ HYDRA_FC_MPIC_ENABLE |
+ HYDRA_FC_SLOW_SCC_PCLK |
+ HYDRA_FC_MPIC_IS_MASTER);
+ OpenPIC = (volatile struct OpenPIC *)&Hydra->OpenPIC;
+ } else if (!OpenPIC /* && find_xxx */) {
+ printk("Unknown openpic implementation\n");
+ /* other OpenPIC implementations */
+ /* ... */
+ }
+ if (OpenPIC)
+ openpic_init();
+ else
+ panic("No OpenPIC found");
+ if (Hydra)
+ hydra_post_openpic_init();
+ i8259_init();
+ break;
}
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov