diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2005-11-23 20:51:21 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2005-11-23 20:51:21 +0000 |
commit | 2fe43460cac6c80d84ca83a03bc31579cd0b1c07 (patch) | |
tree | 5e693e645b1085c071e49ddeca86696bbed44cd0 /sys/dev/ic | |
parent | f68ca1b22c9b07c6e43b9518ce5ef4f1c808d2fd (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/ic')
-rw-r--r-- | sys/dev/ic/ral.c | 78 |
1 files changed, 48 insertions, 30 deletions
diff --git a/sys/dev/ic/ral.c b/sys/dev/ic/ral.c index 783425dd84c..904a1603d11 100644 --- a/sys/dev/ic/ral.c +++ b/sys/dev/ic/ral.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ral.c,v 1.63 2005/11/23 19:56:49 damien Exp $ */ +/* $OpenBSD: ral.c,v 1.64 2005/11/23 20:51:20 damien Exp $ */ /*- * Copyright (c) 2005 @@ -1225,7 +1225,7 @@ ral_decryption_intr(struct ral_softc *sc) struct ral_node *rn; struct ieee80211_frame *wh; struct ieee80211_node *ni; - struct mbuf *m; + struct mbuf *mnew, *m; int hw, error; /* retrieve last decriptor index processed by cipher engine */ @@ -1253,12 +1253,57 @@ ral_decryption_intr(struct ral_softc *sc) goto skip; } + /* + * 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++; + goto skip; + } + + MCLGET(mnew, M_DONTWAIT); + if (!(mnew->m_flags & M_EXT)) { + m_freem(mnew); + ifp->if_ierrors++; + goto skip; + } + bus_dmamap_sync(sc->sc_dmat, data->map, 0, data->map->dm_mapsize, BUS_DMASYNC_POSTREAD); bus_dmamap_unload(sc->sc_dmat, data->map); - /* finalize mbuf */ + error = bus_dmamap_load(sc->sc_dmat, data->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, data->map, + mtod(data->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++; + goto skip; + } + + /* + * New mbuf successfully loaded, update Rx ring and continue + * processing. + */ m = data->m; + data->m = mnew; + desc->physaddr = htole32(data->map->dm_segs->ds_addr); + + /* finalize mbuf */ m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = (letoh32(desc->flags) >> 16) & 0xfff; @@ -1304,33 +1349,6 @@ ral_decryption_intr(struct ral_softc *sc) /* node is no longer needed */ ieee80211_release_node(ic, ni); - MGETHDR(data->m, M_DONTWAIT, MT_DATA); - if (data->m == NULL) { - printf("%s: could not allocate rx mbuf\n", - sc->sc_dev.dv_xname); - break; - } - - MCLGET(data->m, M_DONTWAIT); - if (!(data->m->m_flags & M_EXT)) { - printf("%s: could not allocate rx mbuf cluster\n", - sc->sc_dev.dv_xname); - m_freem(data->m); - data->m = NULL; - break; - } - - error = bus_dmamap_load(sc->sc_dmat, data->map, - mtod(data->m, void *), MCLBYTES, NULL, BUS_DMA_NOWAIT); - if (error != 0) { - printf("%s: could not load rx buf DMA map\n", - sc->sc_dev.dv_xname); - m_freem(data->m); - data->m = NULL; - break; - } - - desc->physaddr = htole32(data->map->dm_segs->ds_addr); skip: desc->flags = htole32(RAL_RX_BUSY); bus_dmamap_sync(sc->sc_dmat, sc->rxq.map, |