patch-2.3.20 linux/arch/ppc/kernel/ppc8xx_pic.c

Next file: linux/arch/ppc/kernel/ppc8xx_pic.h
Previous file: linux/arch/ppc/kernel/pmac_time.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.19/linux/arch/ppc/kernel/ppc8xx_pic.c linux/arch/ppc/kernel/ppc8xx_pic.c
@@ -5,45 +5,170 @@
 #include <linux/signal.h>
 #include <asm/irq.h>
 #include <asm/8xx_immap.h>
-#include <asm/mbx.h>
+#include <asm/mpc8xx.h>
 #include "ppc8xx_pic.h"
 
+/* The 8xx or 82xx internal interrupt controller.  It is usually
+ * the only interrupt controller.  Some boards, like the MBX and
+ * Sandpoint have the 8259 as a secondary controller.  Depending
+ * upon the processor type, the internal controller can have as
+ * few as 16 interrups or as many as 64.  We could use  the
+ * "clear_bit()" and "set_bit()" functions like other platforms,
+ * but they are overkill for us.
+ */
 
-static void mbx_mask_irq(unsigned int irq_nr)
+static void m8xx_mask_irq(unsigned int irq_nr)
 {
-	if ( irq_nr == ISA_BRIDGE_INT ) return;
-	if ( irq_nr >= ppc8xx_pic.irq_offset )
-		irq_nr -= ppc8xx_pic.irq_offset;
-	ppc_cached_irq_mask[0] &= ~(1 << (31-irq_nr));
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =	ppc_cached_irq_mask[0];
+	int	bit, word;
+
+	bit = irq_nr & 0x1f;
+	word = irq_nr >> 5;
+
+	ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
+#ifdef CONFIG_82xx
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask[word] =
+						ppc_cached_irq_mask[word];
+#else
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
+						ppc_cached_irq_mask[word];
+#endif
 }
 
-static void mbx_unmask_irq(unsigned int irq_nr)
+static void m8xx_unmask_irq(unsigned int irq_nr)
 {
-	if ( irq_nr >= ppc8xx_pic.irq_offset )
-		irq_nr -= ppc8xx_pic.irq_offset;
-	ppc_cached_irq_mask[0] |= (1 << (31-irq_nr));
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =	ppc_cached_irq_mask[0];
+	int	bit, word;
+
+	bit = irq_nr & 0x1f;
+	word = irq_nr >> 5;
+
+	ppc_cached_irq_mask[word] |= (1 << (31-bit));
+#ifdef CONFIG_82xx
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask[word] =
+						ppc_cached_irq_mask[word];
+#else
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
+						ppc_cached_irq_mask[word];
+#endif
 }
 
-static void mbx_mask_and_ack(unsigned int irq_nr)
+static void m8xx_mask_and_ack(unsigned int irq_nr)
 {
-	/* this shouldn't be masked, we mask the 8259 if we need to -- Cort */
-	if ( irq_nr != ISA_BRIDGE_INT )
-		mbx_mask_irq(irq_nr);
-	if ( irq_nr >= ppc8xx_pic.irq_offset )
-		irq_nr -= ppc8xx_pic.irq_offset;
-	/* clear the pending bits */
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 1 << (31-irq_nr);
+	int	bit, word;
+
+	bit = irq_nr & 0x1f;
+	word = irq_nr >> 5;
+
+	ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
+#ifdef CONFIG_82xx
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask[word] =
+						ppc_cached_irq_mask[word];
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend[word] = 1 << (31-bit);
+#else
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
+						ppc_cached_irq_mask[word];
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 1 << (31-bit);
+#endif
 }
 
 struct hw_interrupt_type ppc8xx_pic = {
 	" 8xx SIU  ",
 	NULL,
 	NULL,
-	NULL,
-	mbx_unmask_irq,
-	mbx_mask_irq,
-	mbx_mask_and_ack,
+	m8xx_unmask_irq,
+	m8xx_mask_irq,
+	m8xx_mask_and_ack,
 	0
 };
+
+#if 0
+void
+m8xx_do_IRQ(struct pt_regs *regs,
+	   int            cpu,
+           int            isfake)
+{
+	int irq;
+        unsigned long bits = 0;
+
+        /* For MPC8xx, read the SIVEC register and shift the bits down
+         * to get the irq number.         */
+        bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec;
+        irq = bits >> 26;
+#if 0
+        irq += ppc8xx_pic.irq_offset;
+#endif
+        bits = 1UL << irq;
+
+	if (irq < 0) {
+		printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+		       irq, regs->nip);
+		ppc_spurious_interrupts++;
+	}
+	else {
+                ppc_irq_dispatch_handler( regs, irq );
+	}
+
+}
+#endif
+
+
+int
+m8xx_get_irq(struct pt_regs *regs)
+{
+	int irq;
+        unsigned long bits = 0;
+
+        /* For MPC8xx, read the SIVEC register and shift the bits down
+         * to get the irq number.         */
+        bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec;
+        irq = bits >> 26;
+#if 0
+        irq += ppc8xx_pic.irq_offset;
+#endif
+	return irq;
+}
+
+/* The MBX is the only 8xx board that uses the 8259.
+*/
+#ifdef CONFIG_MBX
+void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+	int bits, irq;
+
+	/* A bug in the QSpan chip causes it to give us 0xff always
+	 * when doing a character read.  So read 32 bits and shift.
+	 * This doesn't seem to return useful values anyway, but
+	 * read it to make sure things are acked.
+	 * -- Cort
+	 */
+	irq = (inl(0x508) >> 24)&0xff;
+	if ( irq != 0xff ) printk("iack %d\n", irq);
+	
+	outb(0x0C, 0x20);
+	irq = inb(0x20) & 7;
+	if (irq == 2)
+	{
+		outb(0x0C, 0xA0);
+		irq = inb(0xA0);
+		irq = (irq&7) + 8;
+	}
+	bits = 1UL << irq;
+	irq += i8259_pic.irq_offset;
+	ppc_irq_dispatch_handler( regs, irq );
+}
+#endif
+
+/* Only the MBX uses the external 8259.  This allows us to catch standard
+ * drivers that may mess up the internal interrupt controllers, and also
+ * allow them to run without modification on the MBX.
+ */
+int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+	unsigned long irqflags, const char * devname, void *dev_id)
+{
+
+#ifdef CONFIG_MBX
+	irq += i8259_pic.irq_offset;
+	return (request_8xxirq(irq, handler, irqflags, devname, dev_id));
+#else
+	panic("request_irq");
+#endif
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)