The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ath/if_ath_descdma.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer,
   10  *    without modification.
   11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
   12  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
   13  *    redistribution must be conditioned upon including a substantially
   14  *    similar Disclaimer requirement for further binary redistribution.
   15  *
   16  * NO WARRANTY
   17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   19  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
   20  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
   21  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
   22  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
   25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   27  * THE POSSIBILITY OF SUCH DAMAGES.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD: releng/11.2/sys/dev/ath/if_ath_descdma.c 291233 2015-11-24 03:42:58Z adrian $");
   32 
   33 /*
   34  * Driver for the Atheros Wireless LAN controller.
   35  *
   36  * This software is derived from work of Atsushi Onoe; his contribution
   37  * is greatly appreciated.
   38  */
   39 
   40 #include "opt_inet.h"
   41 #include "opt_ath.h"
   42 /*
   43  * This is needed for register operations which are performed
   44  * by the driver - eg, calls to ath_hal_gettsf32().
   45  *
   46  * It's also required for any AH_DEBUG checks in here, eg the
   47  * module dependencies.
   48  */
   49 #include "opt_ah.h"
   50 #include "opt_wlan.h"
   51 
   52 #include <sys/param.h>
   53 #include <sys/systm.h>
   54 #include <sys/sysctl.h>
   55 #include <sys/mbuf.h>
   56 #include <sys/malloc.h>
   57 #include <sys/lock.h>
   58 #include <sys/mutex.h>
   59 #include <sys/kernel.h>
   60 #include <sys/socket.h>
   61 #include <sys/sockio.h>
   62 #include <sys/errno.h>
   63 #include <sys/callout.h>
   64 #include <sys/bus.h>
   65 #include <sys/endian.h>
   66 #include <sys/kthread.h>
   67 #include <sys/taskqueue.h>
   68 #include <sys/priv.h>
   69 #include <sys/module.h>
   70 #include <sys/ktr.h>
   71 #include <sys/smp.h>    /* for mp_ncpus */
   72 
   73 #include <machine/bus.h>
   74 
   75 #include <net/if.h>
   76 #include <net/if_var.h>
   77 #include <net/if_dl.h>
   78 #include <net/if_media.h>
   79 #include <net/if_types.h>
   80 #include <net/if_arp.h>
   81 #include <net/ethernet.h>
   82 #include <net/if_llc.h>
   83 
   84 #include <net80211/ieee80211_var.h>
   85 #include <net80211/ieee80211_regdomain.h>
   86 #ifdef IEEE80211_SUPPORT_SUPERG
   87 #include <net80211/ieee80211_superg.h>
   88 #endif
   89 #ifdef IEEE80211_SUPPORT_TDMA
   90 #include <net80211/ieee80211_tdma.h>
   91 #endif
   92 
   93 #include <net/bpf.h>
   94 
   95 #ifdef INET
   96 #include <netinet/in.h>
   97 #include <netinet/if_ether.h>
   98 #endif
   99 
  100 #include <dev/ath/if_athvar.h>
  101 #include <dev/ath/ath_hal/ah_devid.h>           /* XXX for softled */
  102 #include <dev/ath/ath_hal/ah_diagcodes.h>
  103 
  104 #include <dev/ath/if_ath_debug.h>
  105 #include <dev/ath/if_ath_misc.h>
  106 #if 0
  107 #include <dev/ath/if_ath_tsf.h>
  108 #include <dev/ath/if_ath_tx.h>
  109 #include <dev/ath/if_ath_sysctl.h>
  110 #include <dev/ath/if_ath_led.h>
  111 #include <dev/ath/if_ath_keycache.h>
  112 #include <dev/ath/if_ath_rx.h>
  113 #include <dev/ath/if_ath_rx_edma.h>
  114 #include <dev/ath/if_ath_tx_edma.h>
  115 #include <dev/ath/if_ath_beacon.h>
  116 #include <dev/ath/if_ath_btcoex.h>
  117 #include <dev/ath/if_ath_spectral.h>
  118 #include <dev/ath/if_ath_lna_div.h>
  119 #include <dev/ath/if_athdfs.h>
  120 #endif
  121 #include <dev/ath/if_ath_descdma.h>
  122 
  123 MALLOC_DECLARE(M_ATHDEV);
  124 
  125 /*
  126  * This is the descriptor setup / busdma memory intialisation and
  127  * teardown routines.
  128  */
  129 
  130 static void
  131 ath_load_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
  132 {
  133         bus_addr_t *paddr = (bus_addr_t*) arg;
  134         KASSERT(error == 0, ("error %u on bus_dma callback", error));
  135         *paddr = segs->ds_addr;
  136 }
  137 
  138 /*
  139  * Allocate the descriptors and appropriate DMA tag/setup.
  140  *
  141  * For some situations (eg EDMA TX completion), there isn't a requirement
  142  * for the ath_buf entries to be allocated.
  143  */
  144 int
  145 ath_descdma_alloc_desc(struct ath_softc *sc,
  146         struct ath_descdma *dd, ath_bufhead *head,
  147         const char *name, int ds_size, int ndesc)
  148 {
  149 #define DS2PHYS(_dd, _ds) \
  150         ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
  151 #define ATH_DESC_4KB_BOUND_CHECK(_daddr, _len) \
  152         ((((u_int32_t)(_daddr) & 0xFFF) > (0x1000 - (_len))) ? 1 : 0)
  153         int error;
  154 
  155         dd->dd_descsize = ds_size;
  156 
  157         DPRINTF(sc, ATH_DEBUG_RESET,
  158             "%s: %s DMA: %u desc, %d bytes per descriptor\n",
  159             __func__, name, ndesc, dd->dd_descsize);
  160 
  161         dd->dd_name = name;
  162         dd->dd_desc_len = dd->dd_descsize * ndesc;
  163 
  164         /*
  165          * Merlin work-around:
  166          * Descriptors that cross the 4KB boundary can't be used.
  167          * Assume one skipped descriptor per 4KB page.
  168          */
  169         if (! ath_hal_split4ktrans(sc->sc_ah)) {
  170                 int numpages = dd->dd_desc_len / 4096;
  171                 dd->dd_desc_len += ds_size * numpages;
  172         }
  173 
  174         /*
  175          * Setup DMA descriptor area.
  176          *
  177          * BUS_DMA_ALLOCNOW is not used; we never use bounce
  178          * buffers for the descriptors themselves.
  179          */
  180         error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), /* parent */
  181                        PAGE_SIZE, 0,            /* alignment, bounds */
  182                        BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
  183                        BUS_SPACE_MAXADDR,       /* highaddr */
  184                        NULL, NULL,              /* filter, filterarg */
  185                        dd->dd_desc_len,         /* maxsize */
  186                        1,                       /* nsegments */
  187                        dd->dd_desc_len,         /* maxsegsize */
  188                        0,                       /* flags */
  189                        NULL,                    /* lockfunc */
  190                        NULL,                    /* lockarg */
  191                        &dd->dd_dmat);
  192         if (error != 0) {
  193                 device_printf(sc->sc_dev,
  194                     "cannot allocate %s DMA tag\n", dd->dd_name);
  195                 return error;
  196         }
  197 
  198         /* allocate descriptors */
  199         error = bus_dmamem_alloc(dd->dd_dmat, (void**) &dd->dd_desc,
  200                                  BUS_DMA_NOWAIT | BUS_DMA_COHERENT,
  201                                  &dd->dd_dmamap);
  202         if (error != 0) {
  203                 device_printf(sc->sc_dev,
  204                     "unable to alloc memory for %u %s descriptors, error %u\n",
  205                     ndesc, dd->dd_name, error);
  206                 goto fail1;
  207         }
  208 
  209         error = bus_dmamap_load(dd->dd_dmat, dd->dd_dmamap,
  210                                 dd->dd_desc, dd->dd_desc_len,
  211                                 ath_load_cb, &dd->dd_desc_paddr,
  212                                 BUS_DMA_NOWAIT);
  213         if (error != 0) {
  214                 device_printf(sc->sc_dev,
  215                     "unable to map %s descriptors, error %u\n",
  216                     dd->dd_name, error);
  217                 goto fail2;
  218         }
  219 
  220         DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA map: %p (%lu) -> %p (%lu)\n",
  221             __func__, dd->dd_name, (uint8_t *) dd->dd_desc,
  222             (u_long) dd->dd_desc_len, (caddr_t) dd->dd_desc_paddr,
  223             /*XXX*/ (u_long) dd->dd_desc_len);
  224 
  225         return (0);
  226 
  227 fail2:
  228         bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap);
  229 fail1:
  230         bus_dma_tag_destroy(dd->dd_dmat);
  231         memset(dd, 0, sizeof(*dd));
  232         return error;
  233 #undef DS2PHYS
  234 #undef ATH_DESC_4KB_BOUND_CHECK
  235 }
  236 
  237 int
  238 ath_descdma_setup(struct ath_softc *sc,
  239         struct ath_descdma *dd, ath_bufhead *head,
  240         const char *name, int ds_size, int nbuf, int ndesc)
  241 {
  242 #define DS2PHYS(_dd, _ds) \
  243         ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
  244 #define ATH_DESC_4KB_BOUND_CHECK(_daddr, _len) \
  245         ((((u_int32_t)(_daddr) & 0xFFF) > (0x1000 - (_len))) ? 1 : 0)
  246         uint8_t *ds;
  247         struct ath_buf *bf;
  248         int i, bsize, error;
  249 
  250         /* Allocate descriptors */
  251         error = ath_descdma_alloc_desc(sc, dd, head, name, ds_size,
  252             nbuf * ndesc);
  253 
  254         /* Assume any errors during allocation were dealt with */
  255         if (error != 0) {
  256                 return (error);
  257         }
  258 
  259         ds = (uint8_t *) dd->dd_desc;
  260 
  261         /* allocate rx buffers */
  262         bsize = sizeof(struct ath_buf) * nbuf;
  263         bf = malloc(bsize, M_ATHDEV, M_NOWAIT | M_ZERO);
  264         if (bf == NULL) {
  265                 device_printf(sc->sc_dev,
  266                     "malloc of %s buffers failed, size %u\n",
  267                     dd->dd_name, bsize);
  268                 goto fail3;
  269         }
  270         dd->dd_bufptr = bf;
  271 
  272         TAILQ_INIT(head);
  273         for (i = 0; i < nbuf; i++, bf++, ds += (ndesc * dd->dd_descsize)) {
  274                 bf->bf_desc = (struct ath_desc *) ds;
  275                 bf->bf_daddr = DS2PHYS(dd, ds);
  276                 if (! ath_hal_split4ktrans(sc->sc_ah)) {
  277                         /*
  278                          * Merlin WAR: Skip descriptor addresses which
  279                          * cause 4KB boundary crossing along any point
  280                          * in the descriptor.
  281                          */
  282                          if (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr,
  283                              dd->dd_descsize)) {
  284                                 /* Start at the next page */
  285                                 ds += 0x1000 - (bf->bf_daddr & 0xFFF);
  286                                 bf->bf_desc = (struct ath_desc *) ds;
  287                                 bf->bf_daddr = DS2PHYS(dd, ds);
  288                         }
  289                 }
  290                 error = bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT,
  291                                 &bf->bf_dmamap);
  292                 if (error != 0) {
  293                         device_printf(sc->sc_dev, "unable to create dmamap "
  294                             "for %s buffer %u, error %u\n",
  295                             dd->dd_name, i, error);
  296                         ath_descdma_cleanup(sc, dd, head);
  297                         return error;
  298                 }
  299                 bf->bf_lastds = bf->bf_desc;    /* Just an initial value */
  300                 TAILQ_INSERT_TAIL(head, bf, bf_list);
  301         }
  302 
  303         /*
  304          * XXX TODO: ensure that ds doesn't overflow the descriptor
  305          * allocation otherwise weird stuff will occur and crash your
  306          * machine.
  307          */
  308         return 0;
  309         /* XXX this should likely just call ath_descdma_cleanup() */
  310 fail3:
  311         bus_dmamap_unload(dd->dd_dmat, dd->dd_dmamap);
  312         bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap);
  313         bus_dma_tag_destroy(dd->dd_dmat);
  314         memset(dd, 0, sizeof(*dd));
  315         return error;
  316 #undef DS2PHYS
  317 #undef ATH_DESC_4KB_BOUND_CHECK
  318 }
  319 
  320 /*
  321  * Allocate ath_buf entries but no descriptor contents.
  322  *
  323  * This is for RX EDMA where the descriptors are the header part of
  324  * the RX buffer.
  325  */
  326 int
  327 ath_descdma_setup_rx_edma(struct ath_softc *sc,
  328         struct ath_descdma *dd, ath_bufhead *head,
  329         const char *name, int nbuf, int rx_status_len)
  330 {
  331         struct ath_buf *bf;
  332         int i, bsize, error;
  333 
  334         DPRINTF(sc, ATH_DEBUG_RESET, "%s: %s DMA: %u buffers\n",
  335             __func__, name, nbuf);
  336 
  337         dd->dd_name = name;
  338         /*
  339          * This is (mostly) purely for show.  We're not allocating any actual
  340          * descriptors here as EDMA RX has the descriptor be part
  341          * of the RX buffer.
  342          *
  343          * However, dd_desc_len is used by ath_descdma_free() to determine
  344          * whether we have already freed this DMA mapping.
  345          */
  346         dd->dd_desc_len = rx_status_len * nbuf;
  347         dd->dd_descsize = rx_status_len;
  348 
  349         /* allocate rx buffers */
  350         bsize = sizeof(struct ath_buf) * nbuf;
  351         bf = malloc(bsize, M_ATHDEV, M_NOWAIT | M_ZERO);
  352         if (bf == NULL) {
  353                 device_printf(sc->sc_dev,
  354                     "malloc of %s buffers failed, size %u\n",
  355                     dd->dd_name, bsize);
  356                 error = ENOMEM;
  357                 goto fail3;
  358         }
  359         dd->dd_bufptr = bf;
  360 
  361         TAILQ_INIT(head);
  362         for (i = 0; i < nbuf; i++, bf++) {
  363                 bf->bf_desc = NULL;
  364                 bf->bf_daddr = 0;
  365                 bf->bf_lastds = NULL;   /* Just an initial value */
  366 
  367                 error = bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT,
  368                                 &bf->bf_dmamap);
  369                 if (error != 0) {
  370                         device_printf(sc->sc_dev, "unable to create dmamap "
  371                             "for %s buffer %u, error %u\n",
  372                             dd->dd_name, i, error);
  373                         ath_descdma_cleanup(sc, dd, head);
  374                         return error;
  375                 }
  376                 TAILQ_INSERT_TAIL(head, bf, bf_list);
  377         }
  378         return 0;
  379 fail3:
  380         memset(dd, 0, sizeof(*dd));
  381         return error;
  382 }
  383 
  384 void
  385 ath_descdma_cleanup(struct ath_softc *sc,
  386         struct ath_descdma *dd, ath_bufhead *head)
  387 {
  388         struct ath_buf *bf;
  389         struct ieee80211_node *ni;
  390         int do_warning = 0;
  391 
  392         if (dd->dd_dmamap != 0) {
  393                 bus_dmamap_unload(dd->dd_dmat, dd->dd_dmamap);
  394                 bus_dmamem_free(dd->dd_dmat, dd->dd_desc, dd->dd_dmamap);
  395                 bus_dma_tag_destroy(dd->dd_dmat);
  396         }
  397 
  398         if (head != NULL) {
  399                 TAILQ_FOREACH(bf, head, bf_list) {
  400                         if (bf->bf_m) {
  401                                 /*
  402                                  * XXX warn if there's buffers here.
  403                                  * XXX it should have been freed by the
  404                                  * owner!
  405                                  */
  406                                 
  407                                 if (do_warning == 0) {
  408                                         do_warning = 1;
  409                                         device_printf(sc->sc_dev,
  410                                             "%s: %s: mbuf should've been"
  411                                             " unmapped/freed!\n",
  412                                             __func__,
  413                                             dd->dd_name);
  414                                 }
  415                                 bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
  416                                     BUS_DMASYNC_POSTREAD);
  417                                 bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
  418                                 m_freem(bf->bf_m);
  419                                 bf->bf_m = NULL;
  420                         }
  421                         if (bf->bf_dmamap != NULL) {
  422                                 bus_dmamap_destroy(sc->sc_dmat, bf->bf_dmamap);
  423                                 bf->bf_dmamap = NULL;
  424                         }
  425                         ni = bf->bf_node;
  426                         bf->bf_node = NULL;
  427                         if (ni != NULL) {
  428                                 /*
  429                                  * Reclaim node reference.
  430                                  */
  431                                 ieee80211_free_node(ni);
  432                         }
  433                 }
  434         }
  435 
  436         if (head != NULL)
  437                 TAILQ_INIT(head);
  438 
  439         if (dd->dd_bufptr != NULL)
  440                 free(dd->dd_bufptr, M_ATHDEV);
  441         memset(dd, 0, sizeof(*dd));
  442 }

Cache object: 62d6b3332a238c7d9928c2d9a6125424


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.