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

Adrian Chadd adrian at FreeBSD.org
Sun Jul 31 08:01:42 UTC 2011


Author: adrian
Date: Sun Jul 31 08:01:41 2011
New Revision: 224541
URL: http://svn.freebsd.org/changeset/base/224541

Log:
  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)

Modified:
  head/sys/dev/ath/if_ath.c

Modified: head/sys/dev/ath/if_ath.c
==============================================================================
--- head/sys/dev/ath/if_ath.c	Sun Jul 31 05:59:33 2011	(r224540)
+++ head/sys/dev/ath/if_ath.c	Sun Jul 31 08:01:41 2011	(r224541)
@@ -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


More information about the svn-src-head mailing list