diff options
Diffstat (limited to 'sys/dev/pci/if_sis.c')
-rw-r--r-- | sys/dev/pci/if_sis.c | 139 |
1 files changed, 77 insertions, 62 deletions
diff --git a/sys/dev/pci/if_sis.c b/sys/dev/pci/if_sis.c index b4e54cbcdbf..a477017cdb6 100644 --- a/sys/dev/pci/if_sis.c +++ b/sys/dev/pci/if_sis.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_sis.c,v 1.87 2009/02/24 21:10:14 claudio Exp $ */ +/* $OpenBSD: if_sis.c,v 1.88 2009/04/14 19:06:49 claudio Exp $ */ /* * Copyright (c) 1997, 1998, 1999 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. @@ -115,10 +115,13 @@ struct cfdriver sis_cd = { int sis_intr(void *); void sis_shutdown(void *); -int sis_newbuf(struct sis_softc *, struct sis_desc *, struct mbuf *); +void sis_fill_rx_ring(struct sis_softc *); +int sis_newbuf(struct sis_softc *, struct sis_desc *); int sis_encap(struct sis_softc *, struct mbuf *, u_int32_t *); void sis_rxeof(struct sis_softc *); +#if 0 void sis_rxeoc(struct sis_softc *); +#endif void sis_txeof(struct sis_softc *); void sis_tick(void *); void sis_start(struct ifnet *); @@ -1098,18 +1101,13 @@ sis_attach(struct device *parent, struct device *self, void *aux) sc->sis_ldata = (struct sis_list_data *)sc->sc_listkva; bzero(sc->sis_ldata, sizeof(struct sis_list_data)); - for (i = 0; i < SIS_RX_LIST_CNT_MAX; i++) { + for (i = 0; i < SIS_RX_LIST_CNT; i++) { if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 0, BUS_DMA_NOWAIT, &sc->sis_ldata->sis_rx_list[i].map) != 0) { printf(": can't create rx map\n"); goto fail_2; } } - if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 0, - BUS_DMA_NOWAIT, &sc->sc_rx_sparemap) != 0) { - printf(": can't create rx spare map\n"); - goto fail_2; - } for (i = 0; i < SIS_TX_LIST_CNT; i++) { if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, @@ -1140,6 +1138,8 @@ sis_attach(struct device *parent, struct device *self, void *aux) ifp->if_capabilities = IFCAP_VLAN_MTU; + m_clsetwms(ifp, MCLBYTES, 2, SIS_RX_LIST_CNT - 1); + sc->sc_mii.mii_ifp = ifp; sc->sc_mii.mii_readreg = sis_miibus_readreg; sc->sc_mii.mii_writereg = sis_miibus_writereg; @@ -1179,7 +1179,7 @@ sis_ring_init(struct sis_softc *sc) { struct sis_list_data *ld; struct sis_ring_data *cd; - int i, error, nexti; + int i, nexti; cd = &sc->sis_cdata; ld = sc->sis_ldata; @@ -1190,8 +1190,9 @@ sis_ring_init(struct sis_softc *sc) else nexti = i + 1; ld->sis_tx_list[i].sis_nextdesc = &ld->sis_tx_list[nexti]; - ld->sis_tx_list[i].sis_next = sc->sc_listmap->dm_segs[0].ds_addr + - offsetof(struct sis_list_data, sis_tx_list[nexti]); + ld->sis_tx_list[i].sis_next = + sc->sc_listmap->dm_segs[0].ds_addr + + offsetof(struct sis_list_data, sis_tx_list[nexti]); ld->sis_tx_list[i].sis_mbuf = NULL; ld->sis_tx_list[i].sis_ptr = 0; ld->sis_tx_list[i].sis_ctl = 0; @@ -1199,68 +1200,70 @@ sis_ring_init(struct sis_softc *sc) cd->sis_tx_prod = cd->sis_tx_cons = cd->sis_tx_cnt = 0; - if (sc->arpcom.ac_if.if_flags & IFF_UP) - sc->sc_rxbufs = SIS_RX_LIST_CNT_MAX; - else - sc->sc_rxbufs = SIS_RX_LIST_CNT_MIN; - - for (i = 0; i < sc->sc_rxbufs; i++) { - error = sis_newbuf(sc, &ld->sis_rx_list[i], NULL); - if (error) - return (error); - if (i == (sc->sc_rxbufs - 1)) + for (i = 0; i < SIS_RX_LIST_CNT; i++) { + if (i == SIS_RX_LIST_CNT - 1) nexti = 0; else nexti = i + 1; ld->sis_rx_list[i].sis_nextdesc = &ld->sis_rx_list[nexti]; - ld->sis_rx_list[i].sis_next = sc->sc_listmap->dm_segs[0].ds_addr + - offsetof(struct sis_list_data, sis_rx_list[nexti]); + ld->sis_rx_list[i].sis_next = + sc->sc_listmap->dm_segs[0].ds_addr + + offsetof(struct sis_list_data, sis_rx_list[nexti]); + ld->sis_rx_list[i].sis_ctl = 0; } - cd->sis_rx_pdsc = &ld->sis_rx_list[0]; + cd->sis_rx_prod = cd->sis_rx_cons = cd->sis_rx_cnt = 0; + sis_fill_rx_ring(sc); return (0); } +void +sis_fill_rx_ring(struct sis_softc *sc) +{ + struct sis_list_data *ld; + struct sis_ring_data *cd; + + cd = &sc->sis_cdata; + ld = sc->sis_ldata; + + while (cd->sis_rx_cnt < SIS_RX_LIST_CNT) { + if (sis_newbuf(sc, &ld->sis_rx_list[cd->sis_rx_prod])) + break; + SIS_INC(cd->sis_rx_prod, SIS_RX_LIST_CNT); + cd->sis_rx_cnt++; + } +} + /* * Initialize an RX descriptor and attach an MBUF cluster. */ int -sis_newbuf(struct sis_softc *sc, struct sis_desc *c, struct mbuf *m) +sis_newbuf(struct sis_softc *sc, struct sis_desc *c) { struct mbuf *m_new = NULL; - bus_dmamap_t map; if (c == NULL) return (EINVAL); - if (m == NULL) { - MGETHDR(m_new, M_DONTWAIT, MT_DATA); - if (m_new == NULL) - return (ENOBUFS); + MGETHDR(m_new, M_DONTWAIT, MT_DATA); + if (m_new == NULL) + return (ENOBUFS); - MCLGET(m_new, M_DONTWAIT); - if (!(m_new->m_flags & M_EXT)) { - m_freem(m_new); - return (ENOBUFS); - } - } else { - m_new = m; - m_new->m_data = m_new->m_ext.ext_buf; + MCLGETI(m_new, M_DONTWAIT, &sc->arpcom.ac_if, MCLBYTES); + if (!(m_new->m_flags & M_EXT)) { + m_freem(m_new); + return (ENOBUFS); } m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; - if (bus_dmamap_load_mbuf(sc->sc_dmat, sc->sc_rx_sparemap, m_new, + if (bus_dmamap_load_mbuf(sc->sc_dmat, c->map, m_new, BUS_DMA_NOWAIT)) { m_freem(m_new); return (ENOBUFS); } - map = c->map; - c->map = sc->sc_rx_sparemap; - sc->sc_rx_sparemap = map; - bus_dmamap_sync(sc->sc_dmat, c->map, 0, c->map->dm_mapsize, BUS_DMASYNC_PREREAD); @@ -1290,9 +1293,10 @@ sis_rxeof(struct sis_softc *sc) ifp = &sc->arpcom.ac_if; - for(cur_rx = sc->sis_cdata.sis_rx_pdsc; SIS_OWNDESC(cur_rx); - cur_rx = cur_rx->sis_nextdesc) { - + while(sc->sis_cdata.sis_rx_cnt > 0) { + cur_rx = &sc->sis_ldata->sis_rx_list[sc->sis_cdata.sis_rx_cons]; + if (!SIS_OWNDESC(cur_rx)) + break; bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap, ((caddr_t)cur_rx - sc->sc_listkva), sizeof(struct sis_desc), @@ -1302,6 +1306,9 @@ sis_rxeof(struct sis_softc *sc) m = cur_rx->sis_mbuf; cur_rx->sis_mbuf = NULL; total_len = SIS_RXBYTES(cur_rx); + /* from here on the buffer is consumed */ + SIS_INC(sc->sis_cdata.sis_rx_cons, SIS_RX_LIST_CNT); + sc->sis_cdata.sis_rx_cnt--; /* * If an error occurs, update stats, clear the @@ -1317,14 +1324,14 @@ sis_rxeof(struct sis_softc *sc) ifp->if_ierrors++; if (rxstat & SIS_RXSTAT_COLL) ifp->if_collisions++; - sis_newbuf(sc, cur_rx, m); + m_freem(m); continue; } /* No errors; receive the packet. */ bus_dmamap_sync(sc->sc_dmat, cur_rx->map, 0, cur_rx->map->dm_mapsize, BUS_DMASYNC_POSTREAD); -#ifndef __STRICT_ALIGNMENT +#ifdef __STRICT_ALIGNMENT /* * On some architectures, we do not have alignment problems, * so try to allocate a new buffer for the receive ring, and @@ -1334,23 +1341,22 @@ sis_rxeof(struct sis_softc *sc) * if the allocation fails, then use m_devget and leave the * existing buffer in the receive ring. */ - if (sis_newbuf(sc, cur_rx, NULL) == 0) { - m->m_pkthdr.rcvif = ifp; - m->m_pkthdr.len = m->m_len = total_len; - } else -#endif - { + if (1) { struct mbuf *m0; m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp, NULL); - sis_newbuf(sc, cur_rx, m); + m_freem(m); if (m0 == NULL) { ifp->if_ierrors++; continue; } m = m0; + } else +#endif + { + m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.len = m->m_len = total_len; } - ifp->if_ipackets++; #if NBPFILTER > 0 @@ -1362,15 +1368,17 @@ sis_rxeof(struct sis_softc *sc) ether_input_mbuf(ifp, m); } - sc->sis_cdata.sis_rx_pdsc = cur_rx; + sis_fill_rx_ring(sc); } +#if 0 void sis_rxeoc(struct sis_softc *sc) { sis_rxeof(sc); sis_init(sc); } +#endif /* * A frame was downloaded to the chip. It's safe for us to clean up @@ -1500,13 +1508,20 @@ sis_intr(void *arg) SIS_ISR_RX_ERR | SIS_ISR_RX_IDLE)) sis_rxeof(sc); +#if 0 if (status & SIS_ISR_RX_OFLOW) sis_rxeoc(sc); - -#if 0 - if (status & (SIS_ISR_RX_IDLE)) - SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE); #endif + if (status & (SIS_ISR_RX_IDLE)) { + /* consume what's there so that sis_rx_cons points + * to the first HW owned descriptor. */ + sis_rxeof(sc); + /* reprogram the RX listptr */ + CSR_WRITE_4(sc, SIS_RX_LISTPTR, + sc->sc_listmap->dm_segs[0].ds_addr + + offsetof(struct sis_list_data, + sis_rx_list[sc->sis_cdata.sis_rx_cons])); + } if (status & SIS_ISR_SYSERR) { sis_reset(sc); @@ -2003,7 +2018,7 @@ sis_stop(struct sis_softc *sc) /* * Free data in the RX lists. */ - for (i = 0; i < SIS_RX_LIST_CNT_MAX; i++) { + for (i = 0; i < SIS_RX_LIST_CNT; i++) { if (sc->sis_ldata->sis_rx_list[i].map->dm_nsegs != 0) { bus_dmamap_t map = sc->sis_ldata->sis_rx_list[i].map; |