svn commit: r211893 - head/sys/mips/rmi

Jayachandran C. jchandra at FreeBSD.org
Fri Aug 27 19:53:57 UTC 2010


Author: jchandra
Date: Fri Aug 27 19:53:57 2010
New Revision: 211893
URL: http://svn.freebsd.org/changeset/base/211893

Log:
  Revamp XLR interrupt handling, the previous scheme does not work well on
  SMP.
  
  We used to route all PIC based interrupts to cpu 0, and used the per-CPU
  interrupt mask to enable/disable interrupts. But the interrupt threads can
  run on any cpu on SMP, and the interrupt thread will re-enable the interrupts
  on the CPU it runs on when it is done, and not on cpu0 where the PIC will
  still send interrupts to.
  
  The fix is move the disable/enable for PIC based interrupts to PIC, we will
  ack on PIC only when the interrupt thread is done, and we do not use the
  per-CPU interrupt mask.
  
  The changes also introduce a way for subsystems to add a function that
  will be called to clear the interrupt on the subsystem. Currently This is
  used by the PCI/PCIe for doing additional work during the interrupt
  handling.

Modified:
  head/sys/mips/rmi/interrupt.h
  head/sys/mips/rmi/intr_machdep.c
  head/sys/mips/rmi/iodi.c
  head/sys/mips/rmi/pic.h
  head/sys/mips/rmi/xlr_machdep.c
  head/sys/mips/rmi/xlr_pci.c

Modified: head/sys/mips/rmi/interrupt.h
==============================================================================
--- head/sys/mips/rmi/interrupt.h	Fri Aug 27 18:55:48 2010	(r211892)
+++ head/sys/mips/rmi/interrupt.h	Fri Aug 27 19:53:57 2010	(r211893)
@@ -40,10 +40,9 @@
  * XLR needs custom pre and post handlers for PCI/PCI-e interrupts
  * XXX: maybe follow i386 intsrc model
  */
-void xlr_cpu_establish_hardintr(const char *, driver_filter_t *,
-    driver_intr_t *, void *, int, int, void **, void (*)(void *),
-    void (*)(void *), void (*)(void *), int (*)(void *, u_char));
-void xlr_mask_hard_irq(void *);
-void xlr_unmask_hard_irq(void *);
+void xlr_establish_intr(const char *name, driver_filter_t filt,
+    driver_intr_t handler, void *arg, int irq, int flags,
+    void **cookiep, void (*busack)(int));
+void xlr_enable_irq(int irq);
 
 #endif				/* _RMI_INTERRUPT_H_ */

Modified: head/sys/mips/rmi/intr_machdep.c
==============================================================================
--- head/sys/mips/rmi/intr_machdep.c	Fri Aug 27 18:55:48 2010	(r211892)
+++ head/sys/mips/rmi/intr_machdep.c	Fri Aug 27 19:53:57 2010	(r211893)
@@ -49,34 +49,76 @@ __FBSDID("$FreeBSD$");
 #include <mips/rmi/clock.h>
 #include <mips/rmi/pic.h>
 
-/*#include <machine/intrcnt.h>*/
+struct xlr_intrsrc {
+	void (*busack)(int);		/* Additional ack */
+	struct intr_event *ie;		/* event corresponding to intr */
+	int irq;
+};
+	
+static struct xlr_intrsrc xlr_interrupts[XLR_MAX_INTR];
 static mips_intrcnt_t mips_intr_counters[XLR_MAX_INTR];
-static struct intr_event *mips_intr_events[XLR_MAX_INTR];
 static int intrcnt_index;
 
 void
-xlr_mask_hard_irq(void *source)
+xlr_enable_irq(int irq)
 {
-	uintptr_t irq = (uintptr_t) source;
 
-	write_c0_eimr64(read_c0_eimr64() & ~(1ULL << irq));
+	write_c0_eimr64(read_c0_eimr64() | (1ULL << irq));
 }
 
 void
