From 4807ddb450d0cb7d02d5e7e17b74f658d0999c96 Mon Sep 17 00:00:00 2001 From: Jonathan Matthew Date: Mon, 20 Dec 2021 04:21:33 +0000 Subject: Rework the tx path to use the consumer and producer positions to work out the number of slots available, and to put packets on the ring until fewer than DWGE_NTXSEGS slots are left, making dwge_start() and dwge_txeof() work independently. While here, only write to GMAC_TX_POLL_DEMAND once per call to dwge_start() rather than once per packet. Adjust the rx interrupt path to check the number of slots in use and return slots once per interrupt. Add interrupt and ifq barriers before taking the interface down. With all of this done, we can mark dwge(4) mpsafe. ok dlg@ patrick@ --- sys/dev/fdt/if_dwge.c | 78 +++++++++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/sys/dev/fdt/if_dwge.c b/sys/dev/fdt/if_dwge.c index 3f2d24a0e6d..400807576b0 100644 --- a/sys/dev/fdt/if_dwge.c +++ b/sys/dev/fdt/if_dwge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_dwge.c,v 1.12 2021/10/24 17:52:26 mpi Exp $ */ +/* $OpenBSD: if_dwge.c,v 1.13 2021/12/20 04:21:32 jmatthew Exp $ */ /* * Copyright (c) 2008, 2019 Mark Kettenis * Copyright (c) 2017 Patrick Wildt @@ -234,6 +234,7 @@ struct dwge_softc { bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; bus_dma_tag_t sc_dmat; + void *sc_ih; struct arpcom sc_ac; #define sc_lladdr sc_ac.ac_enaddr @@ -247,7 +248,6 @@ struct dwge_softc { struct dwge_buf *sc_txbuf; struct dwge_desc *sc_txdesc; int sc_tx_prod; - int sc_tx_cnt; int sc_tx_cons; struct dwge_dmamem *sc_rxring; @@ -289,7 +289,7 @@ uint32_t dwge_read(struct dwge_softc *, bus_addr_t); void dwge_write(struct dwge_softc *, bus_addr_t, uint32_t); int dwge_ioctl(struct ifnet *, u_long, caddr_t); -void dwge_start(struct ifnet *); +void dwge_start(struct ifqueue *); void dwge_watchdog(struct ifnet *); int dwge_media_change(struct ifnet *); @@ -312,7 +312,7 @@ void dwge_rx_proc(struct dwge_softc *); void dwge_up(struct dwge_softc *); void dwge_down(struct dwge_softc *); void dwge_iff(struct dwge_softc *); -int dwge_encap(struct dwge_softc *, struct mbuf *, int *); +int dwge_encap(struct dwge_softc *, struct mbuf *, int *, int *); void dwge_reset(struct dwge_softc *); void dwge_stop_dma(struct dwge_softc *); @@ -422,8 +422,9 @@ dwge_attach(struct device *parent, struct device *self, void *aux) ifp = &sc->sc_ac.ac_if; ifp->if_softc = sc; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_xflags = IFXF_MPSAFE; ifp->if_ioctl = dwge_ioctl; - ifp->if_start = dwge_start; + ifp->if_qstart = dwge_start; ifp->if_watchdog = dwge_watchdog; ifq_set_maxlen(&ifp->if_snd, DWGE_NTXDESC - 1); bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); @@ -535,8 +536,10 @@ dwge_attach(struct device *parent, struct device *self, void *aux) dwge_write(sc, GMAC_MMC_TX_INT_MSK, 0xffffffff); dwge_write(sc, GMAC_MMC_IPC_INT_MSK, 0xffffffff); - fdt_intr_establish(faa->fa_node, IPL_NET, dwge_intr, sc, - sc->sc_dev.dv_xname); + sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_NET | IPL_MPSAFE, + dwge_intr, sc, sc->sc_dev.dv_xname); + if (sc->sc_ih == NULL) + printf("%s: can't establish interrupt\n", sc->sc_dev.dv_xname); } void @@ -612,11 +615,12 @@ dwge_lladdr_write(struct dwge_softc *sc) } void -dwge_start(struct ifnet *ifp) +dwge_start(struct ifqueue *ifq) { + struct ifnet *ifp = ifq->ifq_if; struct dwge_softc *sc = ifp->if_softc; struct mbuf *m; - int error, idx; + int error, idx, left, used; if (!(ifp->if_flags & IFF_RUNNING)) return; @@ -628,27 +632,29 @@ dwge_start(struct ifnet *ifp) return; idx = sc->sc_tx_prod; - while ((sc->sc_txdesc[idx].sd_status & TDES0_OWN) == 0) { - m = ifq_deq_begin(&ifp->if_snd); - if (m == NULL) + left = sc->sc_tx_cons; + if (left <= idx) + left += DWGE_NTXDESC; + left -= idx; + used = 0; + + for (;;) { + if (used + DWGE_NTXSEGS + 1 > left) { + ifq_set_oactive(ifq); break; + } - error = dwge_encap(sc, m, &idx); - if (error == ENOBUFS) { - ifq_deq_rollback(&ifp->if_snd, m); - ifq_set_oactive(&ifp->if_snd); + m = ifq_dequeue(ifq); + if (m == NULL) break; - } + + error = dwge_encap(sc, m, &idx, &used); if (error == EFBIG) { - ifq_deq_commit(&ifp->if_snd, m); m_freem(m); /* give up: drop it */ ifp->if_oerrors++; continue; } - /* Now we are committed to transmit the packet. */ - ifq_deq_commit(&ifp->if_snd, m); - #if NBPFILTER > 0 if (ifp->if_bpf) bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); @@ -660,6 +666,8 @@ dwge_start(struct ifnet *ifp) /* Set a timeout in case the chip goes out to lunch. */ ifp->if_timer = 5; + + dwge_write(sc, GMAC_TX_POLL_DEMAND, 0xffffffff); } } @@ -901,7 +909,7 @@ dwge_tx_proc(struct dwge_softc *sc) BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); txfree = 0; - while (sc->sc_tx_cnt > 0) { + while (sc->sc_tx_cons != sc->sc_tx_prod) { idx = sc->sc_tx_cons; KASSERT(idx < DWGE_NTXDESC); @@ -920,7 +928,6 @@ dwge_tx_proc(struct dwge_softc *sc) } txfree++; - sc->sc_tx_cnt--; if (sc->sc_tx_cons == (DWGE_NTXDESC - 1)) sc->sc_tx_cons = 0; @@ -930,7 +937,7 @@ dwge_tx_proc(struct dwge_softc *sc) txd->sd_status = 0; } - if (sc->sc_tx_cnt == 0) + if (sc->sc_tx_cons == sc->sc_tx_prod) ifp->if_timer = 0; if (txfree) { @@ -947,7 +954,7 @@ dwge_rx_proc(struct dwge_softc *sc) struct dwge_buf *rxb; struct mbuf_list ml = MBUF_LIST_INITIALIZER(); struct mbuf *m; - int idx, len; + int idx, len, cnt, put; if ((ifp->if_flags & IFF_RUNNING) == 0) return; @@ -956,7 +963,9 @@ dwge_rx_proc(struct dwge_softc *sc) DWGE_DMA_LEN(sc->sc_rxring), BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); - while (if_rxr_inuse(&sc->sc_rx_ring) > 0) { + cnt = if_rxr_inuse(&sc->sc_rx_ring); + put = 0; + while (put < cnt) { idx = sc->sc_rx_cons; KASSERT(idx < DWGE_NRXDESC); @@ -982,13 +991,14 @@ dwge_rx_proc(struct dwge_softc *sc) ml_enqueue(&ml, m); - if_rxr_put(&sc->sc_rx_ring, 1); + put++; if (sc->sc_rx_cons == (DWGE_NRXDESC - 1)) sc->sc_rx_cons = 0; else sc->sc_rx_cons++; } + if_rxr_put(&sc->sc_rx_ring, put); if (ifiq_input(&ifp->if_rcv, &ml)) if_rxr_livelocked(&sc->sc_rx_ring); @@ -1030,7 +1040,6 @@ dwge_up(struct dwge_softc *sc) 0, DWGE_DMA_LEN(sc->sc_txring), BUS_DMASYNC_PREWRITE); sc->sc_tx_prod = sc->sc_tx_cons = 0; - sc->sc_tx_cnt = 0; dwge_write(sc, GMAC_TX_DESC_LIST_ADDR, DWGE_DMA_DVA(sc->sc_txring)); @@ -1123,6 +1132,9 @@ dwge_down(struct dwge_softc *sc) dwge_write(sc, GMAC_INT_ENA, 0); + intr_barrier(sc->sc_ih); + ifq_barrier(&ifp->if_snd); + for (i = 0; i < DWGE_NTXDESC; i++) { txb = &sc->sc_txbuf[i]; if (txb->tb_m) { @@ -1208,7 +1220,7 @@ dwge_iff(struct dwge_softc *sc) } int -dwge_encap(struct dwge_softc *sc, struct mbuf *m, int *idx) +dwge_encap(struct dwge_softc *sc, struct mbuf *m, int *idx, int *used) { struct dwge_desc *txd, *txd_start; bus_dmamap_t map; @@ -1224,11 +1236,6 @@ dwge_encap(struct dwge_softc *sc, struct mbuf *m, int *idx) return (EFBIG); } - if (map->dm_nsegs > (DWGE_NTXDESC - sc->sc_tx_cnt - 2)) { - bus_dmamap_unload(sc->sc_dmat, map); - return (ENOBUFS); - } - /* Sync the DMA map. */ bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, BUS_DMASYNC_PREWRITE); @@ -1262,15 +1269,14 @@ dwge_encap(struct dwge_softc *sc, struct mbuf *m, int *idx) bus_dmamap_sync(sc->sc_dmat, DWGE_DMA_MAP(sc->sc_txring), *idx * sizeof(*txd), sizeof(*txd), BUS_DMASYNC_PREWRITE); - dwge_write(sc, GMAC_TX_POLL_DEMAND, 0xffffffff); KASSERT(sc->sc_txbuf[cur].tb_m == NULL); sc->sc_txbuf[*idx].tb_map = sc->sc_txbuf[cur].tb_map; sc->sc_txbuf[cur].tb_map = map; sc->sc_txbuf[cur].tb_m = m; - sc->sc_tx_cnt += map->dm_nsegs; *idx = frag; + *used += map->dm_nsegs; return (0); } -- cgit v1.2.3