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 <dejan.lesjak at ijs.si>  alpha/<Intel 21143 10/100BaseTX>
  "Xin LI" <delphij at frontfree.net>    i386/<Macronix 98713 10/100BaseTX>
  Wiktor Niesiobedzki <bsd at w.evip.pl> i386/<3Com OfficeConnect 10/100B>

Reviewed by:	mux
This commit is contained in:
Don Lewis 2004-01-08 06:22:15 +00:00
parent d4b2657f98
commit 4ff4a9bee9
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=124240
4 changed files with 10 additions and 6 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;