svn commit: r238432 - head/sys/dev/ath

Adrian Chadd adrian at FreeBSD.org
Sat Jul 14 02:07:52 UTC 2012


Author: adrian
Date: Sat Jul 14 02:07:51 2012
New Revision: 238432
URL: http://svn.freebsd.org/changeset/base/238432

Log:
  Fix EDMA RX to actually work without panicing the machine.
  
  I was setting up the RX EDMA buffer to be 4096 bytes rather than the
  RX data buffer portion.  The hardware was likely getting very confused
  and DMAing descriptor portions into places it shouldn't, leading to
  memory corruption and occasional panics.
  
  Whilst here, don't bother allocating descriptors for the RX EDMA case.
  We don't use those descriptors. Instead, just allocate ath_buf entries.

Modified:
  head/sys/dev/ath/if_ath.c
  head/sys/dev/ath/if_ath_misc.h
  head/sys/dev/ath/if_ath_rx_edma.c

Modified: head/sys/dev/ath/if_ath.c
==============================================================================
--- head/sys/dev/ath/if_ath.c	Sat Jul 14 01:45:35 2012	(r238431)
+++ head/sys/dev/ath/if_ath.c	Sat Jul 14 02:07:51 2012	(r238432)
@@ -2888,6 +2888,67 @@ fail0:
 #undef ATH_DESC_4KB_BOUND_CHECK
 }
 
+/*
+ * Allocate ath_buf entries but no descriptor contents.
+ *
+ * This is for RX EDMA where the descriptors are the header part of
+ * the RX buffer.
+ */
+int
+ath_descdma_setup_rx_edma(struct ath_softc *sc,
+	struct ath_descdma *dd, ath_bufhead *head,
+	const char *name, int nbuf, int rx_status_len)
+{
+	struct ifnet *ifp = sc->sc_ifp;
+	struct ath_buf *bf;
+	int i, bsize, error;
+
+	DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA: %u buffers\n",
+	    __func__, name, nbuf);
+
+	dd->dd_name = name;
+	/*
+	 * This is (mostly) purely for show.  We're not allocating any actual
+	 * descriptors here as EDMA RX has the descriptor be part
+	 * of the RX buffer.
+	 *
+	 * However, dd_desc_len is used by ath_descdma_free() to determine
+	 * whether we have already freed this DMA mapping.
+	 */
+	dd->dd_desc_len = rx_status_len;
+
+	/* allocate rx buffers */
+	bsize = sizeof(struct ath_buf) * nbuf;
+	bf = malloc(bsize, M_ATHDEV, M_NOWAIT | M_ZERO);
+	if (bf == NULL) {
+		if_printf(ifp, "malloc of %s buffers failed, size %u\n",
+			dd->dd_name, bsize);
+		goto fail3;
+	}
+	dd->dd_bufptr = bf;
+
+	TAILQ_INIT(head);
+	for (i = 0; i < nbuf; i++, bf++) {
+		bf->bf_desc = NULL;
+		bf->bf_daddr = 0;
+		bf->bf_lastds = NULL;	/* Just an initial value */
+
+		error = bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT,
+				&bf->bf_dmamap);
+		if (error != 0) {
+			if_printf(ifp, "unable to create dmamap for %s "
+				"buffer %u, error %u\n", dd->dd_name, i, error);
+			ath_descdma_cleanup(sc, dd, head);
+			return error;
+		}
+		TAILQ_INSERT_TAIL(head, bf, bf_list);
+	}
+	return 0;
+fail3:
+	memset(dd, 0, sizeof(*dd));
+	return error;
+}
+
 void
 ath_descdma_cleanup(struct ath_softc *sc,
 	struct ath_descdma *dd, ath_bufhead *head)

Modified: head/sys/dev/ath/if_ath_misc.h
==============================================================================
--- head/sys/dev/ath/if_ath_misc.h	Sat Jul 14 01:45:35 2012	(r238431)
+++ head/sys/dev/ath/if_ath_misc.h	Sat Jul 14 02:07:51 2012	(r238432)
@@ -86,6 +86,9 @@ extern void ath_setslottime(struct ath_s
 
 extern	int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
 	    ath_bufhead *head, const char *name, int nbuf, int ndesc);
+extern	int ath_descdma_setup_rx_edma(struct ath_softc *sc,
+	    struct ath_descdma *dd, ath_bufhead *head, const char *name,
+	    int nbuf, int desclen);
 extern	void ath_descdma_cleanup(struct ath_softc *sc,
 	    struct ath_descdma *dd, ath_bufhead *head);
 

Modified: head/sys/dev/ath/if_ath_rx_edma.c
==============================================================================
--- head/sys/dev/ath/if_ath_rx_edma.c	Sat Jul 14 01:45:35 2012	(r238431)
+++ head/sys/dev/ath/if_ath_rx_edma.c	Sat Jul 14 02:07:51 2012	(r238432)
@@ -696,11 +696,11 @@ ath_edma_dma_rxsetup(struct ath_softc *s
 {
 	int error;
 
-	/* Create RX DMA tag */
-	/* Create RX ath_buf array */
-
-	error = ath_descdma_setup(sc, &sc->sc_rxdma, &sc->sc_rxbuf,
-	    "rx", ath_rxbuf, 1);
+	/*
+	 * Create RX DMA tag and buffers.
+	 */
+	error = ath_descdma_setup_rx_edma(sc, &sc->sc_rxdma, &sc->sc_rxbuf,
+	    "rx", ath_rxbuf, sc->sc_rx_statuslen);
 	if (error != 0)
 		return error;
 
@@ -739,15 +739,16 @@ ath_recv_setup_edma(struct ath_softc *sc
 	/* Set buffer size to 4k */
 	sc->sc_edma_bufsize = 4096;
 
-	/* Configure the hardware with this */
-	(void) ath_hal_setrxbufsize(sc->sc_ah, sc->sc_edma_bufsize);
-
 	/* Fetch EDMA field and buffer sizes */
 	(void) ath_hal_getrxstatuslen(sc->sc_ah, &sc->sc_rx_statuslen);
 	(void) ath_hal_gettxdesclen(sc->sc_ah, &sc->sc_tx_desclen);
 	(void) ath_hal_gettxstatuslen(sc->sc_ah, &sc->sc_tx_statuslen);
 	(void) ath_hal_getntxmaps(sc->sc_ah, &sc->sc_tx_nmaps);
 
+	/* Configure the hardware with the RX buffer size */
+	(void) ath_hal_setrxbufsize(sc->sc_ah, sc->sc_edma_bufsize -
+	    sc->sc_rx_statuslen);
+
 	device_printf(sc->sc_dev, "RX status length: %d\n",
 	    sc->sc_rx_statuslen);
 	device_printf(sc->sc_dev, "TX descriptor length: %d\n",


More information about the svn-src-head mailing list