Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 24 Nov 2015 03:42:58 +0000 (UTC)
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r291233 - in head/sys: conf dev/ath modules/ath
Message-ID:  <201511240342.tAO3gw4w036329@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: adrian
Date: Tue Nov 24 03:42:58 2015
New Revision: 291233
URL: https://svnweb.freebsd.org/changeset/base/291233

Log:
  [ath] migrate ioctl and busdma memory operations out into separate source files.
  
  This should be a big no-op pass; and reduces the size of if_ath.c.
  
  I'm hopefully soon going to take a whack at the USB support for ath(4)
  and this'll require some reuse of the busdma memory code.

Added:
  head/sys/dev/ath/if_ath_descdma.c   (contents, props changed)
  head/sys/dev/ath/if_ath_descdma.h   (contents, props changed)
  head/sys/dev/ath/if_ath_ioctl.c   (contents, props changed)
  head/sys/dev/ath/if_ath_ioctl.h   (contents, props changed)
Modified:
  head/sys/conf/files
  head/sys/dev/ath/if_ath.c
  head/sys/dev/ath/if_ath_misc.h
  head/sys/dev/ath/if_ath_rx.c
  head/sys/dev/ath/if_ath_rx_edma.c
  head/sys/dev/ath/if_ath_tx_edma.c
  head/sys/modules/ath/Makefile

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Tue Nov 24 02:37:16 2015	(r291232)
+++ head/sys/conf/files	Tue Nov 24 03:42:58 2015	(r291233)
@@ -748,8 +748,12 @@ dev/ath/if_ath_btcoex.c		optional ath \
 	compile-with "${NORMAL_C} -I$S/dev/ath"
 dev/ath/if_ath_debug.c		optional ath \
 	compile-with "${NORMAL_C} -I$S/dev/ath"
+dev/ath/if_ath_descdma.c	optional ath \
+	compile-with "${NORMAL_C} -I$S/dev/ath"
 dev/ath/if_ath_keycache.c	optional ath \
 	compile-with "${NORMAL_C} -I$S/dev/ath"
+dev/ath/if_ath_ioctl.c		optional ath \
+	compile-with "${NORMAL_C} -I$S/dev/ath"
 dev/ath/if_ath_led.c		optional ath \
 	compile-with "${NORMAL_C} -I$S/dev/ath"
 dev/ath/if_ath_lna_div.c	optional ath \

Modified: head/sys/dev/ath/if_ath.c
==============================================================================
--- head/sys/dev/ath/if_ath.c	Tue Nov 24 02:37:16 2015	(r291232)
+++ head/sys/dev/ath/if_ath.c	Tue Nov 24 03:42:58 2015	(r291233)
@@ -116,6 +116,8 @@ __FBSDID("$FreeBSD$");
 #include <dev/ath/if_ath_spectral.h>
 #include <dev/ath/if_ath_lna_div.h>
 #include <dev/ath/if_athdfs.h>
+#include <dev/ath/if_ath_ioctl.h>
+#include <dev/ath/if_ath_descdma.h>
 
 #ifdef ATH_TX99_DIAG
 #include <dev/ath/ath_tx99/ath_tx99.h>
@@ -157,7 +159,6 @@ static int	ath_reset_vap(struct ieee8021
 static int	ath_transmit(struct ieee80211com *, struct mbuf *);
 static int	ath_media_change(struct ifnet *);
 static void	ath_watchdog(void *);
-static int	ath_ioctl(struct ieee80211com *, u_long, void *);
 static void	ath_parent(struct ieee80211com *);
 static void	ath_fatal_proc(void *, int);
 static void	ath_bmiss_vap(struct ieee80211vap *);
@@ -3668,320 +3669,6 @@ ath_bstuck_proc(void *arg, int pending)
 	ath_reset(sc, ATH_RESET_NOLOSS);
 }
 
