patch-2.4.21 linux-2.4.21/arch/ppc/8xx_io/commproc.c

Next file: linux-2.4.21/arch/ppc/8xx_io/enet.c
Previous file: linux-2.4.21/arch/ppc/8xx_io/Makefile
Back to the patch index
Back to the overall index

diff -urN linux-2.4.20/arch/ppc/8xx_io/commproc.c linux-2.4.21/arch/ppc/8xx_io/commproc.c
@@ -1,8 +1,4 @@
 /*
- * BK Id: SCCS/s.commproc.c 1.15 10/16/01 16:21:52 trini
- */
-
-/*
  * General Purpose functions for the global management of the
  * Communication Processor Module.
  * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
@@ -31,7 +27,7 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
-#include <asm/irq.h>
+#include <linux/irq.h>
 #include <asm/mpc8xx.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -47,14 +43,65 @@
 cpm8xx_t	*cpmp;		/* Pointer to comm processor space */
 
 /* CPM interrupt vector functions.
-*/
+ *
+ * The cpm_vecs structure is only needed to support the cpm_install_handler()
+ * mechanism of installing CPM interrupt handlers.
+ */
 struct	cpm_action {
 	void	(*handler)(void *, struct pt_regs * regs);
 	void	*dev_id;
 };
 static	struct	cpm_action cpm_vecs[CPMVEC_NR];
 static	void	cpm_interrupt(int irq, void * dev, struct pt_regs * regs);
-static	void	cpm_error_interrupt(void *, struct pt_regs * regs);
+static	void	cpm_error_interrupt(int irq, void *, struct pt_regs * regs);
+
+/* Define a table of names to identify CPM interrupt handlers in
+ * /proc/interrupts.
+ */
+const char *cpm_int_name[] =
+	{ "error",	"PC4",		"PC5",		"SMC2",
+	  "SMC1",	"SPI",		"PC6",		"Timer 4",
+	  "",		"PC7",		"PC8",		"PC9",
+	  "Timer 3",	"",		"PC10",		"PC11",
+	  "I2C",	"RISC Timer",	"Timer 2",	"",
+	  "IDMA2",	"IDMA1",	"SDMA error",	"PC12",
+	  "PC13",	"Timer 1",	"PC14",		"SCC4",
+	  "SCC3",	"SCC2",		"SCC1",		"PC15"
+	};
+
+static void
+cpm_mask_irq(unsigned int irq)
+{
+	int cpm_vec = irq - CPM_IRQ_OFFSET;
+
+	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << cpm_vec);
+}
+
+static void
+cpm_unmask_irq(unsigned int irq)
+{
+	int cpm_vec = irq - CPM_IRQ_OFFSET;
+
+	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << cpm_vec);
+}
+
+static void
+cpm_eoi(unsigned int irq)
+{
+	int cpm_vec = irq - CPM_IRQ_OFFSET;
+
+	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr = (1 << cpm_vec);
+}
+
+struct hw_interrupt_type cpm_pic = {
+	" CPM      ",
+	NULL,
+	NULL,
+	cpm_unmask_irq,
+	cpm_mask_irq,
+	NULL,
+	cpm_eoi
+};
 
 void
 m8xx_cpm_reset(uint host_page_addr)
@@ -118,6 +165,8 @@
 void
 cpm_interrupt_init(void)
 {
+	int i;
+
 	/* Initialize the CPM interrupt controller.
 	*/
 	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr =
@@ -125,41 +174,54 @@
 		((CPM_INTERRUPT/2) << 13) | CICR_HP_MASK;
 	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr = 0;
 
+        /* install the CPM interrupt controller routines for the CPM
+         * interrupt vectors
+         */
+        for ( i = CPM_IRQ_OFFSET ; i < CPM_IRQ_OFFSET + NR_CPM_INTS ; i++ )
+                irq_desc[i].handler = &cpm_pic;
+
 	/* Set our interrupt handler with the core CPU.
 	*/
-	if (request_8xxirq(CPM_INTERRUPT, cpm_interrupt, 0, "cpm", NULL) != 0)
+	if (request_irq(CPM_INTERRUPT, cpm_interrupt, 0, "CPM cascade",
+				NULL) != 0)
 		panic("Could not allocate CPM IRQ!");
 
 	/* Install our own error handler.
 	*/
-	cpm_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL);
+	if (request_irq(CPM_IRQ_OFFSET + CPMVEC_ERROR, cpm_error_interrupt,
+				0, cpm_int_name[CPMVEC_ERROR], NULL) != 0)
+		panic("Could not allocate CPM error IRQ!");
+
 	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr |= CICR_IEN;
 }
 
