Subject: if_iwi patch
To: None <tech-kern@netbsd.org>
From: Joerg Sonnenberger <joerg@britannica.bec.de>
List: tech-kern
Date: 10/14/2005 21:23:10
--k+w/mQv8wyuph6w0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi all,
the attached patch is meant to fix the handling of iwi under low mbuf
conditions. The current code just segfaults, so this is definitely an
improvement. The dropping is inspired by similiar behaviour e.g. in fxp.
The only open question is where the explicit panic when the unload of
the old mbuf failed can ever be hit.

Are there any objections to commit this? I'd also provide similiar
patches at least for ral, too.

Joerg

--k+w/mQv8wyuph6w0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="if_iwi.c.diff"

Index: if_iwi.c
===================================================================
RCS file: /repo/netbsd/src/sys/dev/pci/if_iwi.c,v
retrieving revision 1.30
diff -u -r1.30 if_iwi.c
--- if_iwi.c	8 Oct 2005 06:19:46 -0000	1.30
+++ if_iwi.c	10 Oct 2005 12:30:57 -0000
@@ -104,6 +104,8 @@
     int);
 static void	iwi_reset_tx_ring(struct iwi_softc *, struct iwi_tx_ring *);
 static void	iwi_free_tx_ring(struct iwi_softc *, struct iwi_tx_ring *);
+static struct mbuf *
+		iwi_alloc_rx_buf(struct iwi_softc *sc);
 static int	iwi_alloc_rx_ring(struct iwi_softc *, struct iwi_rx_ring *,
     int);
 static void	iwi_reset_rx_ring(struct iwi_softc *, struct iwi_rx_ring *);
@@ -524,7 +526,7 @@
 	 */
 	error = bus_dmamap_create(sc->sc_dmat,
 	    IWI_TX_DESC_SIZE * count, 1,
-	    IWI_TX_DESC_SIZE * count, 0, BUS_DMA_NOWAIT,
+	    IWI_TX_DESC_SIZE * count, 0, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW,
 	    &ring->desc_map);
 	if (error != 0) {
 		aprint_error("%s: could not create tx ring DMA map\n",
@@ -670,19 +672,7 @@
 			goto fail;
 		}
 
-		MGETHDR(ring->data[i].m, M_DONTWAIT, MT_DATA);
-		if (ring->data[i].m == NULL) {
-			aprint_error("%s: could not allocate rx mbuf\n",
-			    sc->sc_dev.dv_xname);
-			error = ENOMEM;
-			goto fail;
-		}
-
-		MCLGET(ring->data[i].m, M_DONTWAIT);
-		if (!(ring->data[i].m->m_flags & M_EXT)) {
-			m_freem(ring->data[i].m);
-			aprint_error("%s: could not allocate rx mbuf cluster\n",
-			    sc->sc_dev.dv_xname);
+		if ((ring->data[i].m = iwi_alloc_rx_buf(sc)) == NULL) {
 			error = ENOMEM;
 			goto fail;
 		}
@@ -996,13 +986,36 @@
 	}
 }
 
+static struct mbuf *
+iwi_alloc_rx_buf(struct iwi_softc *sc)
+{
+	struct mbuf *m;
+
+	MGETHDR(m, M_DONTWAIT, MT_DATA);
+	if (m == NULL) {
+		aprint_error("%s: could not allocate rx mbuf\n",
+		    sc->sc_dev.dv_xname);
+		return NULL;
+	}
+
+	MCLGET(m, M_DONTWAIT);
+	if (!(m->m_flags & M_EXT)) {
+		aprint_error("%s: could not allocate rx mbuf cluster\n",
+		    sc->sc_dev.dv_xname);
+		m_freem(m);
+		return NULL;
+	}
+
+	return m;
+}
+
 static void
 iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data, int i,
     struct iwi_frame *frame)
 {
 	struct ieee80211com *ic = &sc->sc_ic;
 	struct ifnet *ifp = ic->ic_ifp;
-	struct mbuf *m;
+	struct mbuf *m, *m_new;
 	struct ieee80211_frame *wh;
 	struct ieee80211_node *ni;
 	int error;
@@ -1021,10 +1034,37 @@
 		return;
 	}
 
+	if ((m_new = iwi_alloc_rx_buf(sc)) == NULL) {
+		ifp->if_ierrors++;
+		return;
+	}
+
 	bus_dmamap_unload(sc->sc_dmat, data->map);
 
-	/* Finalize mbuf */
+	error = bus_dmamap_load(sc->sc_dmat, data->map, mtod(m_new, void *),
+	    MCLBYTES, NULL, BUS_DMA_NOWAIT);
+	if (error != 0) {
+		aprint_error("%s: could not load rx buf DMA map\n",
+		    sc->sc_dev.dv_xname);
+		m_freem(m_new);
+		ifp->if_ierrors++;
+		error = bus_dmamap_load(sc->sc_dmat, data->map,
+		    mtod(data->m, void *), MCLBYTES, NULL, BUS_DMA_NOWAIT);
+		if (error)
+			panic("%s: unable to remap rx buf",
+			    sc->sc_dev.dv_xname);
+		return;
+	}
+
+	/*
+	 * New mbuf successfully loaded, update RX ring and continue
+	 * processing.
+	 */
 	m = data->m;
+	data->m = m_new;
+	CSR_WRITE_4(sc, IWI_CSR_RX_BASE + i * 4, data->map->dm_segs[0].ds_addr);
+
+	/* Finalize mbuf */
 	m->m_pkthdr.rcvif = ifp;
 	m->m_pkthdr.len = m->m_len = sizeof (struct iwi_hdr) +
 	    sizeof (struct iwi_frame) + le16toh(frame->len);
@@ -1059,34 +1099,6 @@
 
 	/* node is no longer needed */
 	ieee80211_free_node(ni);
-
-	MGETHDR(data->m, M_DONTWAIT, MT_DATA);
-	if (data->m == NULL) {
-		aprint_error("%s: could not allocate rx mbuf\n",
-		    sc->sc_dev.dv_xname);
-		return;
-	}
-
-	MCLGET(data->m, M_DONTWAIT);
-	if (!(data->m->m_flags & M_EXT)) {
-		aprint_error("%s: could not allocate rx mbuf cluster\n",
-		    sc->sc_dev.dv_xname);
-		m_freem(data->m);
-		data->m = NULL;
-		return;
-	}
-
-	error = bus_dmamap_load(sc->sc_dmat, data->map, mtod(data->m, void *),
-	    MCLBYTES, NULL, BUS_DMA_NOWAIT);
-	if (error != 0) {
-		aprint_error("%s: could not load rx buf DMA map\n",
-		    sc->sc_dev.dv_xname);
-		m_freem(data->m);
-		data->m = NULL;
-		return;
-	}
-
-	CSR_WRITE_4(sc, IWI_CSR_RX_BASE + i * 4, data->map->dm_segs[0].ds_addr);
 }
 
 static void

--k+w/mQv8wyuph6w0--