-xlr_unmask_hard_irq(void *source)
+cpu_establish_softintr(const char *name, driver_filter_t * filt,
+    void (*handler) (void *), void *arg, int irq, int flags,
+    void **cookiep)
 {
-	uintptr_t irq = (uintptr_t) source;
 
-	write_c0_eimr64(read_c0_eimr64() | (1ULL << irq));
+	panic("Soft interrupts unsupported!\n");
+}
+
+void
+cpu_establish_hardintr(const char *name, driver_filter_t * filt,
+    void (*handler) (void *), void *arg, int irq, int flags,
+    void **cookiep)
+{
+
+	xlr_establish_intr(name, filt, handler, arg, irq, flags,
+	    cookiep, NULL);
+}
+
+static void
+xlr_post_filter(void *source)
+{
+	struct xlr_intrsrc *src = source;
+	
+	if (src->busack)
+		src->busack(src->irq);
+	pic_ack(PIC_IRQ_TO_INTR(src->irq));
+}
+
+static void
+xlr_pre_ithread(void *source)
+{
+	struct xlr_intrsrc *src = source;
+
+	if (src->busack)
+		src->busack(src->irq);
+}
+
+static void
+xlr_post_ithread(void *source)
+{
+	struct xlr_intrsrc *src = source;
+
+	pic_ack(PIC_IRQ_TO_INTR(src->irq));
 }
 
 void
-xlr_cpu_establish_hardintr(const char *name, driver_filter_t * filt,
-    void (*handler) (void *), void *arg, int irq, int flags, void **cookiep,
-    void (*pre_ithread)(void *), void (*post_ithread)(void *),
-    void (*post_filter)(void *), int (*assign_cpu)(void *, u_char))
+xlr_establish_intr(const char *name, driver_filter_t filt,
+    driver_intr_t handler, void *arg, int irq, int flags,
+    void **cookiep, void (*busack)(int))
 {
 	struct intr_event *ie;	/* descriptor for the IRQ */
+	struct xlr_intrsrc *src = NULL;
 	int errcode;
 
 	if (irq < 0 || irq > XLR_MAX_INTR)
@@ -86,43 +128,37 @@ xlr_cpu_establish_hardintr(const char *n
 	 * FIXME locking - not needed now, because we do this only on
 	 * startup from CPU0
 	 */
-	ie = mips_intr_events[irq];
-	/* mih->cntp = &intrcnt[irq]; */
-	if (ie == NULL) {
-		errcode = intr_event_create(&ie, (void *)(uintptr_t) irq, 0,
-		    irq, pre_ithread, post_ithread, post_filter, assign_cpu,
-		    "hard intr%d:", irq);
+	printf("[%s] Setup intr %d called on cpu %d (%d)\n", name, irq,
+	    xlr_cpu_id(), PCPU_GET(cpuid));
 
+	src = &xlr_interrupts[irq];
+	ie = src->ie;
+	if (ie == NULL) {
+		/*
+		 * PIC based interrupts need ack in PIC, and some SoC
+		 * components need additional acks (e.g. PCI)
+		 */
+		if (PIC_IRQ_IS_PICINTR(irq))
+			errcode = intr_event_create(&ie, src, 0, irq,
+			    xlr_pre_ithread, xlr_post_ithread, xlr_post_filter,
+			    NULL, "hard intr%d:", irq);
+		else {
+			if (filt == NULL)
+				panic("Not supported - non filter percpu intr");
+			errcode = intr_event_create(&ie, src, 0, irq,
+			    NULL, NULL, NULL, NULL, "hard intr%d:", irq);
+		}
 		if (errcode) {
 			printf("Could not create event for intr %d\n", irq);
 			return;
 		}
-		mips_intr_events[irq] = ie;
+		src->irq = irq;
+		src->busack = busack;
+		src->ie = ie;
 	}
-
 	intr_event_add_handler(ie, name, filt, handler, arg,
 	    intr_priority(flags), flags, cookiep);
-	xlr_unmask_hard_irq((void *)(uintptr_t) irq);
-}
-
-void
-cpu_establish_hardintr(const char *name, driver_filter_t * filt,
-    void (*handler) (void *), void *arg, int irq, int flags, void **cookiep)
-{
-	xlr_cpu_establish_hardintr(name, filt, handler, arg, irq,
-		flags, cookiep, xlr_mask_hard_irq, xlr_unmask_hard_irq,
-		NULL, NULL);
-}
-
-void
-cpu_establish_softintr(const char *name, driver_filter_t * filt,
-    void (*handler) (void *), void *arg, int irq, int flags,
-    void **cookiep)
-{
-	/* we don't separate them into soft/hard like other mips */
-	xlr_cpu_establish_hardintr(name, filt, handler, arg, irq,
-		flags, cookiep, xlr_mask_hard_irq, xlr_unmask_hard_irq,
-		NULL, NULL);
+	xlr_enable_irq(irq);
 }
 
 void
@@ -148,7 +184,7 @@ cpu_intr(struct trapframe *tf)
 	 * compare which ACKs the interrupt.
 	 */
 	if (eirr & (1 << IRQ_TIMER)) {
-		intr_event_handle(mips_intr_events[IRQ_TIMER], tf);
+		intr_event_handle(xlr_interrupts[IRQ_TIMER].ie, tf);
 		critical_exit();
 		return;
 	}
@@ -158,7 +194,7 @@ cpu_intr(struct trapframe *tf)
 		if ((eirr & (1ULL << i)) == 0)
 			continue;
 
-		ie = mips_intr_events[i];
+		ie = xlr_interrupts[i].ie;
 		/* Don't account special IRQs */
 		switch (i) {
 		case IRQ_IPI:
@@ -167,16 +203,12 @@ cpu_intr(struct trapframe *tf)
 		default:
 			mips_intrcnt_inc(mips_intr_counters[i]);
 		}
+
+		/* Ack the IRQ on the CPU */
 		write_c0_eirr64(1ULL << i);
-		pic_ack(i);
-		if (!ie || TAILQ_EMPTY(&ie->ie_handlers)) {
-			printf("stray interrupt %d\n", i);
-			continue;
-		}
 		if (intr_event_handle(ie, tf) != 0) {
 			printf("stray interrupt %d\n", i);
 		}
-		pic_delayed_ack(i);
 	}
 	critical_exit();
 }

