From 4ff4a9bee9aa27d76926117bc47c0fd3a88ef668 Mon Sep 17 00:00:00 2001 From: Don Lewis Date: Thu, 8 Jan 2004 06:22:15 +0000 Subject: [PATCH] The transmit frame status is stored in the last transmit descriptor for the frame, not the first. It is probably also not safe to free the mbuf chain as soon as the OWN bit is cleared on the first descriptor since the chip may not be done copying the frame into the transmit FIFO. Revert the part of of busdma conversion (if_dc.c rev 1.115) which changed dc_txeof() to look for the status in the first descriptor and free the mbuf chain when processing the first descriptor for the frame, and revert the matching changes elsewhere in the driver. This part of the busdma change caused the driver to report spurious collisions and output errors, even when running in full-duplex mode. Reverting the mbuf chain handling slightly complicates dc_dma_map_txbuf(), since it is responsible for setting the OWN bits on the descriptors, but does not normally have direct access to the mbuf chain. Tested by: Dejan Lesjak alpha/ "Xin LI" i386/ Wiktor Niesiobedzki i386/<3Com OfficeConnect 10/100B> Reviewed by: mux --- sys/dev/dc/if_dc.c | 7 ++++--- sys/dev/dc/if_dcreg.h | 1 + sys/pci/if_dc.c | 7 ++++--- sys/pci/if_dcreg.h | 1 + 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/sys/dev/dc/if_dc.c b/sys/dev/dc/if_dc.c index 7ff58551eae9..6068194eab7b 100644 --- a/sys/dev/dc/if_dc.c +++ b/sys/dev/dc/if_dc.c @@ -2859,7 +2859,7 @@ dc_txeof(struct dc_softc *sc) if (txstat & DC_TXSTAT_OWN) break; - if (!(ctl & DC_TXCTL_FIRSTFRAG) || ctl & DC_TXCTL_SETUP) { + if (!(ctl & DC_TXCTL_LASTFRAG) || ctl & DC_TXCTL_SETUP) { if (ctl & DC_TXCTL_SETUP) { /* * Yes, the PNIC is so brain damaged @@ -3262,6 +3262,7 @@ dc_dma_map_txbuf(arg, segs, nseg, mapsize, error) sc->dc_cdata.dc_tx_prod = frag; sc->dc_cdata.dc_tx_cnt += nseg; sc->dc_ldata->dc_tx_list[cur].dc_ctl |= htole32(DC_TXCTL_LASTFRAG); + sc->dc_cdata.dc_tx_chain[cur] = sc->dc_cdata.dc_tx_mapping; if (sc->dc_flags & DC_TX_INTR_FIRSTFRAG) sc->dc_ldata->dc_tx_list[first].dc_ctl |= htole32(DC_TXCTL_FINT); @@ -3311,13 +3312,13 @@ dc_encap(struct dc_softc *sc, struct mbuf **m_head) * of fragments or hit the end of the mbuf chain. */ idx = sc->dc_cdata.dc_tx_prod; + sc->dc_cdata.dc_tx_mapping = *m_head; error = bus_dmamap_load_mbuf(sc->dc_mtag, sc->dc_cdata.dc_tx_map[idx], *m_head, dc_dma_map_txbuf, sc, 0); if (error) return (error); if (sc->dc_cdata.dc_tx_err != 0) return (sc->dc_cdata.dc_tx_err); - sc->dc_cdata.dc_tx_chain[idx] = *m_head; bus_dmamap_sync(sc->dc_mtag, sc->dc_cdata.dc_tx_map[idx], BUS_DMASYNC_PREWRITE); bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap, @@ -3768,7 +3769,7 @@ dc_stop(struct dc_softc *sc) if (cd->dc_tx_chain[i] != NULL) { ctl = le32toh(ld->dc_tx_list[i].dc_ctl); if ((ctl & DC_TXCTL_SETUP) || - !(ctl & DC_TXCTL_FIRSTFRAG)) { + !(ctl & DC_TXCTL_LASTFRAG)) { cd->dc_tx_chain[i] = NULL; continue; } diff --git a/sys/dev/dc/if_dcreg.h b/sys/dev/dc/if_dcreg.h index 64dcc28ff791..c7339eb7b533 100644 --- a/sys/dev/dc/if_dcreg.h +++ b/sys/dev/dc/if_dcreg.h @@ -486,6 +486,7 @@ struct dc_list_data { struct dc_chain_data { struct mbuf *dc_rx_chain[DC_RX_LIST_CNT]; struct mbuf *dc_tx_chain[DC_TX_LIST_CNT]; + struct mbuf *dc_tx_mapping; bus_dmamap_t dc_rx_map[DC_RX_LIST_CNT]; bus_dmamap_t dc_tx_map[DC_TX_LIST_CNT]; u_int32_t *dc_sbuf; diff --git a/sys/pci/if_dc.c b/sys/pci/if_dc.c index 7ff58551eae9..6068194eab7b 100644 --- a/sys/pci/if_dc.c +++ b/sys/pci/if_dc.c @@ -2859,7 +2859,7 @@ dc_txeof(struct dc_softc *sc) if (txstat & DC_TXSTAT_OWN) break; - if (!(ctl & DC_TXCTL_FIRSTFRAG) || ctl & DC_TXCTL_SETUP) { + if (!(ctl & DC_TXCTL_LASTFRAG) || ctl & DC_TXCTL_SETUP) { if (ctl & DC_TXCTL_SETUP) { /* * Yes, the PNIC is so brain damaged @@ -3262,6 +3262,7 @@ dc_dma_map_txbuf(arg, segs, nseg, mapsize, error) sc->dc_cdata.dc_tx_prod = frag; sc->dc_cdata.dc_tx_cnt += nseg; sc->dc_ldata->dc_tx_list[cur].dc_ctl |= htole32(DC_TXCTL_LASTFRAG); + sc->dc_cdata.dc_tx_chain[cur] = sc->dc_cdata.dc_tx_mapping; if (sc->dc_flags & DC_TX_INTR_FIRSTFRAG) sc->dc_ldata->dc_tx_list[first].dc_ctl |= htole32(DC_TXCTL_FINT); @@ -3311,13 +3312,13 @@ dc_encap(struct dc_softc *sc, struct mbuf **m_head) * of fragments or hit the end of the mbuf chain. */ idx = sc->dc_cdata.dc_tx_prod; + sc->dc_cdata.dc_tx_mapping = *m_head; error = bus_dmamap_load_mbuf(sc->dc_mtag, sc->dc_cdata.dc_tx_map[idx], *m_head, dc_dma_map_txbuf, sc, 0); if (error) return (error); if (sc->dc_cdata.dc_tx_err != 0) return (sc->dc_cdata.dc_tx_err); - sc->dc_cdata.dc_tx_chain[idx] = *m_head; bus_dmamap_sync(sc->dc_mtag, sc->dc_cdata.dc_tx_map[idx], BUS_DMASYNC_PREWRITE); bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap, @@ -3768,7 +3769,7 @@ dc_stop(struct dc_softc *sc) if (cd->dc_tx_chain[i] != NULL) { ctl = le32toh(ld->dc_tx_list[i].dc_ctl); if ((ctl & DC_TXCTL_SETUP) || - !(ctl & DC_TXCTL_FIRSTFRAG)) { + !(ctl & DC_TXCTL_LASTFRAG)) { cd->dc_tx_chain[i] = NULL; continue; } diff --git a/sys/pci/if_dcreg.h b/sys/pci/if_dcreg.h index 64dcc28ff791..c7339eb7b533 100644 --- a/sys/pci/if_dcreg.h +++ b/sys/pci/if_dcreg.h @@ -486,6 +486,7 @@ struct dc_list_data { struct dc_chain_data { struct mbuf *dc_rx_chain[DC_RX_LIST_CNT]; struct mbuf *dc_tx_chain[DC_TX_LIST_CNT]; + struct mbuf *dc_tx_mapping; bus_dmamap_t dc_rx_map[DC_RX_LIST_CNT]; bus_dmamap_t dc_tx_map[DC_TX_LIST_CNT]; u_int32_t *dc_sbuf;