Implement the 4KB split transaction workaround for Merlin (AR9280).

The AR9280 apparently has an issue with descriptors which straddle a page
boundary (4k). I'm not yet sure whether I should use PAGE_SIZE in the
calculations or whether I should use 4096; the reference code uses 4096.

This patch fiddles with descriptor allocation so a descriptor entry
doesn't straddle a 4kb address boundary. The descriptor memory allocation
is made larger to contain extra descriptors and then the descriptor
address is advanced to the next 4kb boundary where needed.

I've tested this both on Merlin (AR9280) and non-Merlin (in this case,
AR9160.)

Obtained from:	Linux, Atheros
Approved by:	re (kib)
This commit is contained in:
Adrian Chadd 2011-07-31 08:01:41 +00:00
parent ab7aca78ca
commit 45abcd6c9c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=224541

View file

@ -2937,16 +2937,36 @@ ath_descdma_setup(struct ath_softc *sc,
{
#define DS2PHYS(_dd, _ds) \
((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
#define ATH_DESC_4KB_BOUND_CHECK(_daddr, _len) \
((((u_int32_t)(_daddr) & 0xFFF) > (0x1000 - (_len))) ? 1 : 0)
struct ifnet *ifp = sc->sc_ifp;
struct ath_desc *ds;
uint8_t *ds;
struct ath_buf *bf;
int i, bsize, error;
int desc_len;
desc_len = sizeof(struct ath_desc);
DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA: %u buffers %u desc/buf\n",
__func__, name, nbuf, ndesc);
dd->dd_name = name;
dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc;
dd->dd_desc_len = desc_len * nbuf * ndesc;
device_printf(sc->sc_dev, "desc_len: %d, nbuf=%d, ndesc=%d; dd_desc_len=%d\n",
desc_len, nbuf, ndesc, dd->dd_desc_len);
/*
* Merlin work-around:
* Descriptors that cross the 4KB boundary can't be used.
* Assume one skipped descriptor per 4KB page.
*/
if (! ath_hal_split4ktrans(sc->sc_ah)) {
int numdescpage = 4096 / (desc_len * ndesc);
dd->dd_desc_len = (nbuf / numdescpage + 1) * 4096;
device_printf(sc->sc_dev, "numdescpage: %d, new dd_desc_len=%d\n",
numdescpage, dd->dd_desc_len);
}
/*
* Setup DMA descriptor area.
@ -2995,7 +3015,7 @@ ath_descdma_setup(struct ath_softc *sc,
goto fail2;
}
ds = dd->dd_desc;
ds = (uint8_t *) dd->dd_desc;
DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA map: %p (%lu) -> %p (%lu)\n",
__func__, dd->dd_name, ds, (u_long) dd->dd_desc_len,
(caddr_t) dd->dd_desc_paddr, /*XXX*/ (u_long) dd->dd_desc_len);
@ -3011,9 +3031,23 @@ ath_descdma_setup(struct ath_softc *sc,
dd->dd_bufptr = bf;
STAILQ_INIT(head);
for (i = 0; i < nbuf; i++, bf++, ds += ndesc) {
bf->bf_desc = ds;
for (i = 0; i < nbuf; i++, bf++, ds += (ndesc * desc_len)) {
bf->bf_desc = (struct ath_desc *) ds;
bf->bf_daddr = DS2PHYS(dd, ds);
if (! ath_hal_split4ktrans(sc->sc_ah)) {
/*
* Merlin WAR: Skip descriptor addresses which
* cause 4KB boundary crossing along any point
* in the descriptor.
*/
if (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr,
desc_len * ndesc)) {
/* Start at the next page */
ds += 0x1000 - (bf->bf_daddr & 0xFFF);
bf->bf_desc = (struct ath_desc *) ds;
bf->bf_daddr = DS2PHYS(dd, ds);
}
}
error = bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT,
&bf->bf_dmamap);
if (error != 0) {
@ -3036,6 +3070,7 @@ ath_descdma_setup(struct ath_softc *sc,
memset(dd, 0, sizeof(*dd));
return error;
#undef DS2PHYS
#undef ATH_DESC_4KB_BOUND_CHECK
}
static void