Modified: head/sys/mips/rmi/iodi.c
==============================================================================
--- head/sys/mips/rmi/iodi.c	Fri Aug 27 18:55:48 2010	(r211892)
+++ head/sys/mips/rmi/iodi.c	Fri Aug 27 19:53:57 2010	(r211893)
@@ -99,7 +99,7 @@ iodi_setup_intr(device_t dev, device_t c
 		/* FIXME uart 1? */
 		cpu_establish_hardintr("uart", filt, intr, arg,
 		    PIC_UART_0_IRQ, flags, cookiep);
-		pic_setup_intr(PIC_IRT_UART_0_INDEX, PIC_UART_0_IRQ, 0x1);
+		pic_setup_intr(PIC_IRT_UART_0_INDEX, PIC_UART_0_IRQ, 0x1, 0);
 	} else if (strcmp(device_get_name(child), "rge") == 0) {
 		int irq;
 
@@ -107,11 +107,11 @@ iodi_setup_intr(device_t dev, device_t c
 		irq = (intptr_t)ires->__r_i;
 		cpu_establish_hardintr("rge", filt, intr, arg, irq, flags,
 		    cookiep);
-		pic_setup_intr(irq - PIC_IRQ_BASE, irq, 0x1);
+		pic_setup_intr(irq - PIC_IRQ_BASE, irq, 0x1, 0);
 	} else if (strcmp(device_get_name(child), "ehci") == 0) {
 		cpu_establish_hardintr("ehci", filt, intr, arg, PIC_USB_IRQ, flags,
 		    cookiep);
-		pic_setup_intr(PIC_USB_IRQ - PIC_IRQ_BASE, PIC_USB_IRQ, 0x1);
+		pic_setup_intr(PIC_USB_IRQ - PIC_IRQ_BASE, PIC_USB_IRQ, 0x1, 0);
 	}
 
 	return (0);

Modified: head/sys/mips/rmi/pic.h
==============================================================================
--- head/sys/mips/rmi/pic.h	Fri Aug 27 18:55:48 2010	(r211892)
+++ head/sys/mips/rmi/pic.h	Fri Aug 27 19:53:57 2010	(r211893)
@@ -29,16 +29,15 @@
  *
  * RMI_BSD */
 #ifndef _RMI_PIC_H_
-#define _RMI_PIC_H_
-#include <sys/cdefs.h>
+#define	_RMI_PIC_H_
 
+#include <sys/cdefs.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <mips/rmi/iomap.h>
 
 #define	PIC_IRT_WD_INDEX		0
 #define	PIC_IRT_TIMER_INDEX(i)		(1 + (i))
-#define	PIC_IRT_CLOCK_INDEX		PIC_IRT_TIMER_7_INDEX
 #define	PIC_IRT_UART_0_INDEX		9
 #define	PIC_IRT_UART_1_INDEX		10
 #define	PIC_IRT_I2C_0_INDEX		11
@@ -70,7 +69,6 @@
 #define	PIC_IRT_PCIE_FATAL_INDEX	29
 #define	PIC_IRT_GPIO_B_INDEX		30
 #define	PIC_IRT_USB_INDEX		31
-
 #define	PIC_NUM_IRTS			32
 
 #define	PIC_CLOCK_TIMER			7
@@ -102,7 +100,6 @@
 #define	PIC_TIMER_COUNT_1(i)	(PIC_TIMER_COUNT_0_BASE + (i))
 #define	PIC_TIMER_HZ		66000000U
 
-
 /*
  * We use a simple mapping form PIC interrupts to CPU IRQs.
  * The PIC interrupts 0-31 are mapped to CPU irq's 8-39.
@@ -111,7 +108,7 @@
  */
 #define	PIC_IRQ_BASE		8
 #define	PIC_INTR_TO_IRQ(i)	(PIC_IRQ_BASE + (i))
-#define	PIC_IRT_FIRST_IRQ	PIC_IRQ_BASE
+#define	PIC_IRQ_TO_INTR(i)	((i) - PIC_IRQ_BASE)
 
 #define	PIC_WD_IRQ		(PIC_IRQ_BASE + PIC_IRT_WD_INDEX)
 #define	PIC_TIMER_IRQ(i)	(PIC_IRQ_BASE + PIC_IRT_TIMER_INDEX(i))
@@ -137,7 +134,6 @@
 #define	PIC_BRIDGE_BERR_IRQ	(PIC_IRQ_BASE + PIC_IRT_BRIDGE_BERR_INDEX)
 #define	PIC_BRIDGE_TB_IRQ	(PIC_IRQ_BASE + PIC_IRT_BRIDGE_TB_INDEX)
 #define	PIC_BRIDGE_AERR_NMI_IRQ	(PIC_IRQ_BASE + PIC_IRT_BRIDGE_AERR_NMI_INDEX)
-
 #define	PIC_BRIDGE_ERR_IRQ	(PIC_IRQ_BASE + PIC_IRT_BRIDGE_ERR_INDEX)
 #define	PIC_PCIE_LINK0_IRQ	(PIC_IRQ_BASE + PIC_IRT_PCIE_LINK0_INDEX)
 #define	PIC_PCIE_LINK1_IRQ	(PIC_IRQ_BASE + PIC_IRT_PCIE_LINK1_INDEX)
@@ -148,9 +144,10 @@
 #define	PIC_GPIO_B_IRQ		(PIC_IRQ_BASE + PIC_IRT_GPIO_B_INDEX)
 #define	PIC_USB_IRQ		(PIC_IRQ_BASE + PIC_IRT_USB_INDEX)
 
-#define	PIC_IRT_LAST_IRQ	PIC_USB_IRQ
-#define	PIC_IRQ_IS_EDGE_TRIGGERED(irq) (((irq) >= PIC_TIMER_IRQ(0)) && ((irq) <= PIC_TIMER_IRQ(7)))
-#define	PIC_IRQ_IS_IRT(irq)	(((irq) >= PIC_IRT_FIRST_IRQ) && ((irq) <= PIC_IRT_LAST_IRQ))
+#define	PIC_IRQ_IS_PICINTR(irq)	((irq) >= PIC_IRQ_BASE && 		\
+				 (irq) < PIC_IRQ_BASE + PIC_NUM_IRTS)
+#define	PIC_IS_EDGE_TRIGGERED(i) ((i) >= PIC_IRT_TIMER_INDEX(0) &&	\
+				  (i) <= PIC_IRT_TIMER_INDEX(7))
 
 extern struct mtx xlr_pic_lock;
 
