diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2005-11-23 21:15:30 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2005-11-23 21:15:30 +0000 |
commit | e2580f5bbb96b22ee8b0ee7ac9823b901bf374bd (patch) | |
tree | ad793390bace2871e922461d8b5f776944d30bb4 /sys/dev/pci | |
parent | 88900e751301a3453e1e9e5e30d0d6e28baea12c (diff) |
Be more robust when handling Rx interrupts. If we can't allocate and DMA map
a new mbuf, just discard the received frame and reuse the old mbuf.
From NetBSD (joerg@)
Diffstat (limited to 'sys/dev/pci')
-rw-r--r-- | sys/dev/pci/if_ipw.c | 72 |
1 files changed, 42 insertions, 30 deletions
diff --git a/sys/dev/pci/if_ipw.c b/sys/dev/pci/if_ipw.c index 3c0c878af36..8834119e57a 100644 --- a/sys/dev/pci/if_ipw.c +++ b/sys/dev/pci/if_ipw.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ipw.c,v 1.50 2005/08/09 04:10:12 mickey Exp $ */ +/* $OpenBSD: if_ipw.c,v 1.51 2005/11/23 21:15:29 damien Exp $ */ /*- * Copyright (c) 2004, 2005 @@ -841,20 +841,58 @@ ipw_data_intr(struct ipw_softc *sc, struct ipw_status *status, { struct ieee80211com *ic = &sc->sc_ic; struct ifnet *ifp = &ic->ic_if; - struct mbuf *m; + struct mbuf *mnew, *m; struct ieee80211_frame *wh; struct ieee80211_node *ni; int error; DPRINTFN(5, ("RX!DATA!%u!%u\n", letoh32(status->len), status->rssi)); + /* + * Try to allocate a new mbuf for this ring element and load it before + * processing the current mbuf. If the ring element cannot be loaded, + * drop the received packet and reuse the old mbuf. In the unlikely + * case that the old mbuf can't be reloaded either, explicitly panic. + */ + MGETHDR(mnew, M_DONTWAIT, MT_DATA); + if (mnew == NULL) { + ifp->if_ierrors++; + return; + } + + MCLGET(mnew, M_DONTWAIT); + if (!(mnew->m_flags & M_EXT)) { + m_freem(mnew); + ifp->if_ierrors++; + return; + } + bus_dmamap_sync(sc->sc_dmat, sbuf->map, 0, letoh32(status->len), BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(sc->sc_dmat, sbuf->map); - /* Finalize mbuf */ + error = bus_dmamap_load(sc->sc_dmat, sbuf->map, mtod(mnew, void *), + MCLBYTES, NULL, BUS_DMA_NOWAIT); + if (error != 0) { + m_freem(mnew); + + /* try to reload the old mbuf */ + error = bus_dmamap_load(sc->sc_dmat, sbuf->map, + mtod(sbuf->m, void *), MCLBYTES, NULL, BUS_DMA_NOWAIT); + if (error != 0) { + /* very unlikely that it will fail... */ + panic("%s: could not load old rx mbuf", + sc->sc_dev.dv_xname); + } + ifp->if_ierrors++; + return; + } + m = sbuf->m; + sbuf->m = mnew; + sbd->bd->physaddr = htole32(sbuf->map->dm_segs[0].ds_addr); + + /* Finalize mbuf */ m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = letoh32(status->len); @@ -885,32 +923,6 @@ ipw_data_intr(struct ipw_softc *sc, struct ipw_status *status, ieee80211_input(ifp, m, ni, status->rssi, 0); ieee80211_release_node(ic, ni); - - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) { - printf("%s: could not allocate rx mbuf\n", - sc->sc_dev.dv_xname); - return; - } - MCLGET(m, M_DONTWAIT); - if (!(m->m_flags & M_EXT)) { - m_freem(m); - printf("%s: could not allocate rx mbuf cluster\n", - sc->sc_dev.dv_xname); - return; - } - - error = bus_dmamap_load(sc->sc_dmat, sbuf->map, mtod(m, void *), - MCLBYTES, NULL, BUS_DMA_NOWAIT); - if (error != 0) { - printf("%s: could not map rx DMA memory\n", - sc->sc_dev.dv_xname); - m_freem(m); - return; - } - - sbuf->m = m; - sbd->bd->physaddr = htole32(sbuf->map->dm_segs[0].ds_addr); } void |