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.
This commit is contained in:
Adrian Chadd 2012-07-14 02:07:51 +00:00
parent d35c4b1d44
commit 39abbd9bd2
3 changed files with 73 additions and 8 deletions

View File

@ -2888,6 +2888,67 @@ fail0:
#undef ATH_DESC_4KB_BOUND_CHECK #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 void
ath_descdma_cleanup(struct ath_softc *sc, ath_descdma_cleanup(struct ath_softc *sc,
struct ath_descdma *dd, ath_bufhead *head) struct ath_descdma *dd, ath_bufhead *head)

View File

@ -86,6 +86,9 @@ extern void ath_setslottime(struct ath_softc *sc);
extern int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, extern int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
ath_bufhead *head, const char *name, int nbuf, int ndesc); 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, extern void ath_descdma_cleanup(struct ath_softc *sc,
struct ath_descdma *dd, ath_bufhead *head); struct ath_descdma *dd, ath_bufhead *head);

View File

@ -696,11 +696,11 @@ ath_edma_dma_rxsetup(struct ath_softc *sc)
{ {
int error; int error;
/* Create RX DMA tag */ /*
/* Create RX ath_buf array */ * Create RX DMA tag and buffers.
*/
error = ath_descdma_setup(sc, &sc->sc_rxdma, &sc->sc_rxbuf, error = ath_descdma_setup_rx_edma(sc, &sc->sc_rxdma, &sc->sc_rxbuf,
"rx", ath_rxbuf, 1); "rx", ath_rxbuf, sc->sc_rx_statuslen);
if (error != 0) if (error != 0)
return error; return error;
@ -739,15 +739,16 @@ ath_recv_setup_edma(struct ath_softc *sc)
/* Set buffer size to 4k */ /* Set buffer size to 4k */
sc->sc_edma_bufsize = 4096; 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 */ /* Fetch EDMA field and buffer sizes */
(void) ath_hal_getrxstatuslen(sc->sc_ah, &sc->sc_rx_statuslen); (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_gettxdesclen(sc->sc_ah, &sc->sc_tx_desclen);
(void) ath_hal_gettxstatuslen(sc->sc_ah, &sc->sc_tx_statuslen); (void) ath_hal_gettxstatuslen(sc->sc_ah, &sc->sc_tx_statuslen);
(void) ath_hal_getntxmaps(sc->sc_ah, &sc->sc_tx_nmaps); (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", device_printf(sc->sc_dev, "RX status length: %d\n",
sc->sc_rx_statuslen); sc->sc_rx_statuslen);
device_printf(sc->sc_dev, "TX descriptor length: %d\n", device_printf(sc->sc_dev, "TX descriptor length: %d\n",