-/* CPM interrupt controller interrupt.
-*/
-static	void
-cpm_interrupt(int irq, void * dev, struct pt_regs * regs)
+/*
+ * Get the CPM interrupt vector.
+ */
+int
+cpm_get_irq(struct pt_regs *regs)
 {
-	uint	vec;
+	int cpm_vec;
 
 	/* Get the vector by setting the ACK bit and then reading
 	 * the register.
 	 */
 	((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr = 1;
-	vec = ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr;
-	vec >>= 11;
+	cpm_vec = ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr;
+	cpm_vec >>= 11;
 
-	if (cpm_vecs[vec].handler != 0)
-		(*cpm_vecs[vec].handler)(cpm_vecs[vec].dev_id, regs);
-	else
-		((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec);
+	return cpm_vec;
+}
 
-	/* After servicing the interrupt, we have to remove the status
-	 * indicator.
+/* CPM interrupt controller cascade interrupt.
+*/
+static	void
+cpm_interrupt(int irq, void * dev, struct pt_regs * regs)
+{
+	/* This interrupt handler never actually gets called.  It is
+	 * installed only to unmask the CPM cascade interrupt in the SIU
+	 * and to make the CPM cascade interrupt visible in /proc/interrupts.
 	 */
-	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr = (1 << vec);
-	
 }
 
 /* The CPM can generate the error interrupt when there is a race condition
@@ -168,40 +230,69 @@
  * tests in the interrupt handler.
  */
 static	void
-cpm_error_interrupt(void *dev, struct pt_regs *regs)
+cpm_error_interrupt(int irq, void *dev, struct pt_regs *regs)
 {
 }
 
+/* A helper function to translate the handler prototype required by
+ * request_irq() to the handler prototype required by cpm_install_handler().
+ */
+static void
+cpm_handler_helper(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int cpm_vec = irq - CPM_IRQ_OFFSET;
+
+	(*cpm_vecs[cpm_vec].handler)(dev_id, regs);
+}
+
 /* Install a CPM interrupt handler.
-*/
+ * This routine accepts a CPM interrupt vector in the range 0 to 31.
+ * This routine is retained for backward compatibility.  Rather than using
+ * this routine to install a CPM interrupt handler, you can now use
+ * request_irq() with an IRQ in the range CPM_IRQ_OFFSET to
+ * CPM_IRQ_OFFSET + NR_CPM_INTS - 1 (16 to 47).
+ *
+ * Notice that the prototype of the interrupt handler function must be
+ * different depending on whether you install the handler with
+ * request_irq() or cpm_install_handler().
+ */
 void
-cpm_install_handler(int vec, void (*handler)(void *, struct pt_regs *regs),
+cpm_install_handler(int cpm_vec, void (*handler)(void *, struct pt_regs *regs),
 		    void *dev_id)
 {
+	int err;
 
 	/* If null handler, assume we are trying to free the IRQ.
 	*/
 	if (!handler) {
-		cpm_free_handler(vec);
+		free_irq(CPM_IRQ_OFFSET + cpm_vec, dev_id);
 		return;
 	}
 
-	if (cpm_vecs[vec].handler != 0)
-		printk("CPM interrupt %x replacing %x\n",
-			(uint)handler, (uint)cpm_vecs[vec].handler);
-	cpm_vecs[vec].handler = handler;
-	cpm_vecs[vec].dev_id = dev_id;
-	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << vec);
+	if (cpm_vecs[cpm_vec].handler != 0)
+		printk(KERN_INFO "CPM interrupt %x replacing %x\n",
+			(uint)handler, (uint)cpm_vecs[cpm_vec].handler);
+	cpm_vecs[cpm_vec].handler = handler;
+	cpm_vecs[cpm_vec].dev_id = dev_id;
+
+	if ((err = request_irq(CPM_IRQ_OFFSET + cpm_vec, cpm_handler_helper,
+					0, cpm_int_name[cpm_vec], dev_id)))
+		printk(KERN_ERR "request_irq() returned %d for CPM vector %d\n",
+				err, cpm_vec);
 }
 
 /* Free a CPM interrupt handler.
-*/
+ * This routine accepts a CPM interrupt vector in the range 0 to 31.
+ * This routine is retained for backward compatibility.
+ */
 void
-cpm_free_handler(int vec)
+cpm_free_handler(int cpm_vec)
 {
-	cpm_vecs[vec].handler = NULL;
-	cpm_vecs[vec].dev_id = NULL;
-	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec);
+	request_irq(CPM_IRQ_OFFSET + cpm_vec, NULL, 0, 0,
+		cpm_vecs[cpm_vec].dev_id);
+
+	cpm_vecs[cpm_vec].handler = NULL;
+	cpm_vecs[cpm_vec].dev_id = NULL;
 }
 
 /* Allocate some memory from the dual ported ram.  We may want to

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