Date: Fri, 27 Aug 2010 19:53:57 +0000 (UTC) From: "Jayachandran C." <jchandra@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r211893 - head/sys/mips/rmi Message-ID: <201008271953.o7RJrvgX005721@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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,
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201008271953.o7RJrvgX005721>