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:
parent
ab7aca78ca
commit
45abcd6c9c
@ -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 @@ fail0:
|
||||
memset(dd, 0, sizeof(*dd));
|
||||
return error;
|
||||
#undef DS2PHYS
|
||||
#undef ATH_DESC_4KB_BOUND_CHECK
|
||||
}
|
||||
|
||||
static void
|
||||
|
Loading…
x
Reference in New Issue
Block a user