-static void
-ath_load_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
-{
-	bus_addr_t *paddr = (bus_addr_t*) arg;
-	KASSERT(error == 0, ("error %u on bus_dma callback", error));
-	*paddr = segs->ds_addr;
-}
-
-/*
- * Allocate the descriptors and appropriate DMA tag/setup.
- *
- * For some situations (eg EDMA TX completion), there isn't a requirement
- * for the ath_buf entries to be allocated.
- */
-int
-ath_descdma_alloc_desc(struct ath_softc *sc,
-	struct ath_descdma *dd, ath_bufhead *head,
-	const char *name, int ds_size, int ndesc)
-{
-#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)
-	int error;
-
-	dd->dd_descsize = ds_size;
-
-	DPRINTF(sc, ATH_DEBUG_RESET,
-	    "%s: %s DMA: %u desc, %d bytes per descriptor\n",
-	    __func__, name, ndesc, dd->dd_descsize);
-
-	dd->dd_name = name;
-	dd->dd_desc_len = dd->dd_descsize * ndesc;
-
-	/*
-	 * 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 numpages = dd->dd_desc_len / 4096;
-		dd->dd_desc_len += ds_size * numpages;
-	}
-
-	/*
-	 * Setup DMA descriptor area.
-	 *
-	 * BUS_DMA_ALLOCNOW is not used; we never use bounce
-	 * buffers for the descriptors themselves.
-	 */
-	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev),	/* parent */
-		       PAGE_SIZE, 0,		/* alignment, bounds */
-		       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
-		       BUS_SPACE_MAXADDR,	/* highaddr */
-		       NULL, NULL,		/* filter, filterarg */
-		       dd->dd_desc_len,		/* maxsize */
-		       1,			/* nsegments */
-		       dd->dd_desc_len,		/* maxsegsize */
-		       0,			/* flags */
-		       NULL,			/* lockfunc */
-		       NULL,			/* lockarg */
-		       &dd->dd_dmat);
-	if (error != 0) {
-		device_printf(sc->sc_dev,
-		    "cannot allocate %s DMA tag\n", dd->dd_name);
-		return error;
-	}
-
-	/* allocate descriptors */
-	error = bus_dmamem_alloc(dd->dd_dmat, (void**) &dd->dd_desc,
-				 BUS_DMA_NOWAIT | BUS_DMA_COHERENT,
-				 &dd->dd_dmamap);
-	if (error != 0) {
-		device_printf(sc->sc_dev,
-		    "unable to alloc memory for %u %s descriptors, error %u\n",
-		    ndesc, dd->dd_name, error);
-		goto fail1;
-	}
-
-	error = bus_dmamap_load(dd->dd_dmat, dd->dd_dmamap,
-				dd->dd_desc, dd->dd_desc_len,
-				ath_load_cb, &dd->dd_desc_paddr,
-				BUS_DMA_NOWAIT);
-	if (error != 0) {
-		device_printf(sc->sc_dev,
-		    "unable to map %s descriptors, error %u\n",
-		    dd->dd_name, error);
-		goto fail2;
-	}
-
-	DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA map: %p (%lu) -> %p (%lu)\n",
-	    __func__, dd->dd_name, (uint8_t *) dd->dd_desc,
-	    (u_long) dd->dd_desc_len, (caddr_t) dd->dd_desc_paddr,
-	    /*XXX*/ (u_long) dd->dd_desc_len);
-
-	return (0);
-
-fail2:
-	bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap);
-fail1:
-	bus_dma_tag_destroy(dd->dd_dmat);
-	memset(dd, 0, sizeof(*dd));
-	return error;
-#undef DS2PHYS
-#undef ATH_DESC_4KB_BOUND_CHECK
-}
-
-int
-ath_descdma_setup(struct ath_softc *sc,
-	struct ath_descdma *dd, ath_bufhead *head,
-	const char *name, int ds_size, int nbuf, int ndesc)
-{
-#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)
-	uint8_t *ds;
-	struct ath_buf *bf;
-	int i, bsize, error;
-
-	/* Allocate descriptors */
-	error = ath_descdma_alloc_desc(sc, dd, head, name, ds_size,
-	    nbuf * ndesc);
-
-	/* Assume any errors during allocation were dealt with */
-	if (error != 0) {
-		return (error);
-	}
-
-	ds = (uint8_t *) dd->dd_desc;
-
-	/* allocate rx buffers */
-	bsize = sizeof(struct ath_buf) * nbuf;
-	bf = malloc(bsize, M_ATHDEV, M_NOWAIT | M_ZERO);
-	if (bf == NULL) {
-		device_printf(sc->sc_dev,
-		    "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++, ds += (ndesc * dd->dd_descsize)) {
-		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,
-			     dd->dd_descsize)) {
-				/* 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) {
-			device_printf(sc->sc_dev, "unable to create dmamap "
-			    "for %s buffer %u, error %u\n",
-			    dd->dd_name, i, error);
-			ath_descdma_cleanup(sc, dd, head);
-			return error;
-		}
-		bf->bf_lastds = bf->bf_desc;	/* Just an initial value */
-		TAILQ_INSERT_TAIL(head, bf, bf_list);
-	}
-
-	/*
-	 * XXX TODO: ensure that ds doesn't overflow the descriptor
-	 * allocation otherwise weird stuff will occur and crash your
-	 * machine.
-	 */
-	return 0;
-	/* XXX this should likely just call ath_descdma_cleanup() */
-fail3:
-	bus_dmamap_unload(dd->dd_dmat, dd->dd_dmamap);
-	bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap);
-	bus_dma_tag_destroy(dd->dd_dmat);
-	memset(dd, 0, sizeof(*dd));
-	return error;
-#undef DS2PHYS
-#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 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 * nbuf;
-	dd->dd_descsize = rx_status_len;
-
-	/* allocate rx buffers */
-	bsize = sizeof(struct ath_buf) * nbuf;
-	bf = malloc(bsize, M_ATHDEV, M_NOWAIT | M_ZERO);
-	if (bf == NULL) {
-		device_printf(sc->sc_dev,
-		    "malloc of %s buffers failed, size %u\n",
-		    dd->dd_name, bsize);
-		error = ENOMEM;
-		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) {
-			device_printf(sc->sc_dev, "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
-ath_descdma_cleanup(struct ath_softc *sc,
-	struct ath_descdma *dd, ath_bufhead *head)
-{
-	struct ath_buf *bf;
-	struct ieee80211_node *ni;
-	int do_warning = 0;
-
-	if (dd->dd_dmamap != 0) {
-		bus_dmamap_unload(dd->dd_dmat, dd->dd_dmamap);
-		bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap);
-		bus_dma_tag_destroy(dd->dd_dmat);
-	}
-
-	if (head != NULL) {
-		TAILQ_FOREACH(bf, head, bf_list) {
-			if (bf->bf_m) {
-				/*
-				 * XXX warn if there's buffers here.
-				 * XXX it should have been freed by the
-				 * owner!
-				 */
-				
-				if (do_warning == 0) {
-					do_warning = 1;
-					device_printf(sc->sc_dev,
-					    "%s: %s: mbuf should've been"
-					    " unmapped/freed!\n",
-					    __func__,
-					    dd->dd_name);
-				}
-				bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
-				    BUS_DMASYNC_POSTREAD);
-				bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
-				m_freem(bf->bf_m);
-				bf->bf_m = NULL;
-			}
-			if (bf->bf_dmamap != NULL) {
-				bus_dmamap_destroy(sc->sc_dmat, bf->bf_dmamap);
-				bf->bf_dmamap = NULL;
-			}
-			ni = bf->bf_node;
-			bf->bf_node = NULL;
-			if (ni != NULL) {
-				/*
-				 * Reclaim node reference.
-				 */
-				ieee80211_free_node(ni);
-			}
-		}
-	}
-
-	if (head != NULL)
-		TAILQ_INIT(head);
-
-	if (dd->dd_bufptr != NULL)
-		free(dd->dd_bufptr, M_ATHDEV);
-	memset(dd, 0, sizeof(*dd));
-}
-
 static int
 ath_desc_alloc(struct ath_softc *sc)
 {
@@ -6419,119 +6106,6 @@ ath_watchdog(void *arg)
 	callout_schedule(&sc->sc_wd_ch, hz);
 }
 
