From owner-svn-src-all@FreeBSD.ORG Sun Jul 31 08:01:42 2011 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 76DD3106566B; Sun, 31 Jul 2011 08:01:41 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 5D6418FC12; Sun, 31 Jul 2011 08:01:41 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id p6V81f71035729; Sun, 31 Jul 2011 08:01:41 GMT (envelope-from adrian@svn.freebsd.org) Received: (from adrian@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id p6V81fnH035727; Sun, 31 Jul 2011 08:01:41 GMT (envelope-from adrian@svn.freebsd.org) Message-Id: <201107310801.p6V81fnH035727@svn.freebsd.org> From: Adrian Chadd Date: Sun, 31 Jul 2011 08:01:41 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r224541 - head/sys/dev/ath X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 31 Jul 2011 08:01:42 -0000 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