diff --git a/sys/mips/cavium/ciu.c b/sys/mips/cavium/ciu.c index eb58928ca958..fc8df1bc7424 100644 --- a/sys/mips/cavium/ciu.c +++ b/sys/mips/cavium/ciu.c @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -80,13 +81,24 @@ static int ciu_setup_intr(device_t, device_t, struct resource *, void *, void **); static int ciu_teardown_intr(device_t, device_t, struct resource *, void *); +static int ciu_bind_intr(device_t, device_t, struct resource *, + int); +static int ciu_describe_intr(device_t, device_t, + struct resource *, void *, + const char *); static void ciu_hinted_child(device_t, const char *, int); static void ciu_en0_intr_mask(void *); static void ciu_en0_intr_unmask(void *); +#ifdef SMP +static int ciu_en0_intr_bind(void *, u_char); +#endif static void ciu_en1_intr_mask(void *); static void ciu_en1_intr_unmask(void *); +#ifdef SMP +static int ciu_en1_intr_bind(void *, u_char); +#endif static int ciu_intr(void *); @@ -196,6 +208,7 @@ ciu_setup_intr(device_t bus, device_t child, struct resource *res, int flags, struct intr_event *event, **eventp; void (*mask_func)(void *); void (*unmask_func)(void *); + int (*bind_func)(void *, u_char); mips_intrcnt_t intrcnt; int error; int irq; @@ -206,16 +219,25 @@ ciu_setup_intr(device_t bus, device_t child, struct resource *res, int flags, intrcnt = ciu_en0_intrcnt[irq - CIU_IRQ_EN0_BEGIN]; mask_func = ciu_en0_intr_mask; unmask_func = ciu_en0_intr_unmask; +#ifdef SMP + bind_func = ciu_en0_intr_bind; +#endif } else { eventp = &ciu_en1_intr_events[irq - CIU_IRQ_EN1_BEGIN]; intrcnt = ciu_en1_intrcnt[irq - CIU_IRQ_EN1_BEGIN]; mask_func = ciu_en1_intr_mask; unmask_func = ciu_en1_intr_unmask; +#ifdef SMP + bind_func = ciu_en1_intr_bind; +#endif } +#if !defined(SMP) + bind_func = NULL; +#endif if ((event = *eventp) == NULL) { error = intr_event_create(eventp, (void *)(uintptr_t)irq, 0, - irq, mask_func, unmask_func, NULL, NULL, "int%d", irq); + irq, mask_func, unmask_func, NULL, bind_func, "int%d", irq); if (error != 0) return (error); @@ -245,6 +267,50 @@ ciu_teardown_intr(device_t bus, device_t child, struct resource *res, return (0); } +#ifdef SMP +static int +ciu_bind_intr(device_t bus, device_t child, struct resource *res, int cpu) +{ + struct intr_event *event; + int irq; + + irq = rman_get_start(res); + if (irq <= CIU_IRQ_EN0_END) + event = ciu_en0_intr_events[irq - CIU_IRQ_EN0_BEGIN]; + else + event = ciu_en1_intr_events[irq - CIU_IRQ_EN1_BEGIN]; + + return (intr_event_bind(event, cpu)); +} +#endif + +static int +ciu_describe_intr(device_t bus, device_t child, struct resource *res, + void *cookie, const char *descr) +{ + struct intr_event *event; + mips_intrcnt_t intrcnt; + int error; + int irq; + + irq = rman_get_start(res); + if (irq <= CIU_IRQ_EN0_END) { + event = ciu_en0_intr_events[irq - CIU_IRQ_EN0_BEGIN]; + intrcnt = ciu_en0_intrcnt[irq - CIU_IRQ_EN0_BEGIN]; + } else { + event = ciu_en1_intr_events[irq - CIU_IRQ_EN1_BEGIN]; + intrcnt = ciu_en1_intrcnt[irq - CIU_IRQ_EN1_BEGIN]; + } + + error = intr_event_describe_handler(event, cookie, descr); + if (error != 0) + return (error); + + mips_intrcnt_setname(intrcnt, event->ie_fullname); + + return (0); +} + static void ciu_hinted_child(device_t bus, const char *dname, int dunit) { @@ -275,6 +341,28 @@ ciu_en0_intr_unmask(void *arg) cvmx_write_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2), mask); } +#ifdef SMP +static int +ciu_en0_intr_bind(void *arg, u_char target) +{ + uint64_t mask; + int core; + int irq; + + irq = (uintptr_t)arg; + CPU_FOREACH(core) { + mask = cvmx_read_csr(CVMX_CIU_INTX_EN0(core*2)); + if (core == target) + mask |= 1ull << (irq - CIU_IRQ_EN0_BEGIN); + else + mask &= ~(1ull << (irq - CIU_IRQ_EN0_BEGIN)); + cvmx_write_csr(CVMX_CIU_INTX_EN0(core*2), mask); + } + + return (0); +} +#endif + static void ciu_en1_intr_mask(void *arg) { @@ -299,6 +387,28 @@ ciu_en1_intr_unmask(void *arg) cvmx_write_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2), mask); } +#ifdef SMP +static int +ciu_en1_intr_bind(void *arg, u_char target) +{ + uint64_t mask; + int core; + int irq; + + irq = (uintptr_t)arg; + CPU_FOREACH(core) { + mask = cvmx_read_csr(CVMX_CIU_INTX_EN1(core*2)); + if (core == target) + mask |= 1ull << (irq - CIU_IRQ_EN1_BEGIN); + else + mask &= ~(1ull << (irq - CIU_IRQ_EN1_BEGIN)); + cvmx_write_csr(CVMX_CIU_INTX_EN1(core*2), mask); + } + + return (0); +} +#endif + static int ciu_intr(void *arg) { @@ -358,6 +468,10 @@ static device_method_t ciu_methods[] = { DEVMETHOD(bus_activate_resource,bus_generic_activate_resource), DEVMETHOD(bus_setup_intr, ciu_setup_intr), DEVMETHOD(bus_teardown_intr, ciu_teardown_intr), +#ifdef SMP + DEVMETHOD(bus_bind_intr, ciu_bind_intr), +#endif + DEVMETHOD(bus_describe_intr, ciu_describe_intr), DEVMETHOD(bus_add_child, bus_generic_add_child), DEVMETHOD(bus_hinted_child, ciu_hinted_child),