-/*
- * Fetch the rate control statistics for the given node.
- */
-static int
-ath_ioctl_ratestats(struct ath_softc *sc, struct ath_rateioctl *rs)
-{
-	struct ath_node *an;
-	struct ieee80211com *ic = &sc->sc_ic;
-	struct ieee80211_node *ni;
-	int error = 0;
-
-	/* Perform a lookup on the given node */
-	ni = ieee80211_find_node(&ic->ic_sta, rs->is_u.macaddr);
-	if (ni == NULL) {
-		error = EINVAL;
-		goto bad;
-	}
-
-	/* Lock the ath_node */
-	an = ATH_NODE(ni);
-	ATH_NODE_LOCK(an);
-
-	/* Fetch the rate control stats for this node */
-	error = ath_rate_fetch_node_stats(sc, an, rs);
-
-	/* No matter what happens here, just drop through */
-
-	/* Unlock the ath_node */
-	ATH_NODE_UNLOCK(an);
-
-	/* Unref the node */
-	ieee80211_node_decref(ni);
-
-bad:
-	return (error);
-}
-
-#ifdef ATH_DIAGAPI
-/*
- * Diagnostic interface to the HAL.  This is used by various
- * tools to do things like retrieve register contents for
- * debugging.  The mechanism is intentionally opaque so that
- * it can change frequently w/o concern for compatiblity.
- */
-static int
-ath_ioctl_diag(struct ath_softc *sc, struct ath_diag *ad)
-{
-	struct ath_hal *ah = sc->sc_ah;
-	u_int id = ad->ad_id & ATH_DIAG_ID;
-	void *indata = NULL;
-	void *outdata = NULL;
-	u_int32_t insize = ad->ad_in_size;
-	u_int32_t outsize = ad->ad_out_size;
-	int error = 0;
-
-	if (ad->ad_id & ATH_DIAG_IN) {
-		/*
-		 * Copy in data.
-		 */
-		indata = malloc(insize, M_TEMP, M_NOWAIT);
-		if (indata == NULL) {
-			error = ENOMEM;
-			goto bad;
-		}
-		error = copyin(ad->ad_in_data, indata, insize);
-		if (error)
-			goto bad;
-	}
-	if (ad->ad_id & ATH_DIAG_DYN) {
-		/*
-		 * Allocate a buffer for the results (otherwise the HAL
-		 * returns a pointer to a buffer where we can read the
-		 * results).  Note that we depend on the HAL leaving this
-		 * pointer for us to use below in reclaiming the buffer;
-		 * may want to be more defensive.
-		 */
-		outdata = malloc(outsize, M_TEMP, M_NOWAIT);
-		if (outdata == NULL) {
-			error = ENOMEM;
-			goto bad;
-		}
-	}
-
-
-	ATH_LOCK(sc);
-	if (id != HAL_DIAG_REGS)
-		ath_power_set_power_state(sc, HAL_PM_AWAKE);
-	ATH_UNLOCK(sc);
-
-	if (ath_hal_getdiagstate(ah, id, indata, insize, &outdata, &outsize)) {
-		if (outsize < ad->ad_out_size)
-			ad->ad_out_size = outsize;
-		if (outdata != NULL)
-			error = copyout(outdata, ad->ad_out_data,
-					ad->ad_out_size);
-	} else {
-		error = EINVAL;
-	}
-
-	ATH_LOCK(sc);
-	if (id != HAL_DIAG_REGS)
-		ath_power_restore_power_state(sc);
-	ATH_UNLOCK(sc);
-
-bad:
-	if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL)
-		free(indata, M_TEMP);
-	if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL)
-		free(outdata, M_TEMP);
-	return error;
-}
-#endif /* ATH_DIAGAPI */
-
 static void
 ath_parent(struct ieee80211com *ic)
 {
@@ -6578,73 +6152,6 @@ ath_parent(struct ieee80211com *ic)
 	}
 }
 
