diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2009-04-14 19:06:50 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2009-04-14 19:06:50 +0000 |
commit | 106c4031f042e820cde866e483168be5edb8e97a (patch) | |
tree | e8034c03584e14c2841e8428415bfe9d8432e9c9 /sys/dev/pci | |
parent | 0eeedccf76bc2c7471d658552dead38ad5afbea9 (diff) |
Convert sis(4) to MCLGETI() and make soekris suck much less. With this the
little green slug does not block userland even when hammered with twice as
much traffic it can handle. Almost the same code I came up during h2k8 but
now with two other bugs fixed that where exposed by MCLGETI().
Tested and OK dlg@ sthen@ and a lot of pushing by Theo.
Diffstat (limited to 'sys/dev/pci')
-rw-r--r-- | sys/dev/pci/if_sis.c | 139 | ||||
-rw-r--r-- | sys/dev/pci/if_sisreg.h | 13 |
2 files changed, 83 insertions, 69 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; diff --git a/sys/dev/pci/if_sisreg.h b/sys/dev/pci/if_sisreg.h index 1770a1576ec..2766b832469 100644 --- a/sys/dev/pci/if_sisreg.h +++ b/sys/dev/pci/if_sisreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_sisreg.h,v 1.28 2009/02/24 21:10:14 claudio Exp $ */ +/* $OpenBSD: if_sisreg.h,v 1.29 2009/04/14 19:06:49 claudio Exp $ */ /* * Copyright (c) 1997, 1998, 1999 * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. @@ -375,17 +375,18 @@ struct sis_desc { #define SIS_TXSTAT_UNDERRUN 0x02000000 #define SIS_TXSTAT_TX_ABORT 0x04000000 -#define SIS_RX_LIST_CNT_MIN 4 -#define SIS_RX_LIST_CNT_MAX 64 +#define SIS_RX_LIST_CNT 64 #define SIS_TX_LIST_CNT 128 struct sis_list_data { - struct sis_desc sis_rx_list[SIS_RX_LIST_CNT_MAX]; + struct sis_desc sis_rx_list[SIS_RX_LIST_CNT]; struct sis_desc sis_tx_list[SIS_TX_LIST_CNT]; }; struct sis_ring_data { - struct sis_desc *sis_rx_pdsc; + int sis_rx_prod; + int sis_rx_cons; + int sis_rx_cnt; int sis_tx_prod; int sis_tx_cons; int sis_tx_cnt; @@ -462,10 +463,8 @@ struct sis_softc { bus_dma_segment_t sc_listseg[1]; int sc_listnseg; caddr_t sc_listkva; - bus_dmamap_t sc_rx_sparemap; bus_dmamap_t sc_tx_sparemap; int sis_stopped; - int sc_rxbufs; int sc_if_flags; }; |