According to the FreeBSD driver, txp(4) is not setting up its TX
ring correctly.  FreeBSD driver uses up to 16 fragments, while we
use up to 252 which is suspicious.

This gets us in line with FreeBSD, introduces goodness of m_defrag
and removes pesky if_deq_* thingies.

Does anyone still have the hardware (3com 3CR900 Typhoon) to test?
OK's are welcome.

diff --git sys/dev/pci/if_txp.c sys/dev/pci/if_txp.c
index deede70e9de..1aed06765c0 100644
--- sys/dev/pci/if_txp.c
+++ sys/dev/pci/if_txp.c
@@ -883,12 +883,12 @@ txp_alloc_rings(struct txp_softc *sc)
        sc->sc_txhir.r_desc = (struct txp_tx_desc 
*)sc->sc_txhiring_dma.dma_vaddr;
        sc->sc_txhir.r_cons = sc->sc_txhir.r_prod = sc->sc_txhir.r_cnt = 0;
        sc->sc_txhir.r_off = &sc->sc_hostvar->hv_tx_hi_desc_read_idx;
        for (i = 0; i < TX_ENTRIES; i++) {
                if (bus_dmamap_create(sc->sc_dmat, TXP_MAX_PKTLEN,
-                   TX_ENTRIES - 4, TXP_MAX_SEGLEN, 0,
-                   BUS_DMA_NOWAIT, &sc->sc_txd[i].sd_map) != 0) {
+                   TXP_MAXTXSEGS, MCLBYTES, 0, BUS_DMA_NOWAIT,
+                   &sc->sc_txd[i].sd_map) != 0) {
                        for (j = 0; j < i; j++) {
                                bus_dmamap_destroy(sc->sc_dmat,
                                    sc->sc_txd[j].sd_map);
                                sc->sc_txd[j].sd_map = NULL;
                        }
@@ -1261,57 +1261,48 @@ txp_start(struct ifnet *ifp)
        struct txp_softc *sc = ifp->if_softc;
        struct txp_tx_ring *r = &sc->sc_txhir;
        struct txp_tx_desc *txd;
        int txdidx;
        struct txp_frag_desc *fxd;
-       struct mbuf *m, *mnew;
+       struct mbuf *m;
        struct txp_swdesc *sd;
        u_int32_t firstprod, firstcnt, prod, cnt, i;
 
        if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
                return;
 
        prod = r->r_prod;
        cnt = r->r_cnt;
 
        while (1) {
-               m = ifq_deq_begin(&ifp->if_snd);
+               if (cnt >= TX_ENTRIES - TXP_MAXTXSEGS - 4)
+                       goto oactive;
+
+               m = ifq_dequeue(&ifp->if_snd);
                if (m == NULL)
                        break;
-               mnew = NULL;
 
                firstprod = prod;
                firstcnt = cnt;
 
                sd = sc->sc_txd + prod;
                sd->sd_mbuf = m;
 
-               if (bus_dmamap_load_mbuf(sc->sc_dmat, sd->sd_map, m,
+               switch (bus_dmamap_load_mbuf(sc->sc_dmat, sd->sd_map, m,
                    BUS_DMA_NOWAIT)) {
-                       MGETHDR(mnew, M_DONTWAIT, MT_DATA);
-                       if (mnew == NULL)
-                               goto oactive1;
-                       if (m->m_pkthdr.len > MHLEN) {
-                               MCLGET(mnew, M_DONTWAIT);
-                               if ((mnew->m_flags & M_EXT) == 0) {
-                                       m_freem(mnew);
-                                       goto oactive1;
-                               }
-                       }
-                       m_copydata(m, 0, m->m_pkthdr.len, mtod(mnew, caddr_t));
-                       mnew->m_pkthdr.len = mnew->m_len = m->m_pkthdr.len;
-                       ifq_deq_commit(&ifp->if_snd, m);
+               case 0:
+                       break;
+               case EFBIG:
+                       if (m_defrag(m, M_DONTWAIT) == 0 &&
+                           bus_dmamap_load_mbuf(sc->sc_dmat, sd->sd_map, m,
+                           BUS_DMA_NOWAIT) == 0)
+                               break;
+               default:
                        m_freem(m);
-                       m = mnew;
-                       if (bus_dmamap_load_mbuf(sc->sc_dmat, sd->sd_map, m,
-                           BUS_DMA_NOWAIT))
-                               goto oactive1;
+                       continue;
                }
 
-               if ((TX_ENTRIES - cnt) < 4)
-                       goto oactive;
-
                txd = r->r_desc + prod;
                txdidx = prod;
                txd->tx_flags = TX_FLAGS_TYPE_DATA;
                txd->tx_numdesc = 0;
                txd->tx_addrlo = 0;
@@ -1321,13 +1312,10 @@ txp_start(struct ifnet *ifp)
                txd->tx_numdesc = sd->sd_map->dm_nsegs;
 
                if (++prod == TX_ENTRIES)
                        prod = 0;
 
-               if (++cnt >= (TX_ENTRIES - 4))
-                       goto oactive;
-
 #if NVLAN > 0
                if (m->m_flags & M_VLANTAG) {
                        txd->tx_pflags = TX_PFLAGS_VLAN |
                            (htons(m->m_pkthdr.ether_vtag) << 
TX_PFLAGS_VLANTAG_S);
                }
@@ -1351,10 +1339,12 @@ txp_start(struct ifnet *ifp)
                for (i = 0; i < sd->sd_map->dm_nsegs; i++) {
                        if (++cnt >= (TX_ENTRIES - 4)) {
                                bus_dmamap_sync(sc->sc_dmat, sd->sd_map,
                                    0, sd->sd_map->dm_mapsize,
                                    BUS_DMASYNC_POSTWRITE);
+                               bus_dmamap_unload(sc->sc_dmat, sd->sd_map);
+                               m_freem(m);
                                goto oactive;
                        }
 
                        fxd->frag_flags = FRAG_FLAGS_TYPE_FRAG |
                            FRAG_FLAGS_VALID;
@@ -1379,17 +1369,10 @@ txp_start(struct ifnet *ifp)
                        } else
                                fxd++;
 
                }
 
-               /*
-                * if mnew isn't NULL, we already dequeued and copied
-                * the packet.
-                */
-               if (mnew == NULL)
-                       ifq_deq_commit(&ifp->if_snd, m);
-
                ifp->if_timer = 5;
 
 #if NBPFILTER > 0
                if (ifp->if_bpf)
                        bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT);
@@ -1424,13 +1407,10 @@ txp_start(struct ifnet *ifp)
        r->r_prod = prod;
        r->r_cnt = cnt;
        return;
 
 oactive:
-       bus_dmamap_unload(sc->sc_dmat, sd->sd_map);
-oactive1:
-       ifq_deq_rollback(&ifp->if_snd, m);
        ifq_set_oactive(&ifp->if_snd);
        r->r_prod = firstprod;
        r->r_cnt = firstcnt;
 }
 
diff --git sys/dev/pci/if_txpreg.h sys/dev/pci/if_txpreg.h
index cc4d5f1c60c..b6962872f34 100644
--- sys/dev/pci/if_txpreg.h
+++ sys/dev/pci/if_txpreg.h
@@ -607,10 +607,12 @@ struct txp_fw_section_header {
 };
 
 #define        TXP_MAX_SEGLEN  0xffff
 #define        TXP_MAX_PKTLEN  0x0800
 
+#define        TXP_MAXTXSEGS   16
+
 #define        WRITE_REG(sc,reg,val) \
     bus_space_write_4((sc)->sc_bt, (sc)->sc_bh, reg, val)
 #define        READ_REG(sc,reg) \
     bus_space_read_4((sc)->sc_bt, (sc)->sc_bh, reg)
 

Reply via email to