-static int
-ath_ioctl(struct ieee80211com *ic, u_long cmd, void *data)
-{
-	struct ifreq *ifr = data;
-	struct ath_softc *sc = ic->ic_softc;
-
-	switch (cmd) {
-	case SIOCGATHSTATS: {
-		struct ieee80211vap *vap;
-		struct ifnet *ifp;
-		const HAL_RATE_TABLE *rt;
-
-		/* NB: embed these numbers to get a consistent view */
-		sc->sc_stats.ast_tx_packets = 0;
-		sc->sc_stats.ast_rx_packets = 0;
-		TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
-			ifp = vap->iv_ifp;
-			sc->sc_stats.ast_tx_packets += ifp->if_get_counter(ifp,
-			    IFCOUNTER_OPACKETS);
-			sc->sc_stats.ast_rx_packets += ifp->if_get_counter(ifp,
-			    IFCOUNTER_IPACKETS);
-		}
-		sc->sc_stats.ast_tx_rssi = ATH_RSSI(sc->sc_halstats.ns_avgtxrssi);
-		sc->sc_stats.ast_rx_rssi = ATH_RSSI(sc->sc_halstats.ns_avgrssi);
-#ifdef IEEE80211_SUPPORT_TDMA
-		sc->sc_stats.ast_tdma_tsfadjp = TDMA_AVG(sc->sc_avgtsfdeltap);
-		sc->sc_stats.ast_tdma_tsfadjm = TDMA_AVG(sc->sc_avgtsfdeltam);
-#endif
-		rt = sc->sc_currates;
-		sc->sc_stats.ast_tx_rate =
-		    rt->info[sc->sc_txrix].dot11Rate &~ IEEE80211_RATE_BASIC;
-		if (rt->info[sc->sc_txrix].phy & IEEE80211_T_HT)
-			sc->sc_stats.ast_tx_rate |= IEEE80211_RATE_MCS;
-		return copyout(&sc->sc_stats,
-		    ifr->ifr_data, sizeof (sc->sc_stats));
-	}
-	case SIOCGATHAGSTATS:
-		return copyout(&sc->sc_aggr_stats,
-		    ifr->ifr_data, sizeof (sc->sc_aggr_stats));
-	case SIOCZATHSTATS: {
-		int error;
-
-		error = priv_check(curthread, PRIV_DRIVER);
-		if (error == 0) {
-			memset(&sc->sc_stats, 0, sizeof(sc->sc_stats));
-			memset(&sc->sc_aggr_stats, 0,
-			    sizeof(sc->sc_aggr_stats));
-			memset(&sc->sc_intr_stats, 0,
-			    sizeof(sc->sc_intr_stats));
-		}
-		return (error);
-	}
-#ifdef ATH_DIAGAPI
-	case SIOCGATHDIAG:
-		return (ath_ioctl_diag(sc, data));
-	case SIOCGATHPHYERR:
-		return (ath_ioctl_phyerr(sc, data));
-#endif
-	case SIOCGATHSPECTRAL:
-		return (ath_ioctl_spectral(sc, data));
-	case SIOCGATHNODERATESTATS:
-		return (ath_ioctl_ratestats(sc, data));
-	default:
-		return (ENOTTY);
-	}
-}
-
 /*
  * Announce various information on device/driver attach.
  */

