diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2007-08-22 19:50:26 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2007-08-22 19:50:26 +0000 |
commit | dd654a77e55db513af679bbba472472b1a70b096 (patch) | |
tree | c9f8ff688e9c7177f65961021b52f5c013d175b6 | |
parent | 72cafb89b9cca2393b2fb7a479b1f103493f645b (diff) |
when running out of rx buffers, allocate a new mbuf and copy the rx
buffer into it using m_copym2() instead of just dropping the received
frame. otherwise, it may happen that all rx buffers are queued by
tcp_input() waiting for a frame that will never arrive because we are
dropping it. when it happens, rx stop working and it is hard to
recover from this.
the problem is not visible when using WEP because WEP decryption is
currently done by software and that rx buffers are copied into mbufs
by the software decryption code.
while i'm here, increase the number of rx buffers allocated by wpi(4)
from 80 to 96 to limit the number of copies.
problem and solution found by bluhm@ - thanks.
-rw-r--r-- | sys/dev/pci/if_wpi.c | 48 | ||||
-rw-r--r-- | sys/dev/pci/if_wpivar.h | 4 |
2 files changed, 30 insertions, 22 deletions
diff --git a/sys/dev/pci/if_wpi.c b/sys/dev/pci/if_wpi.c index ff0e688e9d3..44a9ce828d5 100644 --- a/sys/dev/pci/if_wpi.c +++ b/sys/dev/pci/if_wpi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_wpi.c,v 1.50 2007/08/10 16:29:27 jasper Exp $ */ +/* $OpenBSD: if_wpi.c,v 1.51 2007/08/22 19:50:25 damien Exp $ */ /*- * Copyright (c) 2006, 2007 @@ -1234,30 +1234,38 @@ wpi_rx_intr(struct wpi_softc *sc, struct wpi_rx_desc *desc, return; } - MGETHDR(mnew, M_DONTWAIT, MT_DATA); - if (mnew == NULL) { - ifp->if_ierrors++; - return; - } - if ((rbuf = wpi_alloc_rbuf(sc)) == NULL) { - m_freem(mnew); - ifp->if_ierrors++; - return; - } - /* attach Rx buffer to mbuf */ - MEXTADD(mnew, rbuf->vaddr, WPI_RBUF_SIZE, 0, wpi_free_rbuf, rbuf); - m = data->m; - data->m = mnew; - - /* update Rx descriptor */ - ring->desc[ring->cur] = htole32(rbuf->paddr); - /* finalize mbuf */ m->m_pkthdr.rcvif = ifp; m->m_data = (caddr_t)(head + 1); m->m_pkthdr.len = m->m_len = letoh16(head->len); + if ((rbuf = SLIST_FIRST(&sc->rxq.freelist)) != NULL) { + MGETHDR(mnew, M_DONTWAIT, MT_DATA); + if (mnew == NULL) { + ifp->if_ierrors++; + return; + } + + /* attach Rx buffer to mbuf */ + MEXTADD(mnew, rbuf->vaddr, WPI_RBUF_SIZE, 0, wpi_free_rbuf, + rbuf); + SLIST_REMOVE_HEAD(&sc->rxq.freelist, next); + + data->m = mnew; + + /* update Rx descriptor */ + ring->desc[ring->cur] = htole32(rbuf->paddr); + } else { + /* no free rbufs, copy frame */ + m = m_copym2(m, 0, M_COPYALL, M_DONTWAIT); + if (m == NULL) { + /* no free mbufs either, drop frame */ + ifp->if_ierrors++; + return; + } + } + #if NBPFILTER > 0 if (sc->sc_drvbpf != NULL) { struct mbuf mb; @@ -1389,7 +1397,7 @@ wpi_notif_intr(struct wpi_softc *sc) hw = letoh32(sc->shared->next); while (sc->rxq.cur != hw) { struct wpi_rx_data *data = &sc->rxq.data[sc->rxq.cur]; - struct wpi_rx_desc *desc = mtod(data->m, struct wpi_rx_desc *); + struct wpi_rx_desc *desc = (void *)data->m->m_ext.ext_buf; DPRINTFN(4, ("rx notification qid=%x idx=%d flags=%x type=%d " "len=%d\n", desc->qid, desc->idx, desc->flags, desc->type, diff --git a/sys/dev/pci/if_wpivar.h b/sys/dev/pci/if_wpivar.h index 09daa0c80c3..921afe74bdf 100644 --- a/sys/dev/pci/if_wpivar.h +++ b/sys/dev/pci/if_wpivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_wpivar.h,v 1.12 2007/06/16 14:15:37 damien Exp $ */ +/* $OpenBSD: if_wpivar.h,v 1.13 2007/08/22 19:50:25 damien Exp $ */ /*- * Copyright (c) 2006, 2007 @@ -80,7 +80,7 @@ struct wpi_tx_ring { int cur; }; -#define WPI_RBUF_COUNT (WPI_RX_RING_COUNT + 16) +#define WPI_RBUF_COUNT (WPI_RX_RING_COUNT + 32) struct wpi_softc; |