@@ -187,35 +184,11 @@ pic_update_control(__uint32_t control)
 }
 
 static __inline void 
-pic_ack(int irq)
-{
-	xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET);
-
-	/* ack the pic, if needed */
-	if (!PIC_IRQ_IS_IRT(irq))
-		return;
-
-	if (PIC_IRQ_IS_EDGE_TRIGGERED(irq)) {
-		mtx_lock_spin(&xlr_pic_lock);
-		xlr_write_reg(mmio, PIC_INT_ACK, (1 << (irq - PIC_IRQ_BASE)));
-		mtx_unlock_spin(&xlr_pic_lock);
-	}
-	return;
-}
-
-static __inline void 
-pic_delayed_ack(int irq)
+pic_ack(int picintr)
 {
 	xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET);
 
-	if (!PIC_IRQ_IS_IRT(irq))
-		return;
-	if (!PIC_IRQ_IS_EDGE_TRIGGERED(irq)) {
-		mtx_lock_spin(&xlr_pic_lock);
-		xlr_write_reg(mmio, PIC_INT_ACK, (1 << (irq - PIC_IRQ_BASE)));
-		mtx_unlock_spin(&xlr_pic_lock);
-	}
-	return;
+	xlr_write_reg(mmio, PIC_INT_ACK, 1 << picintr);
 }
 
 static __inline