Added: head/sys/dev/ath/if_ath_descdma.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/ath/if_ath_descdma.c	Tue Nov 24 03:42:58 2015	(r291233)
@@ -0,0 +1,442 @@
+/*-
+ * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Driver for the Atheros Wireless LAN controller.
+ *
+ * This software is derived from work of Atsushi Onoe; his contribution
+ * is greatly appreciated.
+ */
+
+#include "opt_inet.h"
+#include "opt_ath.h"
+/*
+ * This is needed for register operations which are performed
+ * by the driver - eg, calls to ath_hal_gettsf32().
+ *
+ * It's also required for any AH_DEBUG checks in here, eg the
+ * module dependencies.
+ */
+#include "opt_ah.h"
+#include "opt_wlan.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/errno.h>
+#include <sys/callout.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/kthread.h>
+#include <sys/taskqueue.h>
+#include <sys/priv.h>
+#include <sys/module.h>
+#include <sys/ktr.h>
+#include <sys/smp.h>	/* for mp_ncpus */
+
+#include <machine/bus.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_llc.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_regdomain.h>
+#ifdef IEEE80211_SUPPORT_SUPERG
+#include <net80211/ieee80211_superg.h>
+#endif
+#ifdef IEEE80211_SUPPORT_TDMA
+#include <net80211/ieee80211_tdma.h>
+#endif
+
+#include <net/bpf.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include <dev/ath/if_athvar.h>
+#include <dev/ath/ath_hal/ah_devid.h>		/* XXX for softled */
+#include <dev/ath/ath_hal/ah_diagcodes.h>
+
+#include <dev/ath/if_ath_debug.h>
+#include <dev/ath/if_ath_misc.h>
+#if 0
+#include <dev/ath/if_ath_tsf.h>
+#include <dev/ath/if_ath_tx.h>
+#include <dev/ath/if_ath_sysctl.h>
+#include <dev/ath/if_ath_led.h>
+#include <dev/ath/if_ath_keycache.h>
+#include <dev/ath/if_ath_rx.h>
+#include <dev/ath/if_ath_rx_edma.h>
+#include <dev/ath/if_ath_tx_edma.h>
+#include <dev/ath/if_ath_beacon.h>
+#include <dev/ath/if_ath_btcoex.h>
+#include <dev/ath/if_ath_spectral.h>
+#include <dev/ath/if_ath_lna_div.h>
+#include <dev/ath/if_athdfs.h>
+#endif
+#include <dev/ath/if_ath_descdma.h>
+
+MALLOC_DECLARE(M_ATHDEV);
+
+/*
+ * This is the descriptor setup / busdma memory intialisation and
+ * teardown routines.
+ */
+
+static void
+ath_load_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+	bus_addr_t *paddr = (bus_addr_t*) arg;
+	KASSERT(error == 0, ("error %u on bus_dma callback", error));
+	*paddr = segs->ds_addr;
+}
+
+/*
+ * Allocate the descriptors and appropriate DMA tag/setup.
+ *
+ * For some situations (eg EDMA TX completion), there isn't a requirement
+ * for the ath_buf entries to be allocated.
+ */
+int
+ath_descdma_alloc_desc(struct ath_softc *sc,
+	struct ath_descdma *dd, ath_bufhead *head,
+	const char *name, int ds_size, int ndesc)
+{
+#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)
+	int error;
+
+	dd->dd_descsize = ds_size;
+
+	DPRINTF(sc, ATH_DEBUG_RESET,
+	    "%s: %s DMA: %u desc, %d bytes per descriptor\n",
+	    __func__, name, ndesc, dd->dd_descsize);
+
+	dd->dd_name = name;
+	dd->dd_desc_len = dd->dd_descsize * ndesc;
+
+	/*
+	 * 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 numpages = dd->dd_desc_len / 4096;
+		dd->dd_desc_len += ds_size * numpages;
+	}
+
+	/*
+	 * Setup DMA descriptor area.
+	 *
+	 * BUS_DMA_ALLOCNOW is not used; we never use bounce
+	 * buffers for the descriptors themselves.
+	 */
+	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev),	/* parent */
+		       PAGE_SIZE, 0,		/* alignment, bounds */
+		       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
+		       BUS_SPACE_MAXADDR,	/* highaddr */
+		       NULL, NULL,		/* filter, filterarg */
+		       dd->dd_desc_len,		/* maxsize */
+		       1,			/* nsegments */
+		       dd->dd_desc_len,		/* maxsegsize */
+		       0,			/* flags */
+		       NULL,			/* lockfunc */
+		       NULL,			/* lockarg */
+		       &dd->dd_dmat);
+	if (error != 0) {
+		device_printf(sc->sc_dev,
+		    "cannot allocate %s DMA tag\n", dd->dd_name);
+		return error;
+	}
+
+	/* allocate descriptors */
+	error = bus_dmamem_alloc(dd->dd_dmat, (void**) &dd->dd_desc,
+				 BUS_DMA_NOWAIT | BUS_DMA_COHERENT,
+				 &dd->dd_dmamap);
+	if (error != 0) {
+		device_printf(sc->sc_dev,
+		    "unable to alloc memory for %u %s descriptors, error %u\n",
+		    ndesc, dd->dd_name, error);
+		goto fail1;
+	}
+
+	error = bus_dmamap_load(dd->dd_dmat, dd->dd_dmamap,
+				dd->dd_desc, dd->dd_desc_len,
+				ath_load_cb, &dd->dd_desc_paddr,
+				BUS_DMA_NOWAIT);
+	if (error != 0) {
+		device_printf(sc->sc_dev,
+		    "unable to map %s descriptors, error %u\n",
+		    dd->dd_name, error);
+		goto fail2;
+	}
+
+	DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA map: %p (%lu) -> %p (%lu)\n",
+	    __func__, dd->dd_name, (uint8_t *) dd->dd_desc,
+	    (u_long) dd->dd_desc_len, (caddr_t) dd->dd_desc_paddr,
+	    /*XXX*/ (u_long) dd->dd_desc_len);
+
+	return (0);
+
+fail2:
+	bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap);
+fail1:
+	bus_dma_tag_destroy(dd->dd_dmat);
+	memset(dd, 0, sizeof(*dd));
+	return error;
+#undef DS2PHYS
+#undef ATH_DESC_4KB_BOUND_CHECK
+}
+
+int
+ath_descdma_setup(struct ath_softc *sc,
+	struct ath_descdma *dd, ath_bufhead *head,
+	const char *name, int ds_size, int nbuf, int ndesc)
+{
+#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)
+	uint8_t *ds;
+	struct ath_buf *bf;
+	int i, bsize, error;
+
+	/* Allocate descriptors */
+	error = ath_descdma_alloc_desc(sc, dd, head, name, ds_size,
+	    nbuf * ndesc);
+
+	/* Assume any errors during allocation were dealt with */
+	if (error != 0) {
+		return (error);
+	}
+
+	ds = (uint8_t *) dd->dd_desc;
+
+	/* allocate rx buffers */
+	bsize = sizeof(struct ath_buf) * nbuf;
+	bf = malloc(bsize, M_ATHDEV, M_NOWAIT | M_ZERO);
+	if (bf == NULL) {
+		device_printf(sc->sc_dev,
+		    "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++, ds += (ndesc * dd->dd_descsize)) {
+		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,
+			     dd->dd_descsize)) {
+				/* 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) {
+			device_printf(sc->sc_dev, "unable to create dmamap "
+			    "for %s buffer %u, error %u\n",
+			    dd->dd_name, i, error);
+			ath_descdma_cleanup(sc, dd, head);
+			return error;
+		}
+		bf->bf_lastds = bf->bf_desc;	/* Just an initial value */
+		TAILQ_INSERT_TAIL(head, bf, bf_list);
+	}
+
+	/*
+	 * XXX TODO: ensure that ds doesn't overflow the descriptor
+	 * allocation otherwise weird stuff will occur and crash your
+	 * machine.
+	 */
+	return 0;
+	/* XXX this should likely just call ath_descdma_cleanup() */
+fail3:
+	bus_dmamap_unload(dd->dd_dmat, dd->dd_dmamap);
+	bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap);
+	bus_dma_tag_destroy(dd->dd_dmat);
+	memset(dd, 0, sizeof(*dd));
+	return error;
+#undef DS2PHYS
+#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 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 * nbuf;
+	dd->dd_descsize = rx_status_len;
+
+	/* allocate rx buffers */
+	bsize = sizeof(struct ath_buf) * nbuf;
+	bf = malloc(bsize, M_ATHDEV, M_NOWAIT | M_ZERO);
+	if (bf == NULL) {
+		device_printf(sc->sc_dev,
+		    "malloc of %s buffers failed, size %u\n",
+		    dd->dd_name, bsize);
+		error = ENOMEM;
+		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) {
+			device_printf(sc->sc_dev, "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
+ath_descdma_cleanup(struct ath_softc *sc,
+	struct ath_descdma *dd, ath_bufhead *head)
+{
+	struct ath_buf *bf;
+	struct ieee80211_node *ni;
+	int do_warning = 0;
+
+	if (dd->dd_dmamap != 0) {
+		bus_dmamap_unload(dd->dd_dmat, dd->dd_dmamap);
+		bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap);
+		bus_dma_tag_destroy(dd->dd_dmat);
+	}
+
+	if (head != NULL) {
+		TAILQ_FOREACH(bf, head, bf_list) {
+			if (bf->bf_m) {
+				/*
+				 * XXX warn if there's buffers here.
+				 * XXX it should have been freed by the
+				 * owner!
+				 */
+				
+				if (do_warning == 0) {
+					do_warning = 1;
+					device_printf(sc->sc_dev,
+					    "%s: %s: mbuf should've been"
+					    " unmapped/freed!\n",
+					    __func__,
+					    dd->dd_name);
+				}
+				bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
+				    BUS_DMASYNC_POSTREAD);
+				bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+				m_freem(bf->bf_m);
+				bf->bf_m = NULL;
+			}
+			if (bf->bf_dmamap != NULL) {
+				bus_dmamap_destroy(sc->sc_dmat, bf->bf_dmamap);
+				bf->bf_dmamap = NULL;
+			}
+			ni = bf->bf_node;
+			bf->bf_node = NULL;
+			if (ni != NULL) {
+				/*
+				 * Reclaim node reference.
+				 */
+				ieee80211_free_node(ni);
+			}
+		}
+	}
+
+	if (head != NULL)
+		TAILQ_INIT(head);
+
+	if (dd->dd_bufptr != NULL)
+		free(dd->dd_bufptr, M_ATHDEV);
+	memset(dd, 0, sizeof(*dd));
+}

Added: head/sys/dev/ath/if_ath_descdma.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/ath/if_ath_descdma.h	Tue Nov 24 03:42:58 2015	(r291233)
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2015 Adrian Chadd <adrian@FreeBSD.org>
+ * All rights reserved.

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201511240342.tAO3gw4w036329>