diff options
Diffstat (limited to 'sys/dev/vr')
-rw-r--r-- | sys/dev/vr/if_vr.c | 280 | ||||
-rw-r--r-- | sys/dev/vr/if_vrreg.h | 8 |
2 files changed, 161 insertions, 127 deletions
diff --git a/sys/dev/vr/if_vr.c b/sys/dev/vr/if_vr.c index a91a5a7..33a583a 100644 --- a/sys/dev/vr/if_vr.c +++ b/sys/dev/vr/if_vr.c @@ -137,7 +137,6 @@ static int vr_encap (struct vr_softc *, struct vr_chain *, static void vr_rxeof (struct vr_softc *); static void vr_rxeoc (struct vr_softc *); static void vr_txeof (struct vr_softc *); -static void vr_txeoc (struct vr_softc *); static void vr_tick (void *); static void vr_intr (void *); static void vr_start (struct ifnet *); @@ -952,8 +951,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); } @@ -1048,7 +1046,7 @@ static void vr_rxeof(sc) struct vr_softc *sc; { - struct mbuf *m; + struct mbuf *m, *m0; struct ifnet *ifp; struct vr_chain_onefrag *cur_rx; int total_len = 0; @@ -1060,8 +1058,14 @@ vr_rxeof(sc) while(!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) & VR_RXSTAT_OWN)) { - struct mbuf *m0 = NULL; - +#ifdef DEVICE_POLLING + if (ifp->if_flags & IFF_POLLING) { + if (sc->rxcycles <= 0) + break; + sc->rxcycles--; + } +#endif /* DEVICE_POLLING */ + m0 = NULL; cur_rx = sc->vr_cdata.vr_rx_head; sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc; m = cur_rx->vr_mbuf; @@ -1173,22 +1177,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 = cur_tx->vr_ptr->vr_status; if ((txstat & VR_TXSTAT_ABRT) || @@ -1221,41 +1218,15 @@ vr_txeof(sc) ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3; ifp->if_opackets++; - 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; - } + m_freem(cur_tx->vr_mbuf); + cur_tx->vr_mbuf = NULL; + ifp->if_flags &= ~IFF_OACTIVE; - sc->vr_cdata.vr_tx_head = cur_tx->vr_nextdesc; + cur_tx = cur_tx->vr_nextdesc; } - - return; -} - -/* - * TX 'end of channel' interrupt handler. - */ -static void -vr_txeoc(sc) - struct vr_softc *sc; -{ - struct ifnet *ifp; - - ifp = &sc->arpcom.ac_if; - - if (sc->vr_cdata.vr_tx_head == NULL) { - ifp->if_flags &= ~IFF_OACTIVE; - sc->vr_cdata.vr_tx_tail = NULL; + sc->vr_cdata.vr_tx_cons = cur_tx; + if (cur_tx->vr_mbuf == NULL) ifp->if_timer = 0; - } - - return; } static void @@ -1285,6 +1256,78 @@ vr_tick(xsc) return; } +#ifdef DEVICE_POLLING +static poll_handler_t vr_poll; + +static void +vr_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) +{ + struct vr_softc *sc = ifp->if_softc; + + VR_LOCK(sc); + if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */ + CSR_WRITE_2(sc, VR_IMR, VR_INTRS); + goto done; + } + + sc->rxcycles = count; + vr_rxeof(sc); + vr_txeof(sc); + if (ifp->if_snd.ifq_head != NULL) + vr_start(ifp); + + if (cmd == POLL_AND_CHECK_STATUS) { /* also check status register */ + u_int16_t status; + + status = CSR_READ_2(sc, VR_ISR); + if (status) + CSR_WRITE_2(sc, VR_ISR, status); + + if ((status & VR_INTRS) == 0) + goto done; + + if (status & VR_ISR_RX_DROPPED) { + printf("vr%d: rx packet lost\n", sc->vr_unit); + ifp->if_ierrors++; + } + + if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || + (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) { + printf("vr%d: receive error (%04x)", + sc->vr_unit, status); + if (status & VR_ISR_RX_NOBUF) + printf(" no buffers"); + if (status & VR_ISR_RX_OFLOW) + printf(" overflow"); + if (status & VR_ISR_RX_DROPPED) + printf(" packet lost"); + printf("\n"); + vr_rxeoc(sc); + } + + if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) { + vr_reset(sc); + vr_init(sc); + goto done; + } + + if ((status & VR_ISR_UDFI) || + (status & VR_ISR_TX_ABRT2) || + (status & VR_ISR_TX_ABRT)) { + ifp->if_oerrors++; + 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); + } + } + } + +done: + VR_UNLOCK(sc); + +} +#endif /* DEVICE_POLLING */ + static void vr_intr(arg) void *arg; @@ -1297,6 +1340,16 @@ vr_intr(arg) VR_LOCK(sc); ifp = &sc->arpcom.ac_if; +#ifdef DEVICE_POLLING + if (ifp->if_flags & IFF_POLLING) + goto done; + if (ether_poll_register(vr_poll, ifp)) { /* ok, disable interrupts */ + CSR_WRITE_2(sc, VR_IMR, 0x0000); + vr_poll(ifp, 0, 1); + goto done; + } +#endif /* DEVICE_POLLING */ + /* Supress unwanted interrupts. */ if (!(ifp->if_flags & IFF_UP)) { vr_stop(sc); @@ -1351,12 +1404,11 @@ 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); + } } } @@ -1368,6 +1420,9 @@ vr_intr(arg) vr_start(ifp); } +#ifdef DEVICE_POLLING +done: +#endif /* DEVICE_POLLING */ VR_UNLOCK(sc); return; @@ -1383,49 +1438,38 @@ vr_encap(sc, c, m_head) struct vr_chain *c; struct mbuf *m_head; { - int frag = 0; struct vr_desc *f = NULL; - int total_len; struct mbuf *m; - m = m_head; - total_len = 0; - /* * The VIA Rhine wants packet buffers to be longword * aligned, but very often our mbufs aren't. Rather than * waste time trying to decide when to copy and when not * to copy, just do it all the time. */ - if (m != NULL) { - struct mbuf *m_new = NULL; - - m_new = m_defrag(m_head, M_DONTWAIT); - if (m_new == NULL) { - return(1); - } + m = m_defrag(m_head, M_DONTWAIT); + if (m == NULL) { + return(1); + } - m_head = m_new; - /* - * The Rhine chip doesn't auto-pad, so we have to make - * sure to pad short frames out to the minimum frame length - * ourselves. - */ - if (m_head->m_len < VR_MIN_FRAMELEN) { - m_new->m_pkthdr.len += VR_MIN_FRAMELEN - m_new->m_len; - m_new->m_len = m_new->m_pkthdr.len; - } - f = c->vr_ptr; - f->vr_data = vtophys(mtod(m_new, caddr_t)); - f->vr_ctl = total_len = m_new->m_len; - f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG; - f->vr_status = 0; - frag = 1; + /* + * The Rhine chip doesn't auto-pad, so we have to make + * sure to pad short frames out to the minimum frame length + * ourselves. + */ + if (m->m_len < VR_MIN_FRAMELEN) { + m->m_pkthdr.len += VR_MIN_FRAMELEN - m->m_len; + m->m_len = m->m_pkthdr.len; } - c->vr_mbuf = m_head; - c->vr_ptr->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT; - c->vr_ptr->vr_next = vtophys(c->vr_nextdesc->vr_ptr); + c->vr_mbuf = m; + f = c->vr_ptr; + f->vr_data = vtophys(mtod(m, caddr_t)); + f->vr_ctl = m->m_len; + f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG; + f->vr_status = 0; + f->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT; + f->vr_next = vtophys(c->vr_nextdesc->vr_ptr); return(0); } @@ -1442,45 +1486,30 @@ 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; + + if (ifp->if_flags & IFF_OACTIVE) + return; sc = ifp->if_softc; VR_LOCK(sc); - /* - * Check for an available queue slot. If there are none, - * punt. - */ - if (sc->vr_cdata.vr_tx_free->vr_mbuf != NULL) { - VR_UNLOCK(sc); - 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) { IF_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. */ 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) = VR_TXSTAT_OWN; + VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; /* * If there's a BPF listener, bounce a copy of this frame @@ -1488,29 +1517,21 @@ vr_start(ifp) */ BPF_MTAP(ifp, cur_tx->vr_mbuf); - VR_TXOWN(cur_tx) = 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) { - VR_UNLOCK(sc); - return; - } + /* Tell the chip to start transmitting. */ + VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/VR_CMD_TX_GO); - sc->vr_cdata.vr_tx_tail = cur_tx; + /* Set a timeout in case the chip goes out to lunch. */ + ifp->if_timer = 5; - 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); + if (cur_tx->vr_mbuf != NULL) + ifp->if_flags |= IFF_OACTIVE; + } - /* - * Set a timeout in case the chip goes out to lunch. - */ - ifp->if_timer = 5; VR_UNLOCK(sc); return; @@ -1604,10 +1625,18 @@ vr_init(xsc) CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0])); + CSR_WRITE_2(sc, VR_ISR, 0xFFFF); +#ifdef DEVICE_POLLING + /* + * Disable interrupts if we are polling. + */ + if (ifp->if_flags & IFF_POLLING) + CSR_WRITE_2(sc, VR_IMR, 0); + else +#endif /* DEVICE_POLLING */ /* * Enable interrupts. */ - CSR_WRITE_2(sc, VR_ISR, 0xFFFF); CSR_WRITE_2(sc, VR_IMR, VR_INTRS); mii_mediachg(mii); @@ -1743,6 +1772,10 @@ vr_stop(sc) ifp->if_timer = 0; untimeout(vr_tick, sc, sc->vr_stat_ch); + ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); +#ifdef DEVICE_POLLING + ether_poll_deregister(ifp); +#endif /* DEVICE_POLLING */ VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP); VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON)); @@ -1775,7 +1808,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); VR_UNLOCK(sc); return; diff --git a/sys/dev/vr/if_vrreg.h b/sys/dev/vr/if_vrreg.h index 2f8e810..5cf3bb2 100644 --- a/sys/dev/vr/if_vrreg.h +++ b/sys/dev/vr/if_vrreg.h @@ -420,9 +420,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 { @@ -469,6 +468,9 @@ struct vr_softc { struct vr_chain_data vr_cdata; struct callout_handle vr_stat_ch; struct mtx vr_mtx; +#ifdef DEVICE_POLLING + int rxcycles; +#endif }; #define VR_F_RESTART 0x01 /* Restart unit on next tick */ |