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/rtwn/pci/rtwn_pci_tx.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 /*      $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $     */
    2 
    3 /*-
    4  * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
    5  * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
    6  * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
    7  *
    8  * Permission to use, copy, modify, and distribute this software for any
    9  * purpose with or without fee is hereby granted, provided that the above
   10  * copyright notice and this permission notice appear in all copies.
   11  *
   12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   19  */
   20 
   21 #include <sys/cdefs.h>
   22 __FBSDID("$FreeBSD$");
   23 
   24 #include "opt_wlan.h"
   25 
   26 #include <sys/param.h>
   27 #include <sys/lock.h>
   28 #include <sys/mutex.h>
   29 #include <sys/mbuf.h>
   30 #include <sys/kernel.h>
   31 #include <sys/socket.h>
   32 #include <sys/systm.h>
   33 #include <sys/malloc.h>
   34 #include <sys/queue.h>
   35 #include <sys/taskqueue.h>
   36 #include <sys/bus.h>
   37 #include <sys/endian.h>
   38 
   39 #include <machine/bus.h>
   40 #include <machine/resource.h>
   41 #include <sys/rman.h>
   42 
   43 #include <net/if.h>
   44 #include <net/if_var.h>
   45 #include <net/ethernet.h>
   46 #include <net/if_media.h>
   47 
   48 #include <net80211/ieee80211_var.h>
   49 #include <net80211/ieee80211_radiotap.h>
   50 
   51 #include <dev/rtwn/if_rtwnreg.h>
   52 #include <dev/rtwn/if_rtwnvar.h>
   53 #include <dev/rtwn/if_rtwn_debug.h>
   54 
   55 #include <dev/rtwn/pci/rtwn_pci_var.h>
   56 #include <dev/rtwn/pci/rtwn_pci_tx.h>
   57 
   58 #include <dev/rtwn/rtl8192c/pci/r92ce_reg.h>
   59 
   60 static struct mbuf *
   61 rtwn_mbuf_defrag(struct mbuf *m0, int how)
   62 {
   63         struct mbuf *m = NULL;
   64 
   65         KASSERT(m0->m_flags & M_PKTHDR,
   66             ("M_PKTHDR flag is absent (m %p)!", m0));
   67 
   68         /* NB: we need _exactly_ one mbuf (no less, no more). */
   69         if (m0->m_pkthdr.len > MJUMPAGESIZE) {
   70                 /* XXX MJUM9BYTES? */
   71                 return (NULL);
   72         } else if (m0->m_pkthdr.len > MCLBYTES) {
   73                 m = m_getjcl(how, MT_DATA, M_PKTHDR, MJUMPAGESIZE);
   74                 if (m == NULL)
   75                         return (NULL);
   76 
   77                 if (m_dup_pkthdr(m, m0, how) == 0) {
   78                         m_freem(m);
   79                         return (NULL);
   80                 }
   81 
   82                 m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, caddr_t));
   83                 m->m_len = m->m_pkthdr.len;
   84                 m_freem(m0);
   85 
   86                 return (m);
   87         } else
   88                 return (m_defrag(m0, how));
   89 }
   90 
   91 static int
   92 rtwn_pci_tx_start_frame(struct rtwn_softc *sc, struct ieee80211_node *ni,
   93     struct mbuf *m, uint8_t *tx_desc, uint8_t type)
   94 {
   95         struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
   96         struct rtwn_tx_ring *ring;
   97         struct rtwn_tx_data *data;
   98         struct rtwn_tx_desc_common *txd;
   99         bus_dma_segment_t segs[1];
  100         uint8_t qid;
  101         int nsegs, error;
  102 
  103         RTWN_ASSERT_LOCKED(sc);
  104 
  105         switch (type) {
  106         case IEEE80211_FC0_TYPE_CTL:
  107         case IEEE80211_FC0_TYPE_MGT:
  108                 qid = RTWN_PCI_MGNT_QUEUE;
  109                 break;
  110         default:
  111                 qid = M_WME_GETAC(m);
  112                 break;
  113         }
  114 
  115         ring = &pc->tx_ring[qid];
  116         data = &ring->tx_data[ring->cur];
  117         if (data->m != NULL) {
  118                 RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT,
  119                     "%s: ring #%u is full (m %p)\n", __func__, qid, data->m);
  120                 return (ENOBUFS);
  121         }
  122 
  123         txd = (struct rtwn_tx_desc_common *)
  124             ((uint8_t *)ring->desc + sc->txdesc_len * ring->cur);
  125         if (txd->flags0 & RTWN_FLAGS0_OWN) {
  126                 device_printf(sc->sc_dev,
  127                     "%s: OWN bit is set (tx desc %d, ring %u)!\n",
  128                     __func__, ring->cur, qid);
  129                 return (ENOBUFS);
  130         }
  131 
  132         /* Copy Tx descriptor. */
  133         rtwn_pci_copy_tx_desc(pc, txd, tx_desc);
  134         txd->pktlen = htole16(m->m_pkthdr.len);
  135         txd->offset = sc->txdesc_len;
  136 
  137         error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, segs,
  138             &nsegs, BUS_DMA_NOWAIT);
  139         if (error != 0 && error != EFBIG) {
  140                 device_printf(sc->sc_dev, "can't map mbuf (error %d)\n",
  141                     error);
  142                 return (error);
  143         }
  144         if (error != 0) {
  145                 struct mbuf *mnew;
  146 
  147                 mnew = rtwn_mbuf_defrag(m, M_NOWAIT);
  148                 if (mnew == NULL) {
  149                         device_printf(sc->sc_dev, "can't defragment mbuf\n");
  150                         return (ENOBUFS);
  151                 }
  152                 m = mnew;
  153 
  154                 error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m,
  155                     segs, &nsegs, BUS_DMA_NOWAIT);
  156                 if (error != 0) {
  157                         device_printf(sc->sc_dev,
  158                             "can't map mbuf (error %d)\n", error);
  159                         if (ni != NULL) {
  160                                 if_inc_counter(ni->ni_vap->iv_ifp,
  161                                     IFCOUNTER_OERRORS, 1);
  162                                 ieee80211_free_node(ni);
  163                         }
  164                         m_freem(m);
  165                         return (0);     /* XXX */
  166                 }
  167         }
  168 
  169         rtwn_pci_tx_postsetup(pc, txd, segs);
  170         txd->flags0 |= RTWN_FLAGS0_OWN;
  171 
  172         /* Dump Tx descriptor. */
  173         rtwn_dump_tx_desc(sc, txd);
  174 
  175         bus_dmamap_sync(ring->desc_dmat, ring->desc_map,
  176             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
  177         bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREWRITE);
  178 
  179         data->m = m;
  180         data->ni = ni;
  181 
  182         ring->cur = (ring->cur + 1) % RTWN_PCI_TX_LIST_COUNT;
  183 
  184         ring->queued++;
  185         if (ring->queued >= (RTWN_PCI_TX_LIST_COUNT - 1))
  186                 sc->qfullmsk |= (1 << qid);
  187 
  188 #ifndef D4054
  189         sc->sc_tx_timer = 5;
  190 #endif
  191 
  192         /* Kick TX. */
  193         rtwn_write_2(sc, R92C_PCIE_CTRL_REG, (1 << qid));
  194 
  195         return (0);
  196 }
  197 
  198 static int
  199 rtwn_pci_tx_start_beacon(struct rtwn_softc *sc, struct mbuf *m,
  200     uint8_t *tx_desc, int id)
  201 {
  202         struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
  203         struct rtwn_tx_ring *ring;
  204         struct rtwn_tx_data *data;
  205         struct rtwn_tx_desc_common *txd;
  206         bus_dma_segment_t segs[1];
  207         int nsegs, error, own;
  208 
  209         RTWN_ASSERT_LOCKED(sc);
  210 
  211         KASSERT(id == 0 || id == 1, ("bogus vap id %d\n", id));
  212 
  213         ring = &pc->tx_ring[RTWN_PCI_BEACON_QUEUE];
  214         data = &ring->tx_data[id];
  215         txd = (struct rtwn_tx_desc_common *)
  216             ((uint8_t *)ring->desc + id * sc->txdesc_len);
  217 
  218         bus_dmamap_sync(ring->desc_dmat, ring->desc_map,
  219             BUS_DMASYNC_POSTREAD);
  220         own = !!(txd->flags0 & RTWN_FLAGS0_OWN);
  221         error = 0;
  222         if (!own || txd->pktlen != htole16(m->m_pkthdr.len)) {
  223                 if (!own) {
  224                         /* Copy Tx descriptor. */
  225                         rtwn_pci_copy_tx_desc(pc, txd, tx_desc);
  226                         txd->offset = sc->txdesc_len;
  227                 } else {
  228                         /* Reload mbuf. */
  229                         bus_dmamap_unload(ring->data_dmat, data->map);
  230                 }
  231 
  232                 error = bus_dmamap_load_mbuf_sg(ring->data_dmat,
  233                     data->map, m, segs, &nsegs, BUS_DMA_NOWAIT);
  234                 if (error != 0) {
  235                         device_printf(sc->sc_dev,
  236                             "can't map beacon (error %d)\n", error);
  237                         txd->flags0 &= ~RTWN_FLAGS0_OWN;
  238                         goto end;
  239                 }
  240 
  241                 txd->pktlen = htole16(m->m_pkthdr.len);
  242                 rtwn_pci_tx_postsetup(pc, txd, segs);
  243                 txd->flags0 |= RTWN_FLAGS0_OWN;
  244 end:
  245                 bus_dmamap_sync(ring->desc_dmat, ring->desc_map,
  246                     BUS_DMASYNC_PREWRITE);
  247         }
  248 
  249         /* Dump Tx descriptor. */
  250         rtwn_dump_tx_desc(sc, txd);
  251 
  252         bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREWRITE);
  253 
  254         return (0);
  255 }
  256 
  257 int
  258 rtwn_pci_tx_start(struct rtwn_softc *sc, struct ieee80211_node *ni,
  259     struct mbuf *m, uint8_t *tx_desc, uint8_t type, int id)
  260 {
  261         int error = 0;
  262 
  263         RTWN_ASSERT_LOCKED(sc);
  264 
  265         if (ni == NULL)         /* beacon frame */
  266                 error = rtwn_pci_tx_start_beacon(sc, m, tx_desc, id);
  267         else
  268                 error = rtwn_pci_tx_start_frame(sc, ni, m, tx_desc, type);
  269 
  270         return (error);
  271 }

Cache object: 9e95189bac076eda27e303953cb2ba65


[ 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.