diff options
author | Brad Smith <brad@cvs.openbsd.org> | 2005-07-06 02:22:29 +0000 |
---|---|---|
committer | Brad Smith <brad@cvs.openbsd.org> | 2005-07-06 02:22:29 +0000 |
commit | fe75099af4d6407556b221ca13a90d7d4e5492fc (patch) | |
tree | fa2259b578eec9e9a5a0bc8e15f53b8f691f3495 /sys/dev | |
parent | df73f4268c743dabdce06df29075a63fb3b83ebe (diff) |
- Rewritten TX to use only two pointers to track producer/consumer.
- Bugfix: don't forget to set IFF_OACTIVE when TX list is full.
From FreeBSD
- clear IFF_RUNNING & IFF_OACTIVE in vr_stop() before de-allocating resources.
Thanks to cloder@, millert@ and pedro@ for testing.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/if_vr.c | 127 | ||||
-rw-r--r-- | sys/dev/pci/if_vrreg.h | 7 |
2 files changed, 38 insertions, 96 deletions
diff --git a/sys/dev/pci/if_vr.c b/sys/dev/pci/if_vr.c index 92db3df3858..914d289f2a8 100644 --- a/sys/dev/pci/if_vr.c +++ b/sys/dev/pci/if_vr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_vr.c,v 1.45 2005/01/15 05:24:11 brad Exp $ */ +/* $OpenBSD: if_vr.c,v 1.46 2005/07/06 02:22:28 brad Exp $ */ /* * Copyright (c) 1997, 1998 @@ -115,7 +115,6 @@ int vr_encap(struct vr_softc *, struct vr_chain *, struct mbuf *); void vr_rxeof(struct vr_softc *); void vr_rxeoc(struct vr_softc *); void vr_txeof(struct vr_softc *); -void vr_txeoc(struct vr_softc *); void vr_tick(void *); int vr_intr(void *); void vr_start(struct ifnet *); @@ -879,8 +878,7 @@ vr_list_tx_init(sc) &cd->vr_tx_chain[i + 1]; } - cd->vr_tx_free = &cd->vr_tx_chain[0]; - cd->vr_tx_tail = cd->vr_tx_head = NULL; + cd->vr_tx_cons = cd->vr_tx_prod = &cd->vr_tx_chain[0]; return (0); } @@ -964,6 +962,7 @@ void vr_rxeof(sc) struct vr_softc *sc; { + struct mbuf *m0; struct ifnet *ifp; struct vr_chain_onefrag *cur_rx; int total_len = 0; @@ -972,7 +971,6 @@ vr_rxeof(sc) ifp = &sc->arpcom.ac_if; for (;;) { - struct mbuf *m0 = NULL; bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap, 0, sc->sc_listmap->dm_mapsize, @@ -981,6 +979,7 @@ vr_rxeof(sc) if (rxstat & VR_RXSTAT_OWN) break; + m0 = NULL; cur_rx = sc->vr_cdata.vr_rx_head; sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc; @@ -1127,22 +1126,15 @@ vr_txeof(sc) ifp = &sc->arpcom.ac_if; - /* Reset the timeout timer; if_txeoc will clear it. */ - ifp->if_timer = 5; - - /* Sanity check. */ - if (sc->vr_cdata.vr_tx_head == NULL) - return; - /* * Go through our tx list and free mbufs for those * frames that have been transmitted. */ - while(sc->vr_cdata.vr_tx_head->vr_mbuf != NULL) { + cur_tx = sc->vr_cdata.vr_tx_cons; + while(cur_tx->vr_mbuf != NULL) { u_int32_t txstat; int i; - cur_tx = sc->vr_cdata.vr_tx_head; txstat = letoh32(cur_tx->vr_ptr->vr_status); if ((txstat & VR_TXSTAT_ABRT) || @@ -1178,41 +1170,17 @@ vr_txeof(sc) ifp->if_opackets++; if (cur_tx->vr_map != NULL && cur_tx->vr_map->dm_segs > 0) bus_dmamap_unload(sc->sc_dmat, cur_tx->vr_map); - if (cur_tx->vr_mbuf != NULL) { - m_freem(cur_tx->vr_mbuf); - cur_tx->vr_mbuf = NULL; - } - - if (sc->vr_cdata.vr_tx_head == sc->vr_cdata.vr_tx_tail) { - sc->vr_cdata.vr_tx_head = NULL; - sc->vr_cdata.vr_tx_tail = NULL; - break; - } - - sc->vr_cdata.vr_tx_head = cur_tx->vr_nextdesc; - } - - return; -} - -/* - * TX 'end of channel' interrupt handler. - */ -void -vr_txeoc(sc) - struct vr_softc *sc; -{ - struct ifnet *ifp; - ifp = &sc->arpcom.ac_if; - - if (sc->vr_cdata.vr_tx_head == NULL) { + m_freem(cur_tx->vr_mbuf); + cur_tx->vr_mbuf = NULL; ifp->if_flags &= ~IFF_OACTIVE; - sc->vr_cdata.vr_tx_tail = NULL; - ifp->if_timer = 0; + + cur_tx = cur_tx->vr_nextdesc; } - return; + sc->vr_cdata.vr_tx_cons = cur_tx; + if (cur_tx->vr_mbuf == NULL) + ifp->if_timer = 0; } void @@ -1303,14 +1271,13 @@ vr_intr(arg) (status & VR_ISR_TX_ABRT2) || (status & VR_ISR_TX_ABRT)) { ifp->if_oerrors++; - if (sc->vr_cdata.vr_tx_head != NULL) { + if (sc->vr_cdata.vr_tx_cons->vr_mbuf != NULL) { VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON); VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO); } - } else - vr_txeoc(sc); + } } } @@ -1401,31 +1368,17 @@ vr_start(ifp) struct ifnet *ifp; { struct vr_softc *sc; - struct mbuf *m_head = NULL; - struct vr_chain *cur_tx = NULL, *start_tx, *prev_tx; + struct mbuf *m_head; + struct vr_chain *cur_tx; sc = ifp->if_softc; - /* - * Check for an available queue slot. If there are none, - * punt. - */ - if (sc->vr_cdata.vr_tx_free->vr_mbuf != NULL) { - return; - } - - start_tx = sc->vr_cdata.vr_tx_free; - - while(sc->vr_cdata.vr_tx_free->vr_mbuf == NULL) { + cur_tx = sc->vr_cdata.vr_tx_prod; + while (cur_tx->vr_mbuf == NULL) { IFQ_DEQUEUE(&ifp->if_snd, m_head); if (m_head == NULL) break; - /* Pick a descriptor off the free list. */ - prev_tx = cur_tx; - cur_tx = sc->vr_cdata.vr_tx_free; - sc->vr_cdata.vr_tx_free = cur_tx->vr_nextdesc; - /* Pack the data into the descriptor. */ if (vr_encap(sc, cur_tx, m_head)) { /* Rollback, send what we were able to encap. */ @@ -1434,13 +1387,10 @@ vr_start(ifp) } else { IF_PREPEND(&ifp->if_snd, m_head); } - sc->vr_cdata.vr_tx_free = cur_tx; - cur_tx = prev_tx; break; } - if (cur_tx != start_tx) - VR_TXOWN(cur_tx) = htole32(VR_TXSTAT_OWN); + VR_TXOWN(cur_tx) = htole32(VR_TXSTAT_OWN); #if NBPFILTER > 0 /* @@ -1450,31 +1400,24 @@ vr_start(ifp) if (ifp->if_bpf) bpf_mtap(ifp->if_bpf, cur_tx->vr_mbuf); #endif - VR_TXOWN(cur_tx) = htole32(VR_TXSTAT_OWN); + cur_tx = cur_tx->vr_nextdesc; } + if (cur_tx != sc->vr_cdata.vr_tx_prod || cur_tx->vr_mbuf != NULL) { + sc->vr_cdata.vr_tx_prod = cur_tx; - /* - * If there are no frames queued, bail. - */ - if (cur_tx == NULL) - return; - - sc->vr_cdata.vr_tx_tail = cur_tx; + bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap, 0, + sc->sc_listmap->dm_mapsize, + BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD); - if (sc->vr_cdata.vr_tx_head == NULL) - sc->vr_cdata.vr_tx_head = start_tx; + /* Tell the chip to start transmitting. */ + VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/VR_CMD_TX_GO); - bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap, 0, - sc->sc_listmap->dm_mapsize, - BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD); - - /* Tell the chip to start transmitting. */ - VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/VR_CMD_TX_GO); + /* Set a timeout in case the chip goes out to lunch. */ + ifp->if_timer = 5; - /* - * Set a timeout in case the chip goes out to lunch. - */ - ifp->if_timer = 5; + if (cur_tx->vr_mbuf != NULL) + ifp->if_flags |= IFF_OACTIVE; + } } void @@ -1730,6 +1673,8 @@ vr_stop(sc) if (timeout_pending(&sc->sc_to)) timeout_del(&sc->sc_to); + ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); + VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP); VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON)); CSR_WRITE_2(sc, VR_IMR, 0x0000); @@ -1779,8 +1724,6 @@ vr_stop(sc) bzero((char *)&sc->vr_ldata->vr_tx_list, sizeof(sc->vr_ldata->vr_tx_list)); - ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); - return; } diff --git a/sys/dev/pci/if_vrreg.h b/sys/dev/pci/if_vrreg.h index 62a545e1124..6c2c55a5282 100644 --- a/sys/dev/pci/if_vrreg.h +++ b/sys/dev/pci/if_vrreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_vrreg.h,v 1.14 2005/05/27 00:18:59 pvalchev Exp $ */ +/* $OpenBSD: if_vrreg.h,v 1.15 2005/07/06 02:22:28 brad Exp $ */ /* * Copyright (c) 1997, 1998 @@ -424,9 +424,8 @@ struct vr_chain_data { struct vr_chain_onefrag *vr_rx_head; - struct vr_chain *vr_tx_head; - struct vr_chain *vr_tx_tail; - struct vr_chain *vr_tx_free; + struct vr_chain *vr_tx_cons; + struct vr_chain *vr_tx_prod; }; struct vr_type { |