Apply mpsafe changes from dwge(4) to dwxe(4):
authorjmatthew <jmatthew@openbsd.org>
Sat, 8 Jan 2022 00:20:10 +0000 (00:20 +0000)
committerjmatthew <jmatthew@openbsd.org>
Sat, 8 Jan 2022 00:20:10 +0000 (00:20 +0000)
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

index b1f881f..1801610 100644 (file)
@@ -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 <patrick@blueri.se>
@@ -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);
 }