reorder ops in sk_start to avoid possibly rolling back ifq_deq.
authordlg <dlg@openbsd.org>
Thu, 1 Jun 2017 23:17:01 +0000 (23:17 +0000)
committerdlg <dlg@openbsd.org>
Thu, 1 Jun 2017 23:17:01 +0000 (23:17 +0000)
instead of checking for space after beggining to deq a packet, check
for space before committing to handling a packet. this means we
can use ifq_dequeue instead of ifq_deq_begin/commit/rollback.

ok mikeb@

sys/dev/pci/if_sk.c

index 180bfaa..0172cd9 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_sk.c,v 1.186 2017/01/22 10:17:38 dlg Exp $ */
+/*     $OpenBSD: if_sk.c,v 1.187 2017/06/01 23:17:01 dlg Exp $ */
 
 /*
  * Copyright (c) 1997, 1998, 1999, 2000
@@ -1405,30 +1405,20 @@ sk_encap(struct sk_if_softc *sc_if, struct mbuf *m_head, u_int32_t *txidx)
 
        cur = frag = *txidx;
 
-#ifdef SK_DEBUG
-       if (skdebug >= 2)
-               sk_dump_mbuf(m_head);
-#endif
-
-       /*
-        * Start packing the mbufs in this chain into
-        * the fragment pointers. Stop when we run out
-        * of fragments or hit the end of the mbuf chain.
-        */
-       if (bus_dmamap_load_mbuf(sc->sc_dmatag, txmap, m_head,
-           BUS_DMA_NOWAIT)) {
-               DPRINTFN(2, ("sk_encap: dmamap failed\n"));
-               return (ENOBUFS);
-       }
+       switch (bus_dmamap_load_mbuf(sc->sc_dmatag, txmap, m_head,
+           BUS_DMA_STREAMING | BUS_DMA_NOWAIT)) {
+       case 0:
+               break;
 
-       if (txmap->dm_nsegs > (SK_TX_RING_CNT - sc_if->sk_cdata.sk_tx_cnt - 2)) {
-               DPRINTFN(2, ("sk_encap: too few descriptors free\n"));
-               bus_dmamap_unload(sc->sc_dmatag, txmap);
-               return (ENOBUFS);
+       case EFBIG: /* mbuf chain is too fragmented */
+               if (m_defrag(m_head, M_DONTWAIT) == 0 &&
+                   bus_dmamap_load_mbuf(sc->sc_dmatag, txmap, m_head,
+                   BUS_DMA_STREAMING | BUS_DMA_NOWAIT) == 0)
+                       break;
+       default:
+               return (1);
        }
 
-       DPRINTFN(2, ("sk_encap: dm_nsegs=%d\n", txmap->dm_nsegs));
-
        /* Sync the DMA map. */
        bus_dmamap_sync(sc->sc_dmatag, txmap, 0, txmap->dm_mapsize,
            BUS_DMASYNC_PREWRITE);
@@ -1490,12 +1480,18 @@ sk_start(struct ifnet *ifp)
        struct sk_softc         *sc = sc_if->sk_softc;
        struct mbuf             *m_head = NULL;
        u_int32_t               idx = sc_if->sk_cdata.sk_tx_prod;
-       int                     pkts = 0;
+       int                     post = 0;
 
        DPRINTFN(2, ("sk_start\n"));
 
-       while (sc_if->sk_cdata.sk_tx_chain[idx].sk_mbuf == NULL) {
-               m_head = ifq_deq_begin(&ifp->if_snd);
+       for (;;) {
+               if (sc_if->sk_cdata.sk_tx_cnt + SK_NTXSEG + 1 >
+                   SK_TX_RING_CNT) {
+                       ifq_set_oactive(&ifp->if_snd);
+                       break;
+               }
+               
+               m_head = ifq_dequeue(&ifp->if_snd);
                if (m_head == NULL)
                        break;
 
@@ -1505,14 +1501,11 @@ sk_start(struct ifnet *ifp)
                 * for the NIC to drain the ring.
                 */
                if (sk_encap(sc_if, m_head, &idx)) {
-                       ifq_deq_rollback(&ifp->if_snd, m_head);
-                       ifq_set_oactive(&ifp->if_snd);
-                       break;
+                       m_freem(m_head);
+                       continue;
                }
 
                /* now we are committed to transmit the packet */
-               ifq_deq_commit(&ifp->if_snd, m_head);
-               pkts++;
 
                /*
                 * If there's a BPF listener, bounce a copy of this frame
@@ -1522,18 +1515,18 @@ sk_start(struct ifnet *ifp)
                if (ifp->if_bpf)
                        bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
 #endif
+
+               post = 1;
        }
-       if (pkts == 0)
+       if (post == 0)
                return;
 
        /* Transmit */
-       if (idx != sc_if->sk_cdata.sk_tx_prod) {
-               sc_if->sk_cdata.sk_tx_prod = idx;
-               CSR_WRITE_4(sc, sc_if->sk_tx_bmu, SK_TXBMU_TX_START);
+       sc_if->sk_cdata.sk_tx_prod = idx;
+       CSR_WRITE_4(sc, sc_if->sk_tx_bmu, SK_TXBMU_TX_START);
 
-               /* Set a timeout in case the chip goes out to lunch. */
-               ifp->if_timer = SK_TX_TIMEOUT;
-       }
+       /* Set a timeout in case the chip goes out to lunch. */
+       ifp->if_timer = SK_TX_TIMEOUT;
 }