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