diff options
author | damien <damien@FreeBSD.org> | 2005-11-13 17:19:12 +0000 |
---|---|---|
committer | damien <damien@FreeBSD.org> | 2005-11-13 17:19:12 +0000 |
commit | c63501ff97eba1036680173fc222dc6ade13e507 (patch) | |
tree | 3a0f16a46b0703e09409525c26305a316eaed44c | |
parent | 7c8c64ed53424f98c7ef3fee4b56cb8b8dea9ea0 (diff) | |
download | FreeBSD-src-c63501ff97eba1036680173fc222dc6ade13e507.zip FreeBSD-src-c63501ff97eba1036680173fc222dc6ade13e507.tar.gz |
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.
This should fix kernel panics on high network traffic.
MFC after: 2 weeks
-rw-r--r-- | sys/dev/ral/if_ral.c | 62 |
1 files changed, 41 insertions, 21 deletions
diff --git a/sys/dev/ral/if_ral.c b/sys/dev/ral/if_ral.c index acc7daf..79cbd05 100644 --- a/sys/dev/ral/if_ral.c +++ b/sys/dev/ral/if_ral.c @@ -1317,7 +1317,7 @@ ral_decryption_intr(struct ral_softc *sc) struct ieee80211_frame *wh; struct ieee80211_node *ni; struct ral_node *rn; - struct mbuf *m; + struct mbuf *mnew, *m; int hw, error; /* retrieve last decriptor index processed by cipher engine */ @@ -1345,12 +1345,51 @@ 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. + */ + mnew = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); + if (mnew == NULL) { + ifp->if_ierrors++; + goto skip; + } + bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); bus_dmamap_unload(sc->rxq.data_dmat, data->map); - /* finalize mbuf */ + error = bus_dmamap_load(sc->rxq.data_dmat, data->map, + mtod(mnew, void *), MCLBYTES, ral_dma_map_addr, &physaddr, + 0); + if (error != 0) { + m_freem(mnew); + + /* try to reload the old mbuf */ + error = bus_dmamap_load(sc->rxq.data_dmat, data->map, + mtod(data->m, void *), MCLBYTES, ral_dma_map_addr, + &physaddr, 0); + if (error != 0) { + /* very unlikely that it will fail... */ + panic("%s: could not load old rx mbuf", + device_get_name(sc->sc_dev)); + } + ifp->if_ierrors++; + goto skip; + } + + /* + * New mbuf successfully loaded, update Rx ring and continue + * processing. + */ m = data->m; + data->m = mnew; + desc->physaddr = htole32(physaddr); + + /* finalize mbuf */ m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = (le32toh(desc->flags) >> 16) & 0xfff; @@ -1389,25 +1428,6 @@ ral_decryption_intr(struct ral_softc *sc) /* node is no longer needed */ ieee80211_free_node(ni); - data->m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); - if (data->m == NULL) { - device_printf(sc->sc_dev, - "could not allocate rx mbuf\n"); - break; - } - - error = bus_dmamap_load(sc->rxq.data_dmat, data->map, - mtod(data->m, void *), MCLBYTES, ral_dma_map_addr, - &physaddr, 0); - if (error != 0) { - device_printf(sc->sc_dev, - "could not load rx buf DMA map\n"); - m_freem(data->m); - data->m = NULL; - break; - } - - desc->physaddr = htole32(physaddr); skip: desc->flags = htole32(RAL_RX_BUSY); DPRINTFN(15, ("decryption done idx=%u\n", sc->rxq.cur_decrypt)); |