summaryrefslogtreecommitdiffstats
path: root/sys/dev/ral
diff options
context:
space:
mode:
authordamien <damien@FreeBSD.org>2005-11-13 17:19:12 +0000
committerdamien <damien@FreeBSD.org>2005-11-13 17:19:12 +0000
commitc63501ff97eba1036680173fc222dc6ade13e507 (patch)
tree3a0f16a46b0703e09409525c26305a316eaed44c /sys/dev/ral
parent7c8c64ed53424f98c7ef3fee4b56cb8b8dea9ea0 (diff)
downloadFreeBSD-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
Diffstat (limited to 'sys/dev/ral')
-rw-r--r--sys/dev/ral/if_ral.c62
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));
OpenPOWER on IntegriCloud