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 <adr...@freebsd.org>
+ * All rights reserved.

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to