Index: if_myx.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_myx.c,v retrieving revision 1.86 diff -u -p -r1.86 if_myx.c --- if_myx.c 19 Nov 2015 12:46:08 -0000 1.86 +++ if_myx.c 23 Nov 2015 14:10:13 -0000 @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include @@ -146,7 +148,9 @@ struct myx_softc { u_int32_t sc_tx_ring_offset; u_int sc_tx_nsegs; u_int32_t sc_tx_count; /* shadows ms_txdonecnt */ - u_int sc_tx_ring_idx; + u_int sc_tx_ring_prod; + u_int sc_tx_ring_cons; + struct task sc_tx_task; u_int sc_tx_prod; u_int sc_tx_cons; @@ -201,6 +205,7 @@ void myx_iff(struct myx_softc *); void myx_down(struct myx_softc *); void myx_start(struct ifnet *); +void myx_start_task(void *); void myx_write_txd_tail(struct myx_softc *, struct myx_slot *, u_int8_t, u_int32_t, u_int); int myx_load_mbuf(struct myx_softc *, struct myx_slot *, struct mbuf *); @@ -264,6 +269,8 @@ myx_attach(struct device *parent, struct timeout_set(&sc->sc_rx_ring[MYX_RXBIG].mrr_refill, myx_refill, &sc->sc_rx_ring[MYX_RXBIG]); + task_set(&sc->sc_tx_task, myx_start_task, sc); + /* Map the PCI memory space */ memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, MYXBAR0); if (pci_mapreg_map(pa, MYXBAR0, memtype, BUS_SPACE_MAP_PREFETCHABLE, @@ -1032,7 +1039,8 @@ myx_up(struct myx_softc *sc) printf("%s: unable to get tx ring size\n", DEVNAME(sc)); goto free_pad; } - sc->sc_tx_ring_idx = 0; + sc->sc_tx_ring_prod = 0; + sc->sc_tx_ring_cons = 0; sc->sc_tx_ring_count = r / sizeof(struct myx_tx_desc); sc->sc_tx_nsegs = min(16, sc->sc_tx_ring_count / 4); /* magic */ sc->sc_tx_count = 0; @@ -1316,6 +1324,14 @@ myx_iff(struct myx_softc *sc) return; } } +void +myx_down_barrier(void *r); + +void +myx_down_barrier(void *r) +{ + refcnt_rele_wake(r); +} void myx_down(struct myx_softc *sc) @@ -1328,6 +1344,9 @@ myx_down(struct myx_softc *sc) int s; int ring; + struct task t; + struct refcnt r; + bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); sc->sc_linkdown = sts->ms_linkdown; @@ -1361,6 +1380,12 @@ myx_down(struct myx_softc *sc) CLR(ifp->if_flags, IFF_RUNNING | IFF_OACTIVE); + refcnt_init(&r); + refcnt_take(&r); + task_set(&t, myx_down_barrier, &r); + task_add(systqmp, &t); + refcnt_finalize(&r, "myxbar"); + for (ring = 0; ring < 2; ring++) { struct myx_rx_ring *mrr = &sc->sc_rx_ring[ring]; @@ -1424,8 +1449,18 @@ myx_write_txd_tail(struct myx_softc *sc, void myx_start(struct ifnet *ifp) { - struct myx_tx_desc txd; struct myx_softc *sc = ifp->if_softc; + +// myx_start_task(sc); + task_add(systqmp, &sc->sc_tx_task); +} + +void +myx_start_task(void *scp) +{ + struct myx_softc *sc = scp; + struct ifnet *ifp = &sc->sc_ac.ac_if; + struct myx_tx_desc txd; struct myx_slot *ms; bus_dmamap_t map; struct mbuf *m; @@ -1439,23 +1474,24 @@ myx_start(struct ifnet *ifp) IFQ_IS_EMPTY(&ifp->if_snd)) return; - prod = sc->sc_tx_prod; - cons = sc->sc_tx_cons; + idx = sc->sc_tx_ring_prod; + cons = sc->sc_tx_ring_cons; /* figure out space */ - free = prod; - if (cons >= prod) + free = idx; + if (cons >= idx) free += sc->sc_tx_ring_count; free -= cons; - /* keep track of our usage */ - cons = prod; + cons = prod = sc->sc_tx_prod; used = 0; for (;;) { - if (used + sc->sc_tx_nsegs + 1 > free) { + if (used + sc->sc_tx_nsegs + 1 >= free) { + KERNEL_LOCK(); SET(ifp->if_flags, IFF_OACTIVE); + KERNEL_UNLOCK(); break; } @@ -1478,7 +1514,7 @@ myx_start(struct ifnet *ifp) map = ms->ms_map; bus_dmamap_sync(sc->sc_dmat, map, 0, - map->dm_mapsize, BUS_DMASYNC_POSTWRITE); + map->dm_mapsize, BUS_DMASYNC_PREWRITE); used += map->dm_nsegs + (map->dm_mapsize < 60 ? 1 : 0); @@ -1490,7 +1526,6 @@ myx_start(struct ifnet *ifp) return; ms = &sc->sc_tx_slots[cons]; - idx = sc->sc_tx_ring_idx; for (;;) { idx += ms->ms_map->dm_nsegs + @@ -1537,26 +1572,27 @@ myx_start(struct ifnet *ifp) txd.tx_flags = flags | MYXTXD_FLAGS_FIRST; /* make sure the first descriptor is seen after the others */ - myx_write_txd_tail(sc, ms, flags, offset, sc->sc_tx_ring_idx); + myx_write_txd_tail(sc, ms, flags, offset, sc->sc_tx_ring_prod); myx_bus_space_write(sc, - offset + sizeof(txd) * sc->sc_tx_ring_idx, &txd, + offset + sizeof(txd) * sc->sc_tx_ring_prod, &txd, sizeof(txd) - sizeof(myx_bus_t)); bus_space_barrier(sc->sc_memt, sc->sc_memh, offset, sizeof(txd) * sc->sc_tx_ring_count, BUS_SPACE_BARRIER_WRITE); myx_bus_space_write(sc, - offset + sizeof(txd) * (sc->sc_tx_ring_idx + 1) - sizeof(myx_bus_t), + offset + sizeof(txd) * (sc->sc_tx_ring_prod + 1) - + sizeof(myx_bus_t), (u_int8_t *)&txd + sizeof(txd) - sizeof(myx_bus_t), sizeof(myx_bus_t)); bus_space_barrier(sc->sc_memt, sc->sc_memh, - offset + sizeof(txd) * sc->sc_tx_ring_idx, sizeof(txd), + offset + sizeof(txd) * sc->sc_tx_ring_prod, sizeof(txd), BUS_SPACE_BARRIER_WRITE); /* commit */ - sc->sc_tx_ring_idx = idx; + sc->sc_tx_ring_prod = idx; sc->sc_tx_prod = prod; } @@ -1663,8 +1699,8 @@ myx_intr(void *arg) if (start) { KERNEL_LOCK(); CLR(ifp->if_flags, IFF_OACTIVE); - myx_start(ifp); KERNEL_UNLOCK(); + myx_start(ifp); } return (1); @@ -1688,16 +1724,16 @@ myx_txeof(struct myx_softc *sc, u_int32_ struct ifnet *ifp = &sc->sc_ac.ac_if; struct myx_slot *ms; bus_dmamap_t map; - u_int free = 0; - u_int cons; + u_int idx, cons; + idx = sc->sc_tx_ring_cons; cons = sc->sc_tx_cons; do { ms = &sc->sc_tx_slots[cons]; map = ms->ms_map; - free += map->dm_nsegs + (map->dm_mapsize < 60 ? 1 : 0); + idx += map->dm_nsegs + (map->dm_mapsize < 60 ? 1 : 0); bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, BUS_DMASYNC_POSTWRITE); @@ -1710,7 +1746,33 @@ myx_txeof(struct myx_softc *sc, u_int32_ cons = 0; } while (++sc->sc_tx_count != done_count); + if (idx >= sc->sc_tx_ring_count) + idx -= sc->sc_tx_ring_count; + + sc->sc_tx_ring_cons = idx; sc->sc_tx_cons = cons; +} +void +myx_dump(void); + +void +myx_dump(void) +{ + struct myx_softc *sc; + int i; + + for (i = 0; i < myx_cd.cd_ndevs; i++) { + sc = myx_cd.cd_devs[i]; + if (sc == NULL) + continue; + + printf("%s: count %u tx_count %u sts %u\n", DEVNAME(sc), + sc->sc_tx_ring_count, sc->sc_tx_count, + betoh32(sc->sc_sts->ms_txdonecnt)); + printf("%s: prod %u cons %u ring prod %u ring cons %u\n", + DEVNAME(sc), sc->sc_tx_prod, sc->sc_tx_cons, + sc->sc_tx_ring_cons, sc->sc_tx_ring_prod); + } } void