Index: dev/cbus.c =================================================================== RCS file: /cvs/src/sys/arch/sparc64/dev/cbus.c,v retrieving revision 1.16 diff -u -p -r1.16 cbus.c --- dev/cbus.c 20 Dec 2016 13:40:50 -0000 1.16 +++ dev/cbus.c 15 Jun 2020 06:07:16 -0000 @@ -53,6 +53,8 @@ struct cfdriver cbus_cd = { void *cbus_intr_establish(bus_space_tag_t, bus_space_tag_t, int, int, int, int (*)(void *), void *, const char *); +void *cbus_intr_establish_cpu(bus_space_tag_t, bus_space_tag_t, int, int, int, + struct cpu_info *, int (*)(void *), void *, const char *); void cbus_intr_ack(struct intrhand *); bus_space_tag_t cbus_alloc_bus_tag(struct cbus_softc *, bus_space_tag_t); @@ -155,6 +157,15 @@ void * cbus_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle, int level, int flags, int (*handler)(void *), void *arg, const char *what) { + return (cbus_intr_establish_cpu(t, t0, ihandle, level, flags, NULL, + handler, arg, what)); +} + +void * +cbus_intr_establish_cpu(bus_space_tag_t t, bus_space_tag_t t0, int ihandle, + int level, int flags, struct cpu_info *cpu, int (*handler)(void *), + void *arg, const char *what) +{ struct cbus_softc *sc = t0->cookie; uint64_t devhandle = sc->sc_devhandle; uint64_t devino = ihandle; @@ -184,7 +195,10 @@ cbus_intr_establish(bus_space_tag_t t, b evcount_attach(&ih->ih_count, ih->ih_name, NULL); ih->ih_ack = cbus_intr_ack; - ih->ih_cpu = cpus; + if (cpu == NULL) + ih->ih_cpu = cpus; + else + ih->ih_cpu = cpu; err = hv_vintr_settarget(devhandle, devino, ih->ih_cpu->ci_upaid); if (err != H_EOK) { @@ -229,6 +243,7 @@ cbus_alloc_bus_tag(struct cbus_softc *sc bt->sasi = parent->sasi; bt->sparc_bus_map = parent->sparc_bus_map; bt->sparc_intr_establish = cbus_intr_establish; + bt->sparc_intr_establish_cpu = cbus_intr_establish_cpu; return (bt); } Index: dev/msi.c =================================================================== RCS file: /cvs/src/sys/arch/sparc64/dev/msi.c,v retrieving revision 1.4 diff -u -p -r1.4 msi.c --- dev/msi.c 8 Sep 2015 10:24:25 -0000 1.4 +++ dev/msi.c 15 Jun 2020 06:07:16 -0000 @@ -28,7 +28,7 @@ struct msi_msg { }; struct msi_eq * -msi_eq_alloc(bus_dma_tag_t t, int msi_eq_size) +msi_eq_alloc(bus_dma_tag_t t, int msi_eq_size, int num_eq) { struct msi_eq *meq; bus_size_t size; @@ -39,7 +39,8 @@ msi_eq_alloc(bus_dma_tag_t t, int msi_eq if (meq == NULL) return NULL; - size = roundup(msi_eq_size * sizeof(struct msi_msg), PAGE_SIZE); + size = roundup(num_eq * msi_eq_size * sizeof(struct msi_msg), + PAGE_SIZE); if (bus_dmamap_create(t, size, 1, size, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &meq->meq_map) != 0) @@ -59,6 +60,7 @@ msi_eq_alloc(bus_dma_tag_t t, int msi_eq meq->meq_va = va; meq->meq_nentries = msi_eq_size; + meq->meq_nqueues = num_eq; return (meq); unmap: @@ -76,11 +78,18 @@ msi_eq_free(bus_dma_tag_t t, struct msi_ { bus_size_t size; - size = roundup(meq->meq_nentries * sizeof(struct msi_msg), PAGE_SIZE); + size = roundup(meq->meq_nqueues * meq->meq_nentries * sizeof(struct msi_msg), + PAGE_SIZE); bus_dmamap_unload(t, meq->meq_map); bus_dmamem_unmap(t, meq->meq_va, size); bus_dmamem_free(t, &meq->meq_seg, 1); bus_dmamap_destroy(t, meq->meq_map); free(meq, M_DEVBUF, sizeof *meq); +} + +size_t +msi_eq_offset(struct msi_eq *meq, int eq) +{ + return (meq->meq_nentries * sizeof(struct msi_msg) * eq); } Index: dev/msivar.h =================================================================== RCS file: /cvs/src/sys/arch/sparc64/dev/msivar.h,v retrieving revision 1.1 diff -u -p -r1.1 msivar.h --- dev/msivar.h 6 Jul 2011 05:35:53 -0000 1.1 +++ dev/msivar.h 15 Jun 2020 06:07:16 -0000 @@ -15,7 +15,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -struct msi_eq *msi_eq_alloc(bus_dma_tag_t, int); +struct msi_eq *msi_eq_alloc(bus_dma_tag_t, int, int); +size_t msi_eq_offset(struct msi_eq *, int); void msi_eq_free(bus_dma_tag_t t, struct msi_eq *); struct msi_eq { @@ -23,4 +24,5 @@ struct msi_eq { bus_dma_segment_t meq_seg; caddr_t meq_va; int meq_nentries; + int meq_nqueues; }; Index: dev/pci_machdep.c =================================================================== RCS file: /cvs/src/sys/arch/sparc64/dev/pci_machdep.c,v retrieving revision 1.49 diff -u -p -r1.49 pci_machdep.c --- dev/pci_machdep.c 5 Dec 2019 12:46:54 -0000 1.49 +++ dev/pci_machdep.c 15 Jun 2020 06:07:16 -0000 @@ -523,18 +523,39 @@ pci_intr_establish(pc, ih, level, func, void *arg; const char *what; { + return (pci_intr_establish_cpu(pc, ih, level, -1, func, arg, what)); +} + +void * +pci_intr_establish_cpu(pci_chipset_tag_t pc, pci_intr_handle_t ih, + int level, int cpuid, int (*func)(void *), void *arg, + const char *what) +{ void *cookie; int flags = 0; + struct cpu_info *cpu = NULL; if (level & IPL_MPSAFE) { flags |= BUS_INTR_ESTABLISH_MPSAFE; level &= ~IPL_MPSAFE; } + if (cpuid != -1) { + struct cpu_info *ci; + CPU_INFO_ITERATOR cii; + + CPU_INFO_FOREACH(cii, ci) { + if (CPU_INFO_UNIT(ci) == cpuid) { + cpu = ci; + break; + } + } + } + DPRINTF(SPDB_INTR, ("pci_intr_establish: ih %lu; level %d", (u_long)ih, level)); - cookie = bus_intr_establish(pc->bustag, ih, level, flags, - func, arg, what); + cookie = bus_intr_establish_cpu(pc->bustag, ih, level, flags, + cpu, func, arg, what); DPRINTF(SPDB_INTR, ("; returning handle %p\n", cookie)); return (cookie); Index: dev/pyro.c =================================================================== RCS file: /cvs/src/sys/arch/sparc64/dev/pyro.c,v retrieving revision 1.33 diff -u -p -r1.33 pyro.c --- dev/pyro.c 25 Jun 2019 22:30:56 -0000 1.33 +++ dev/pyro.c 15 Jun 2020 06:07:16 -0000 @@ -62,13 +62,16 @@ int pyro_debug = ~0; #define DPRINTF(l, s) #endif +#define FIRE_INTR_MAP(n) 0x01000 + ((n) * 8) +#define FIRE_INTR_CLR(n) 0x01400 + ((n) * 8) + #define FIRE_EQ_BASE_ADDR 0x10000 -#define FIRE_EQ_CNTRL_SET 0x11000 +#define FIRE_EQ_CNTRL_SET(n) 0x11000 + ((n) * 8) #define FIRE_EQ_CTRL_SET_EN 0x0000100000000000UL -#define FIRE_EQ_CNTRL_CLEAR 0x11200 -#define FIRE_EQ_STATE 0x11400 -#define FIRE_EQ_TAIL 0x11600 -#define FIRE_EQ_HEAD 0x11800 +#define FIRE_EQ_CNTRL_CLEAR(n) 0x11200 + ((n) * 8) +#define FIRE_EQ_STATE(n) 0x11400 + ((n) * 8) +#define FIRE_EQ_TAIL(n) 0x11600 + ((n) * 8) +#define FIRE_EQ_HEAD(n) 0x11800 + ((n) * 8) #define FIRE_MSI_MAP 0x20000 #define FIRE_MSI_MAP_V 0x8000000000000000UL #define FIRE_MSI_MAP_EQWR_N 0x4000000000000000UL @@ -102,6 +105,7 @@ void pyro_attach(struct device *, struct void pyro_init(struct pyro_softc *, int); void pyro_init_iommu(struct pyro_softc *, struct pyro_pbm *); void pyro_init_msi(struct pyro_softc *, struct pyro_pbm *); +void pyro_redistribute_msi(struct device *); int pyro_print(void *, const char *); pci_chipset_tag_t pyro_alloc_chipset(struct pyro_pbm *, int, @@ -124,6 +128,8 @@ paddr_t pyro_bus_mmap(bus_space_tag_t, b int, int); void *pyro_intr_establish(bus_space_tag_t, bus_space_tag_t, int, int, int, int (*)(void *), void *, const char *); +void *pyro_intr_establish_cpu(bus_space_tag_t, bus_space_tag_t, int, int, int, + struct cpu_info *, int (*)(void *), void *, const char *); void pyro_msi_ack(struct intrhand *); int pyro_msi_eq_intr(void *); @@ -250,6 +256,7 @@ pyro_init(struct pyro_softc *sc, int bus pbm->pp_cfgt = pyro_alloc_config_tag(pbm); pbm->pp_dmat = pyro_alloc_dma_tag(pbm); + sc->sc_pbm = pbm; /* XXX */ pyro_init_msi(sc, pbm); if (bus_space_map(pbm->pp_cfgt, 0, 0x10000000, 0, &pbm->pp_cfgh)) @@ -332,7 +339,15 @@ pyro_init_msi(struct pyro_softc *sc, str u_int32_t msi_addr_range[3]; u_int32_t msi_eq_devino[3] = { 0, 36, 24 }; int ihandle; - int msis, msi_eq_size; + int msis, msi_eq_size, num_eq; + struct pyro_eq *eq; + struct msi_eq *meq; + struct pyro_msi_msg *msgs; + struct cpu_info *ci; + CPU_INFO_ITERATOR cii; + + /* one queue per cpu */ + num_eq = ncpus; if (OF_getprop(sc->sc_node, "msi-address-ranges", msi_addr_range, sizeof(msi_addr_range)) <= 0) @@ -347,12 +362,13 @@ pyro_init_msi(struct pyro_softc *sc, str return; msi_eq_size = getpropint(sc->sc_node, "msi-eq-size", 256); - pbm->pp_meq = msi_eq_alloc(pbm->pp_dmat, msi_eq_size); + pbm->pp_meq = msi_eq_alloc(pbm->pp_dmat, msi_eq_size, num_eq); if (pbm->pp_meq == NULL) goto free_table; bzero(pbm->pp_meq->meq_va, - pbm->pp_meq->meq_nentries * sizeof(struct pyro_msi_msg)); + pbm->pp_meq->meq_nentries * sizeof(struct pyro_msi_msg) * + num_eq); bus_space_write_8(sc->sc_bust, sc->sc_csrh, FIRE_EQ_BASE_ADDR, pbm->pp_meq->meq_map->dm_segs[0].ds_addr); @@ -365,28 +381,123 @@ pyro_init_msi(struct pyro_softc *sc, str bus_space_write_8(sc->sc_bust, sc->sc_csrh, FIRE_MSI32_ADDR, pbm->pp_msiaddr); - bus_space_write_8(sc->sc_bust, sc->sc_csrh, FIRE_EQ_HEAD, 0); - bus_space_write_8(sc->sc_bust, sc->sc_csrh, FIRE_EQ_TAIL, 0); + if (OF_getprop(sc->sc_node, "msi-eq-to-devino", + msi_eq_devino, sizeof(msi_eq_devino)) == -1) { + OF_getprop(sc->sc_node, "msi-eq-devino", + msi_eq_devino, sizeof(msi_eq_devino)); + } + + pbm->pp_eq = mallocarray(num_eq, sizeof(*eq), M_DEVBUF, M_WAITOK); + pbm->pp_neq = num_eq; + + meq = pbm->pp_meq; + msgs = (struct pyro_msi_msg *)meq->meq_va; + + CPU_INFO_FOREACH(cii, ci) { + int unit = CPU_INFO_UNIT(ci); + eq = &pbm->pp_eq[unit]; + + eq->eq_id = unit; + eq->eq_intr = msi_eq_devino[2] + unit; + eq->eq_pbm = pbm; + snprintf(eq->eq_name, sizeof(eq->eq_name), "%s:eq%d", + sc->sc_dv.dv_xname, unit); + eq->eq_head = FIRE_EQ_HEAD(unit); + eq->eq_tail = FIRE_EQ_TAIL(unit); + eq->eq_ring = msgs + (unit * meq->meq_nentries); + eq->eq_mask = (meq->meq_nentries - 1); - OF_getprop(sc->sc_node, "msi-eq-to-devino", - msi_eq_devino, sizeof(msi_eq_devino)); + bus_space_write_8(sc->sc_bust, sc->sc_csrh, + FIRE_EQ_HEAD(unit), 0); + bus_space_write_8(sc->sc_bust, sc->sc_csrh, + FIRE_EQ_TAIL(unit), 0); - ihandle = msi_eq_devino[2] | sc->sc_ign; - if (pyro_intr_establish(pbm->pp_memt, sc->sc_bust, ihandle, - IPL_HIGH, 0, pyro_msi_eq_intr, pbm, sc->sc_dv.dv_xname) == NULL) - goto free_table; + ihandle = eq->eq_intr | sc->sc_ign; + eq->eq_ih = pyro_intr_establish_cpu(pbm->pp_memt, sc->sc_bust, + ihandle, IPL_HIGH, BUS_INTR_ESTABLISH_MPSAFE, ci, + pyro_msi_eq_intr, eq, eq->eq_name); + if (eq->eq_ih == NULL) { + /* XXX */ + goto free_table; + } - /* Enable EQ. */ - bus_space_write_8(sc->sc_bust, sc->sc_csrh, FIRE_EQ_CNTRL_SET, - FIRE_EQ_CTRL_SET_EN); + /* Enable EQ. */ + bus_space_write_8(sc->sc_bust, sc->sc_csrh, + FIRE_EQ_CNTRL_SET(unit), FIRE_EQ_CTRL_SET_EN); + } pbm->pp_flags |= PCI_FLAGS_MSI_ENABLED; + + /* + * XXX some devices may interrupt before a cpu has hatched, + * so rather than have their interrupts get dropped because + * the other cpu isn't running, point the interrupts at the + * boot cpu and redistribute them later on. this assumes that + * only msi and msix interrupts get targetted to other CPUs, + * so only the msi eqs need to be redistributed. + */ + config_mountroot(&sc->sc_dv, pyro_redistribute_msi); + return; free_table: free(pbm->pp_msi, M_DEVBUF, 0); } +void +pyro_redistribute_msi(struct device *dev) +{ + struct pyro_softc *sc = (struct pyro_softc *)dev; + struct pyro_pbm *pbm = sc->sc_pbm; + struct pyro_eq *eq; + struct cpu_info *ci; + CPU_INFO_ITERATOR cii; + uint64_t map, clr; + int i; + + CPU_INFO_FOREACH(cii, ci) { + unsigned int unit = CPU_INFO_UNIT(ci); + struct intrhand *ih; + + eq = &pbm->pp_eq[unit]; + ih = eq->eq_ih; + + map = bus_space_read_8(sc->sc_bust, sc->sc_csrh, + FIRE_INTR_MAP(eq->eq_intr)); + CLR(map, INTMAP_V); + bus_space_write_8(sc->sc_bust, sc->sc_csrh, + FIRE_INTR_MAP(eq->eq_intr), map); + + /* wait for pending to clear */ + for (i = 0; i < 10000; i++) { + clr = bus_space_read_8(sc->sc_bust, sc->sc_csrh, + FIRE_INTR_CLR(eq->eq_intr)); + clr &= 0x3; + if (clr != 0x3) + break; + + delay(10000); + } + + if (clr == 0x3) { + panic("%s: unable to clear pending state on eq %u", + sc->sc_dv.dv_xname, eq->eq_id); + } + + if (sc->sc_oberon) { + CLR(map, OBERON_INTRMAP_T_DESTID_MASK); + SET(map, ci->ci_upaid << OBERON_INTRMAP_T_DESTID_SHIFT); + } else { + CLR(map, FIRE_INTRMAP_T_JPID_MASK); + SET(map, ci->ci_upaid << FIRE_INTRMAP_T_JPID_SHIFT); + } + SET(map, INTMAP_V); + + bus_space_write_8(sc->sc_bust, sc->sc_csrh, + FIRE_INTR_MAP(eq->eq_intr), map); + } +} + int pyro_print(void *aux, const char *p) { @@ -513,6 +624,7 @@ pyro_alloc_bus_tag(struct pyro_pbm *pbm, bt->sparc_bus_map = pyro_bus_map; bt->sparc_bus_mmap = pyro_bus_mmap; bt->sparc_intr_establish = pyro_intr_establish; + bt->sparc_intr_establish_cpu = pyro_intr_establish_cpu; return (bt); } @@ -642,6 +754,15 @@ void * pyro_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle, int level, int flags, int (*handler)(void *), void *arg, const char *what) { + return (pyro_intr_establish_cpu(t, t0, ihandle, level, flags, NULL, + handler, arg, what)); +} + +void * +pyro_intr_establish_cpu(bus_space_tag_t t, bus_space_tag_t t0, int ihandle, + int level, int flags, struct cpu_info *cpu, + int (*handler)(void *), void *arg, const char *what) +{ struct pyro_pbm *pbm = t->cookie; struct pyro_softc *sc = pbm->pp_sc; struct intrhand *ih = NULL; @@ -661,11 +782,11 @@ pyro_intr_establish(bus_space_tag_t t, b evcount_attach(&ih->ih_count, ih->ih_name, NULL); - ih->ih_ack = pyro_msi_ack; - pbm->pp_msi[msinum] = ih; ih->ih_number = msinum; + ih->ih_ack = pyro_msi_ack; + ih->ih_cpu = cpu; if (flags & BUS_INTR_ESTABLISH_MPSAFE) ih->ih_mpsafe = 1; @@ -682,7 +803,9 @@ pyro_intr_establish(bus_space_tag_t t, b /* Map MSI to the right EQ and mark it as valid. */ reg = bus_space_read_8(sc->sc_bust, sc->sc_csrh, FIRE_MSI_MAP + msinum * 8); - reg &= ~FIRE_MSI_MAP_EQNUM; + CLR(reg, FIRE_MSI_MAP_EQNUM); + if (cpu != NULL) + SET(reg, CPU_INFO_UNIT(cpu)); bus_space_write_8(sc->sc_bust, sc->sc_csrh, FIRE_MSI_MAP + msinum * 8, reg); @@ -691,7 +814,7 @@ pyro_intr_establish(bus_space_tag_t t, b reg = bus_space_read_8(sc->sc_bust, sc->sc_csrh, FIRE_MSI_MAP + msinum * 8); - reg |= FIRE_MSI_MAP_V; + SET(reg, FIRE_MSI_MAP_V); bus_space_write_8(sc->sc_bust, sc->sc_csrh, FIRE_MSI_MAP + msinum * 8, reg); @@ -717,11 +840,12 @@ pyro_intr_establish(bus_space_tag_t t, b ino |= INTVEC(ihandle); } - ih = bus_intr_allocate(t0, handler, arg, ino, level, intrmapptr, + ih = bus_intr_allocate(t0, handler, arg, ino, level, NULL, intrclrptr, what); if (ih == NULL) return (NULL); + ih->ih_cpu = cpu; if (flags & BUS_INTR_ESTABLISH_MPSAFE) ih->ih_mpsafe = 1; @@ -733,15 +857,39 @@ pyro_intr_establish(bus_space_tag_t t, b intrmap = *intrmapptr; intrmap &= ~FIRE_INTRMAP_INT_CNTRL_NUM_MASK; intrmap |= FIRE_INTRMAP_INT_CNTRL_NUM0; +#if 0 + if (sc->sc_oberon) { + intrmap &= ~OBERON_INTRMAP_T_DESTID_MASK; + if (cpu != NULL) { + intrmap |= cpu->ci_upaid << + OBERON_INTRMAP_T_DESTID_SHIFT; + } else { + intrmap |= CPU_JUPITERID << + OBERON_INTRMAP_T_DESTID_SHIFT; + } + } else { + intrmap &= ~FIRE_INTRMAP_T_JPID_MASK; + if (cpu != NULL) { + intrmap |= cpu->ci_upaid << + FIRE_INTRMAP_T_JPID_SHIFT; + } else { + intrmap |= CPU_UPAID << + FIRE_INTRMAP_T_JPID_SHIFT; + } + } +#else if (sc->sc_oberon) { intrmap &= ~OBERON_INTRMAP_T_DESTID_MASK; intrmap |= CPU_JUPITERID << OBERON_INTRMAP_T_DESTID_SHIFT; } else { intrmap &= ~FIRE_INTRMAP_T_JPID_MASK; - intrmap |= CPU_UPAID << FIRE_INTRMAP_T_JPID_SHIFT; + intrmap |= CPU_UPAID << + FIRE_INTRMAP_T_JPID_SHIFT; } +#endif intrmap |= INTMAP_V; + membar_producer(); *intrmapptr = intrmap; intrmap = *intrmapptr; ih->ih_number |= intrmap & INTMAP_INR; @@ -758,28 +906,28 @@ pyro_msi_ack(struct intrhand *ih) int pyro_msi_eq_intr(void *arg) { - struct pyro_pbm *pbm = arg; + struct pyro_eq *eq = arg; + struct pyro_pbm *pbm = eq->eq_pbm; struct pyro_softc *sc = pbm->pp_sc; - struct msi_eq *meq = pbm->pp_meq; struct pyro_msi_msg *msg; uint64_t head, tail; struct intrhand *ih; int msinum; - head = bus_space_read_8(sc->sc_bust, sc->sc_csrh, FIRE_EQ_HEAD); - tail = bus_space_read_8(sc->sc_bust, sc->sc_csrh, FIRE_EQ_TAIL); + head = bus_space_read_8(sc->sc_bust, sc->sc_csrh, eq->eq_head); + tail = bus_space_read_8(sc->sc_bust, sc->sc_csrh, eq->eq_tail); if (head == tail) return (0); - while (head != tail) { - msg = (struct pyro_msi_msg *)meq->meq_va; - - if (msg[head].mm_type == 0) + do { + msg = &eq->eq_ring[head]; + if (msg->mm_type == 0) break; - msg[head].mm_type = 0; - msinum = msg[head].mm_data; + msg->mm_type = 0; + + msinum = msg->mm_data; ih = pbm->pp_msi[msinum]; bus_space_write_8(sc->sc_bust, sc->sc_csrh, FIRE_MSI_CLEAR + msinum * 8, FIRE_MSI_CLEAR_EQWR_N); @@ -787,10 +935,10 @@ pyro_msi_eq_intr(void *arg) send_softint(-1, ih->ih_pil, ih); head += 1; - head &= (meq->meq_nentries - 1); - } + head &= eq->eq_mask; + } while (head != tail); - bus_space_write_8(sc->sc_bust, sc->sc_csrh, FIRE_EQ_HEAD, head); + bus_space_write_8(sc->sc_bust, sc->sc_csrh, eq->eq_head, head); return (1); } Index: dev/pyrovar.h =================================================================== RCS file: /cvs/src/sys/arch/sparc64/dev/pyrovar.h,v retrieving revision 1.4 diff -u -p -r1.4 pyrovar.h --- dev/pyrovar.h 6 Jul 2011 05:48:57 -0000 1.4 +++ dev/pyrovar.h 15 Jun 2020 06:07:16 -0000 @@ -44,6 +44,20 @@ struct pyro_range { u_int32_t size_lo; }; +struct pyro_eq { + char eq_name[16]; + struct pyro_pbm *eq_pbm; + void *eq_ih; + bus_size_t eq_head; + bus_size_t eq_tail; + struct pyro_msi_msg *eq_ring; + uint64_t eq_mask; + + unsigned int eq_id; + unsigned int eq_intr; + uint64_t eq_count; +}; + struct pyro_pbm { struct pyro_softc *pp_sc; @@ -65,6 +79,9 @@ struct pyro_pbm { int pp_msinum; struct intrhand **pp_msi; + unsigned int pp_neq; + struct pyro_eq *pp_eq; + int pp_flags; }; @@ -76,6 +93,8 @@ struct pyro_softc { bus_space_tag_t sc_bust; bus_addr_t sc_csr, sc_xbc; bus_space_handle_t sc_csrh, sc_xbch; + + struct pyro_pbm *sc_pbm; int sc_oberon; }; Index: dev/vpci.c =================================================================== RCS file: /cvs/src/sys/arch/sparc64/dev/vpci.c,v retrieving revision 1.29 diff -u -p -r1.29 vpci.c --- dev/vpci.c 26 Jul 2019 11:33:05 -0000 1.29 +++ dev/vpci.c 15 Jun 2020 06:07:16 -0000 @@ -118,6 +118,8 @@ paddr_t vpci_bus_mmap(bus_space_tag_t, b int, int); void *vpci_intr_establish(bus_space_tag_t, bus_space_tag_t, int, int, int, int (*)(void *), void *, const char *); +void *vpci_intr_establish_cpu(bus_space_tag_t, bus_space_tag_t, int, int, + int, struct cpu_info *, int (*)(void *), void *, const char *); void vpci_intr_ack(struct intrhand *); void vpci_msi_ack(struct intrhand *); @@ -249,8 +251,13 @@ vpci_init_msi(struct vpci_softc *sc, str u_int32_t msi_eq_devino[3] = { 0, 36, 24 }; u_int32_t msi_range[2]; uint64_t sysino; - int msis, msi_eq_size; + int msis, msi_eq_size, num_eq, eq; int err; + CPU_INFO_ITERATOR cii; + struct cpu_info *ci; + + /* one eq per cpu */ + num_eq = ncpus; if (OF_getprop(sc->sc_node, "msi-address-ranges", msi_addr_range, sizeof(msi_addr_range)) <= 0) @@ -265,7 +272,7 @@ vpci_init_msi(struct vpci_softc *sc, str return; msi_eq_size = getpropint(sc->sc_node, "msi-eq-size", 256); - pbm->vp_meq = msi_eq_alloc(sc->sc_dmat, msi_eq_size); + pbm->vp_meq = msi_eq_alloc(sc->sc_dmat, msi_eq_size, num_eq); if (pbm->vp_meq == NULL) goto free_table; @@ -274,33 +281,39 @@ vpci_init_msi(struct vpci_softc *sc, str goto free_table; pbm->vp_msibase = msi_range[0]; - err = hv_pci_msiq_conf(pbm->vp_devhandle, 0, - pbm->vp_meq->meq_map->dm_segs[0].ds_addr, - pbm->vp_meq->meq_nentries); - if (err != H_EOK) - goto free_queue; + CPU_INFO_FOREACH(cii, ci) { + eq = CPU_INFO_UNIT(ci); - OF_getprop(sc->sc_node, "msi-eq-to-devino", - msi_eq_devino, sizeof(msi_eq_devino)); - err = sun4v_intr_devino_to_sysino(pbm->vp_devhandle, - msi_eq_devino[2], &sysino); - if (err != H_EOK) - goto disable_queue; + err = hv_pci_msiq_conf(pbm->vp_devhandle, eq, + pbm->vp_meq->meq_map->dm_segs[0].ds_addr + + msi_eq_offset(pbm->vp_meq, eq), + pbm->vp_meq->meq_nentries); + if (err != H_EOK) + goto free_queue; - if (vpci_intr_establish(pbm->vp_memt, pbm->vp_memt, sysino, - IPL_HIGH, 0, vpci_msi_eq_intr, pbm, sc->sc_dv.dv_xname) == NULL) - goto disable_queue; - - err = hv_pci_msiq_setvalid(pbm->vp_devhandle, 0, PCI_MSIQ_VALID); - if (err != H_EOK) { - printf("%s: pci_msiq_setvalid: err %d\n", __func__, err); - goto disable_queue; - } + OF_getprop(sc->sc_node, "msi-eq-to-devino", + msi_eq_devino, sizeof(msi_eq_devino)); + err = sun4v_intr_devino_to_sysino(pbm->vp_devhandle, + msi_eq_devino[2] + eq, &sysino); + if (err != H_EOK) + goto disable_queue; + + if (vpci_intr_establish_cpu(pbm->vp_memt, pbm->vp_memt, sysino, + IPL_HIGH | IPL_MPSAFE, 0, ci, vpci_msi_eq_intr, pbm, + sc->sc_dv.dv_xname) == NULL) + goto disable_queue; + + err = hv_pci_msiq_setvalid(pbm->vp_devhandle, eq, PCI_MSIQ_VALID); + if (err != H_EOK) { + printf("%s: pci_msiq_setvalid(%d): err %d\n", __func__, eq, err); + goto disable_queue; + } - err = hv_pci_msiq_setstate(pbm->vp_devhandle, 0, PCI_MSIQSTATE_IDLE); - if (err != H_EOK) { - printf("%s: pci_msiq_setstate: err %d\n", __func__, err); - goto disable_queue; + err = hv_pci_msiq_setstate(pbm->vp_devhandle, eq, PCI_MSIQSTATE_IDLE); + if (err != H_EOK) { + printf("%s: pci_msiq_setstate(%d): err %d\n", __func__, eq, err); + goto disable_queue; + } } pbm->vp_flags |= PCI_FLAGS_MSI_ENABLED; @@ -547,6 +560,15 @@ void * vpci_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle, int level, int flags, int (*handler)(void *), void *arg, const char *what) { + return (vpci_intr_establish_cpu(t, t0, ihandle, level, flags, NULL, + handler, arg, what)); +} + +void * +vpci_intr_establish_cpu(bus_space_tag_t t, bus_space_tag_t t0, int ihandle, + int level, int flags, struct cpu_info *cpu, int (*handler)(void *), void *arg, + const char *what) +{ struct vpci_pbm *pbm = t->cookie; uint64_t devhandle = pbm->vp_devhandle; uint64_t sysino = INTVEC(ihandle); @@ -566,6 +588,7 @@ vpci_intr_establish(bus_space_tag_t t, b pcitag_t tag = PCI_INTR_TAG(ihandle); int msinum = pbm->vp_msinum++; int msi = pbm->vp_msibase + msinum; + int eq = 0; evcount_attach(&ih->ih_count, ih->ih_name, NULL); @@ -584,7 +607,10 @@ vpci_intr_establish(bus_space_tag_t t, b break; } - err = hv_pci_msi_setmsiq(devhandle, msi, 0, 0); + if (cpu != NULL) + eq = CPU_INFO_UNIT(cpu); + + err = hv_pci_msi_setmsiq(devhandle, msi, eq, 0); if (err != H_EOK) { printf("%s: pci_msi_setmsiq: err %d\n", __func__, err); return (NULL); @@ -650,25 +676,30 @@ vpci_msi_eq_intr(void *arg) struct vpci_pbm *pbm = arg; struct msi_eq *meq = pbm->vp_meq; struct vpci_msi_msg *msg; + struct cpu_info *cpu; uint64_t devhandle = pbm->vp_devhandle; uint64_t head, tail; struct intrhand *ih; - int msinum, msi; + int msinum, msi, eq; int err; - err = hv_pci_msiq_gethead(devhandle, 0, &head); + cpu = curcpu(); + eq = CPU_INFO_UNIT(cpu); + + err = hv_pci_msiq_gethead(devhandle, eq, &head); if (err != H_EOK) - printf("%s: pci_msiq_gethead: %d\n", __func__, err); + printf("%s: pci_msiq_gethead(%d): %d\n", __func__, eq, err); - err = hv_pci_msiq_gettail(devhandle, 0, &tail); + err = hv_pci_msiq_gettail(devhandle, eq, &tail); if (err != H_EOK) - printf("%s: pci_msiq_gettail: %d\n", __func__, err); + printf("%s: pci_msiq_gettail(%d): %d\n", __func__, eq, err); if (head == tail) return (0); while (head != tail) { - msg = (struct vpci_msi_msg *)(meq->meq_va + head); + msg = (struct vpci_msi_msg *)(meq->meq_va + + (eq * meq->meq_nentries) + head); if (msg->mm_type == 0) break; @@ -687,9 +718,9 @@ vpci_msi_eq_intr(void *arg) head &= ((meq->meq_nentries * sizeof(struct vpci_msi_msg)) - 1); } - err = hv_pci_msiq_sethead(devhandle, 0, head); + err = hv_pci_msiq_sethead(devhandle, eq, head); if (err != H_EOK) - printf("%s: pci_msiq_sethead: %d\n", __func__, err); + printf("%s: pci_msiq_sethead(%d): %d\n", __func__, eq, err); return (1); } Index: include/bus.h =================================================================== RCS file: /cvs/src/sys/arch/sparc64/include/bus.h,v retrieving revision 1.33 diff -u -p -r1.33 bus.h --- include/bus.h 25 May 2017 03:19:39 -0000 1.33 +++ include/bus.h 15 Jun 2020 06:07:16 -0000 @@ -206,6 +206,12 @@ struct sparc_bus_space_tag { int, int, int, int (*)(void *), void *, const char *); + void *(*sparc_intr_establish_cpu)(bus_space_tag_t, + bus_space_tag_t, + int, int, int, + struct cpu_info *, + int (*)(void *), void *, + const char *); bus_addr_t (*sparc_bus_addr)(bus_space_tag_t, bus_space_tag_t, bus_space_handle_t); @@ -267,6 +273,16 @@ void *bus_intr_establish( int, /*device class level, see machine/intr.h*/ int, /*flags*/ + int (*)(void *), /*handler*/ + void *, /*handler arg*/ + const char *); /*what*/ +void *bus_intr_establish_cpu( + bus_space_tag_t, + int, /*bus-specific intr*/ + int, /*device class level, + see machine/intr.h*/ + int, /*flags*/ + struct cpu_info *, /*cpu*/ int (*)(void *), /*handler*/ void *, /*handler arg*/ const char *); /*what*/ Index: include/pci_machdep.h =================================================================== RCS file: /cvs/src/sys/arch/sparc64/include/pci_machdep.h,v retrieving revision 1.36 diff -u -p -r1.36 pci_machdep.h --- include/pci_machdep.h 5 Dec 2019 12:46:54 -0000 1.36 +++ include/pci_machdep.h 15 Jun 2020 06:07:16 -0000 @@ -125,4 +125,8 @@ int sparc64_pci_enumerate_bus(struct pc #define pci_dev_postattach(a, b) +void *pci_intr_establish_cpu(pci_chipset_tag_t, pci_intr_handle_t, + int, int, int (*)(void *), void *, + const char *); + #endif /* _MACHINE_PCI_MACHDEP_H_ */ Index: sparc64/intr.c =================================================================== RCS file: /cvs/src/sys/arch/sparc64/sparc64/intr.c,v retrieving revision 1.59 diff -u -p -r1.59 intr.c --- sparc64/intr.c 21 Mar 2018 14:25:14 -0000 1.59 +++ sparc64/intr.c 15 Jun 2020 06:07:16 -0000 @@ -202,7 +202,12 @@ intr_establish(int level, struct intrhan ih->ih_pil = level; /* XXXX caller should have done this before */ ih->ih_pending = 0; /* XXXX caller should have done this before */ ih->ih_next = NULL; - ih->ih_cpu = cpus; + if (ih->ih_cpu == NULL) + ih->ih_cpu = curcpu(); + else if (!ih->ih_mpsafe) { + panic("non-mpsafe interrupt \"%s\" " + "established on a specific cpu", ih->ih_name); + } if (ih->ih_clr) ih->ih_ack = intr_ack; else @@ -288,7 +293,7 @@ intr_establish(int level, struct intrhan *ih->ih_clr = INTCLR_IDLE; if (ih->ih_map) { - id = CPU_UPAID; + id = ih->ih_cpu->ci_upaid; m = *ih->ih_map; if (INTTID(m) != id) { #ifdef DEBUG Index: sparc64/machdep.c =================================================================== RCS file: /cvs/src/sys/arch/sparc64/sparc64/machdep.c,v retrieving revision 1.197 diff -u -p -r1.197 machdep.c --- sparc64/machdep.c 5 Jun 2020 14:25:05 -0000 1.197 +++ sparc64/machdep.c 15 Jun 2020 06:07:16 -0000 @@ -1822,21 +1822,22 @@ sparc_bus_free(bus_space_tag_t t, bus_sp } static const struct sparc_bus_space_tag _mainbus_space_tag = { - NULL, /* cookie */ - NULL, /* parent bus tag */ - UPA_BUS_SPACE, /* type */ - ASI_PRIMARY, - ASI_PRIMARY, - "mainbus", - sparc_bus_alloc, - sparc_bus_free, - sparc_bus_map, /* bus_space_map */ - sparc_bus_protect, /* bus_space_protect */ - sparc_bus_unmap, /* bus_space_unmap */ - sparc_bus_subregion, /* bus_space_subregion */ - sparc_bus_mmap, /* bus_space_mmap */ - sparc_mainbus_intr_establish, /* bus_intr_establish */ - sparc_bus_addr /* bus_space_addr */ + .cookie = NULL, + .parent = NULL, + .default_type = UPA_BUS_SPACE, + .asi = ASI_PRIMARY, + .sasi = ASI_PRIMARY, + .name = "mainbus", + .sparc_bus_alloc = sparc_bus_alloc, + .sparc_bus_free = sparc_bus_free, + .sparc_bus_map = sparc_bus_map, + .sparc_bus_protect = sparc_bus_protect, + .sparc_bus_unmap = sparc_bus_unmap, + .sparc_bus_subregion = sparc_bus_subregion, + .sparc_bus_mmap = sparc_bus_mmap, + .sparc_intr_establish = sparc_mainbus_intr_establish, + /*.sparc_intr_establish_cpu*/ + .sparc_bus_addr = sparc_bus_addr }; const bus_space_tag_t mainbus_space_tag = &_mainbus_space_tag; @@ -1996,6 +1997,23 @@ bus_intr_establish(bus_space_tag_t t, in _BS_PRECALL(t, sparc_intr_establish); ret = _BS_CALL(t, sparc_intr_establish)(t, t0, p, l, f, h, a, w); + _BS_POSTCALL; + return (ret); +} + +void * +bus_intr_establish_cpu(bus_space_tag_t t, int p, int l, int f, + struct cpu_info *ci, int (*h)(void *), void *a, const char *w) +{ + const bus_space_tag_t t0 = t; + void *ret; + + if (t->sparc_intr_establish_cpu == NULL) + return (bus_intr_establish(t, p, l, f, h, a, w)); + + _BS_PRECALL(t, sparc_intr_establish_cpu); + ret = _BS_CALL(t, sparc_intr_establish_cpu)(t, t0, p, l, f, ci, + h, a, w); _BS_POSTCALL; return (ret); }