@@ -230,13 +203,11 @@ void pic_send_ipi(int cpu, int ipi)
 }
 
 static __inline
-void pic_setup_intr(int picintr, int irq, uint32_t cpumask)
+void pic_setup_intr(int picintr, int irq, uint32_t cpumask, int level)
 {
         xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET);
-	int level;
 
 	mtx_lock_spin(&xlr_pic_lock);
-	level = PIC_IRQ_IS_EDGE_TRIGGERED(irq);
 	xlr_write_reg(mmio, PIC_IRT_0(picintr), cpumask);
 	xlr_write_reg(mmio, PIC_IRT_1(picintr), ((1 << 31) | (level << 30) |
 	    (1 << 6) | irq));

Modified: head/sys/mips/rmi/xlr_machdep.c
==============================================================================
--- head/sys/mips/rmi/xlr_machdep.c	Fri Aug 27 18:55:48 2010	(r211892)
+++ head/sys/mips/rmi/xlr_machdep.c	Fri Aug 27 19:53:57 2010	(r211893)
@@ -305,7 +305,7 @@ xlr_pic_init(void)
 	/* Initialize all IRT entries */
 	for (i = 0; i < PIC_NUM_IRTS; i++) {
 		irq = PIC_INTR_TO_IRQ(i);
-		level = PIC_IRQ_IS_EDGE_TRIGGERED(irq);
+		level = PIC_IS_EDGE_TRIGGERED(i);
 
 		/* Bind all PIC irqs to cpu 0 */
 		xlr_write_reg(mmio, PIC_IRT_0(i), 0x01);
@@ -575,11 +575,11 @@ platform_init_ap(int cpuid)
 	stat |= MIPS_SR_COP_2_BIT | MIPS_SR_COP_0_BIT;
 	mips_wr_status(stat);
 
-	xlr_unmask_hard_irq((void *)IRQ_IPI);
-	xlr_unmask_hard_irq((void *)IRQ_TIMER);
+	xlr_enable_irq(IRQ_IPI);
+	xlr_enable_irq(IRQ_TIMER);
 	if (xlr_thr_id() == 0) {
 		xlr_msgring_cpu_init(); 
-	 	xlr_unmask_hard_irq((void *)IRQ_MSGRING);
+	 	xlr_enable_irq(IRQ_MSGRING);
 	}
 
 	return;

Modified: head/sys/mips/rmi/xlr_pci.c
==============================================================================
--- head/sys/mips/rmi/xlr_pci.c	Fri Aug 27 18:55:48 2010	(r211892)
+++ head/sys/mips/rmi/xlr_pci.c	Fri Aug 27 19:53:57 2010	(r211893)
@@ -403,24 +403,15 @@ xlr_map_msi(device_t pcib, device_t dev,
 }
 
 static void
-bridge_pcix_ack(void *arg)
+bridge_pcix_ack(int irq)
 {
 
 	xlr_read_reg(xlr_io_mmio(XLR_IO_PCIX_OFFSET), 0x140 >> 2);
 }
 
 static void
-bridge_pcix_mask_ack(void *arg)
+bridge_pcie_ack(int irq)
 {
-
-	xlr_mask_hard_irq(arg);
-	bridge_pcix_ack(arg);
-}
-	
-static void
-bridge_pcie_ack(void *arg)
-{
-	int irq = (intptr_t)arg;
 	uint32_t reg;
 	xlr_reg_t *pcie_mmio_le = xlr_io_mmio(XLR_IO_PCIE_1_OFFSET);
 
@@ -443,14 +434,6 @@ bridge_pcie_ack(void *arg)
 	xlr_write_reg(pcie_mmio_le, reg>>2, 0xffffffff);
 }
 
-static void
-bridge_pcie_mask_ack(void *arg)
-{
-
-	xlr_mask_hard_irq(arg);
-	bridge_pcie_ack(arg);
-}
-
 static int
 mips_platform_pci_setup_intr(device_t dev, device_t child,
     struct resource *irq, int flags,
@@ -475,17 +458,13 @@ mips_platform_pci_setup_intr(device_t de
 		return (0);
 
 	if (xlr_board_info.is_xls == 0) {
-		xlr_cpu_establish_hardintr(device_get_name(child), filt,
-		    intr, arg, PIC_PCIX_IRQ, flags, cookiep,
-		    bridge_pcix_mask_ack, xlr_unmask_hard_irq,
-		    bridge_pcix_ack, NULL);
-		pic_setup_intr(PIC_IRT_PCIX_INDEX, PIC_PCIX_IRQ, 0x1);
+		xlr_establish_intr(device_get_name(child), filt,
+		    intr, arg, PIC_PCIX_IRQ, flags, cookiep, bridge_pcix_ack);
+		pic_setup_intr(PIC_IRT_PCIX_INDEX, PIC_PCIX_IRQ, 0x1, 0);
 	} else {
-		xlr_cpu_establish_hardintr(device_get_name(child), filt,
-		    intr, arg, xlrirq, flags, cookiep,
-	    	    bridge_pcie_mask_ack, xlr_unmask_hard_irq,
-		    bridge_pcie_ack, NULL);
-		pic_setup_intr(xlrirq - PIC_IRQ_BASE, xlrirq, 0x1);
+		xlr_establish_intr(device_get_name(child), filt,
+		    intr, arg, xlrirq, flags, cookiep, bridge_pcie_ack);
+		pic_setup_intr(xlrirq - PIC_IRQ_BASE, xlrirq, 0x1, 0);
 	}
 
 	return (bus_generic_setup_intr(dev, child, irq, flags, filt, intr,


More information about the svn-src-all mailing list