From 9a56c644f5c8b97623872088f796307ab25ec6e0 Mon Sep 17 00:00:00 2001 From: jmatthew Date: Sat, 8 Jan 2022 00:20:10 +0000 Subject: [PATCH] Apply mpsafe changes from dwge(4) to dwxe(4): 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 DWXE_NTXSEGS slots are left, making dwxe_start() and dwxe_txeof() work independently. While here, only write to DWXE_TX_CTL1 once per call to dwxe_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 dwxe(4) mpsafe. tested on arm64 (a64 sopine) by mlarkin@ and armv7 (h2+) by me ok dlg@ --- sys/dev/fdt/if_dwxe.c | 81 +++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/sys/dev/fdt/if_dwxe.c b/sys/dev/fdt/if_dwxe.c index b1f881f0d02..1801610e1d6 100644 --- a/sys/dev/fdt/if_dwxe.c +++ b/sys/dev/fdt/if_dwxe.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_dwxe.c,v 1.19 2021/10/24 17:52:26 mpi Exp $ */ +/* $OpenBSD: if_dwxe.c,v 1.20 2022/01/08 00:20:10 jmatthew Exp $ */ /* * Copyright (c) 2008 Mark Kettenis * Copyright (c) 2017 Patrick Wildt @@ -275,6 +275,7 @@ struct dwxe_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 @@ -287,7 +288,6 @@ struct dwxe_softc { struct dwxe_buf *sc_txbuf; struct dwxe_desc *sc_txdesc; int sc_tx_prod; - int sc_tx_cnt; int sc_tx_cons; struct dwxe_dmamem *sc_rxring; @@ -322,7 +322,7 @@ uint32_t dwxe_read(struct dwxe_softc *, bus_addr_t); void dwxe_write(struct dwxe_softc *, bus_addr_t, uint32_t); int dwxe_ioctl(struct ifnet *, u_long, caddr_t); -void dwxe_start(struct ifnet *); +void dwxe_start(struct ifqueue *); void dwxe_watchdog(struct ifnet *); int dwxe_media_change(struct ifnet *); @@ -345,7 +345,7 @@ void dwxe_rx_proc(struct dwxe_softc *); void dwxe_up(struct dwxe_softc *); void dwxe_down(struct dwxe_softc *); void dwxe_iff(struct dwxe_softc *); -int dwxe_encap(struct dwxe_softc *, struct mbuf *, int *); +int dwxe_encap(struct dwxe_softc *, struct mbuf *, int *, int *); void dwxe_reset(struct dwxe_softc *); void dwxe_stop_dma(struct dwxe_softc *); @@ -431,8 +431,9 @@ dwxe_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 = dwxe_ioctl; - ifp->if_start = dwxe_start; + ifp->if_qstart = dwxe_start; ifp->if_watchdog = dwxe_watchdog; ifq_set_maxlen(&ifp->if_snd, DWXE_NTXDESC - 1); bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); @@ -460,8 +461,10 @@ dwxe_attach(struct device *parent, struct device *self, void *aux) if_attach(ifp); ether_ifattach(ifp); - fdt_intr_establish(faa->fa_node, IPL_NET, dwxe_intr, sc, - sc->sc_dev.dv_xname); + sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_NET | IPL_MPSAFE, + dwxe_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 @@ -584,11 +587,12 @@ dwxe_lladdr_write(struct dwxe_softc *sc) } void -dwxe_start(struct ifnet *ifp) +dwxe_start(struct ifqueue *ifq) { + struct ifnet *ifp = ifq->ifq_if; struct dwxe_softc *sc = ifp->if_softc; struct mbuf *m; - int error, idx; + int error, idx, left, used; if (!(ifp->if_flags & IFF_RUNNING)) return; @@ -600,27 +604,29 @@ dwxe_start(struct ifnet *ifp) return; idx = sc->sc_tx_prod; - while ((sc->sc_txdesc[idx].sd_status & DWXE_TX_DESC_CTL) == 0) { - m = ifq_deq_begin(&ifp->if_snd); - if (m == NULL) + left = sc->sc_tx_cons; + if (left <= idx) + left += DWXE_NTXDESC; + left -= idx; + used = 0; + + for (;;) { + if (used + DWXE_NTXSEGS + 1 > left) { + ifq_set_oactive(ifq); break; + } - error = dwxe_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 = dwxe_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); @@ -632,6 +638,9 @@ dwxe_start(struct ifnet *ifp) /* Set a timeout in case the chip goes out to lunch. */ ifp->if_timer = 5; + + dwxe_write(sc, DWXE_TX_CTL1, dwxe_read(sc, + DWXE_TX_CTL1) | DWXE_TX_CTL1_TX_DMA_START); } } @@ -877,7 +886,7 @@ dwxe_tx_proc(struct dwxe_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 < DWXE_NTXDESC); @@ -896,7 +905,6 @@ dwxe_tx_proc(struct dwxe_softc *sc) } txfree++; - sc->sc_tx_cnt--; if (sc->sc_tx_cons == (DWXE_NTXDESC - 1)) sc->sc_tx_cons = 0; @@ -906,7 +914,7 @@ dwxe_tx_proc(struct dwxe_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) { @@ -923,7 +931,7 @@ dwxe_rx_proc(struct dwxe_softc *sc) struct dwxe_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; @@ -932,7 +940,9 @@ dwxe_rx_proc(struct dwxe_softc *sc) DWXE_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 < DWXE_NRXDESC); @@ -959,13 +969,14 @@ dwxe_rx_proc(struct dwxe_softc *sc) ml_enqueue(&ml, m); - if_rxr_put(&sc->sc_rx_ring, 1); + put++; if (sc->sc_rx_cons == (DWXE_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); @@ -1005,7 +1016,6 @@ dwxe_up(struct dwxe_softc *sc) 0, DWXE_DMA_LEN(sc->sc_txring), BUS_DMASYNC_PREWRITE); sc->sc_tx_prod = sc->sc_tx_cons = 0; - sc->sc_tx_cnt = 0; dwxe_write(sc, DWXE_TX_DESC_LIST, DWXE_DMA_DVA(sc->sc_txring)); @@ -1103,6 +1113,9 @@ dwxe_down(struct dwxe_softc *sc) dwxe_write(sc, DWXE_INT_EN, 0); + intr_barrier(sc->sc_ih); + ifq_barrier(&ifp->if_snd); + for (i = 0; i < DWXE_NTXDESC; i++) { txb = &sc->sc_txbuf[i]; if (txb->tb_m) { @@ -1188,7 +1201,7 @@ dwxe_iff(struct dwxe_softc *sc) } int -dwxe_encap(struct dwxe_softc *sc, struct mbuf *m, int *idx) +dwxe_encap(struct dwxe_softc *sc, struct mbuf *m, int *idx, int *used) { struct dwxe_desc *txd, *txd_start; bus_dmamap_t map; @@ -1204,11 +1217,6 @@ dwxe_encap(struct dwxe_softc *sc, struct mbuf *m, int *idx) return (EFBIG); } - if (map->dm_nsegs > (DWXE_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); @@ -1242,16 +1250,13 @@ dwxe_encap(struct dwxe_softc *sc, struct mbuf *m, int *idx) bus_dmamap_sync(sc->sc_dmat, DWXE_DMA_MAP(sc->sc_txring), *idx * sizeof(*txd), sizeof(*txd), BUS_DMASYNC_PREWRITE); - dwxe_write(sc, DWXE_TX_CTL1, dwxe_read(sc, - DWXE_TX_CTL1) | DWXE_TX_CTL1_TX_DMA_START); - 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); } -- 2.20.1