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/rtl8812a/r12a_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 /*-
    2  * Copyright (c) 2016 Andriy Voskoboinyk <avos@FreeBSD.org>
    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  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include "opt_wlan.h"
   31 
   32 #include <sys/param.h>
   33 #include <sys/lock.h>
   34 #include <sys/mutex.h>
   35 #include <sys/mbuf.h>
   36 #include <sys/kernel.h>
   37 #include <sys/socket.h>
   38 #include <sys/systm.h>
   39 #include <sys/malloc.h>
   40 #include <sys/queue.h>
   41 #include <sys/taskqueue.h>
   42 #include <sys/bus.h>
   43 #include <sys/endian.h>
   44 #include <sys/linker.h>
   45 
   46 #include <net/if.h>
   47 #include <net/ethernet.h>
   48 #include <net/if_media.h>
   49 
   50 #include <net80211/ieee80211_var.h>
   51 #include <net80211/ieee80211_radiotap.h>
   52 
   53 #include <dev/rtwn/if_rtwnreg.h>
   54 #include <dev/rtwn/if_rtwnvar.h>
   55 
   56 #include <dev/rtwn/if_rtwn_ridx.h>
   57 
   58 #include <dev/rtwn/rtl8812a/r12a.h>
   59 #include <dev/rtwn/rtl8812a/r12a_tx_desc.h>
   60 
   61 static int
   62 r12a_get_primary_channel(struct rtwn_softc *sc, struct ieee80211_channel *c)
   63 {
   64         /* XXX 80 MHz */
   65         if (IEEE80211_IS_CHAN_HT40U(c))
   66                 return (R12A_TXDW5_PRIM_CHAN_20_80_2);
   67         else
   68                 return (R12A_TXDW5_PRIM_CHAN_20_80_3);
   69 }
   70 
   71 static void
   72 r12a_tx_set_ht40(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni)
   73 {
   74         struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf;
   75 
   76         /* XXX 80 Mhz */
   77         if (ni->ni_chan != IEEE80211_CHAN_ANYC &&
   78             IEEE80211_IS_CHAN_HT40(ni->ni_chan)) {
   79                 int prim_chan;
   80 
   81                 prim_chan = r12a_get_primary_channel(sc, ni->ni_chan);
   82                 txd->txdw5 |= htole32(SM(R12A_TXDW5_DATA_BW,
   83                     R12A_TXDW5_DATA_BW40));
   84                 txd->txdw5 |= htole32(SM(R12A_TXDW5_DATA_PRIM_CHAN,
   85                     prim_chan));
   86         }
   87 }
   88 
   89 static void
   90 r12a_tx_protection(struct rtwn_softc *sc, struct r12a_tx_desc *txd,
   91     enum ieee80211_protmode mode, uint8_t ridx)
   92 {
   93         struct ieee80211com *ic = &sc->sc_ic;
   94         uint8_t rate;
   95 
   96         switch (mode) {
   97         case IEEE80211_PROT_CTSONLY:
   98                 txd->txdw3 |= htole32(R12A_TXDW3_CTS2SELF);
   99                 break;
  100         case IEEE80211_PROT_RTSCTS:
  101                 txd->txdw3 |= htole32(R12A_TXDW3_RTSEN);
  102                 break;
  103         default:
  104                 break;
  105         }
  106 
  107         if (mode == IEEE80211_PROT_CTSONLY ||
  108             mode == IEEE80211_PROT_RTSCTS) {
  109                 if (ridx >= RTWN_RIDX_HT_MCS(0))
  110                         rate = rtwn_ctl_mcsrate(ic->ic_rt, ridx);
  111                 else
  112                         rate = ieee80211_ctl_rate(ic->ic_rt, ridx2rate[ridx]);
  113                 ridx = rate2ridx(IEEE80211_RV(rate));
  114 
  115                 txd->txdw4 |= htole32(SM(R12A_TXDW4_RTSRATE, ridx));
  116                 /* RTS rate fallback limit (max). */
  117                 txd->txdw4 |= htole32(SM(R12A_TXDW4_RTSRATE_FB_LMT, 0xf));
  118 
  119                 if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 &&
  120                     (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
  121                         txd->txdw5 |= htole32(R12A_TXDW5_RTS_SHORT);
  122         }
  123 }
  124 
  125 static void
  126 r12a_tx_raid(struct rtwn_softc *sc, struct r12a_tx_desc *txd,
  127     struct ieee80211_node *ni, int ismcast)
  128 {
  129         struct ieee80211com *ic = &sc->sc_ic;
  130         struct ieee80211vap *vap = ni->ni_vap;
  131         struct ieee80211_channel *chan;
  132         enum ieee80211_phymode mode;
  133         uint8_t raid;
  134 
  135         chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ?
  136                 ni->ni_chan : ic->ic_curchan;
  137         mode = ieee80211_chan2mode(chan);
  138 
  139         /* NB: group addressed frames are done at 11bg rates for now */
  140         if (ismcast || !(ni->ni_flags & IEEE80211_NODE_HT)) {
  141                 switch (mode) {
  142                 case IEEE80211_MODE_11A:
  143                 case IEEE80211_MODE_11B:
  144                 case IEEE80211_MODE_11G:
  145                         break;
  146                 case IEEE80211_MODE_11NA:
  147                         mode = IEEE80211_MODE_11A;
  148                         break;
  149                 case IEEE80211_MODE_11NG:
  150                         mode = IEEE80211_MODE_11G;
  151                         break;
  152                 default:
  153                         device_printf(sc->sc_dev, "unknown mode(1) %d!\n",
  154                             ic->ic_curmode);
  155                         return;
  156                 }
  157         }
  158 
  159         switch (mode) {
  160         case IEEE80211_MODE_11A:
  161                 raid = R12A_RAID_11G;
  162                 break;
  163         case IEEE80211_MODE_11B:
  164                 raid = R12A_RAID_11B;
  165                 break;
  166         case IEEE80211_MODE_11G:
  167                 if (vap->iv_flags & IEEE80211_F_PUREG)
  168                         raid = R12A_RAID_11G;
  169                 else
  170                         raid = R12A_RAID_11BG;
  171                 break;
  172         case IEEE80211_MODE_11NA:
  173                 if (sc->ntxchains == 1)
  174                         raid = R12A_RAID_11GN_1;
  175                 else
  176                         raid = R12A_RAID_11GN_2;
  177                 break;
  178         case IEEE80211_MODE_11NG:
  179                 if (sc->ntxchains == 1) {
  180                         if (IEEE80211_IS_CHAN_HT40(chan))
  181                                 raid = R12A_RAID_11BGN_1_40;
  182                         else
  183                                 raid = R12A_RAID_11BGN_1;
  184                 } else {
  185                         if (IEEE80211_IS_CHAN_HT40(chan))
  186                                 raid = R12A_RAID_11BGN_2_40;
  187                         else
  188                                 raid = R12A_RAID_11BGN_2;
  189                 }
  190                 break;
  191         default:
  192                 /* TODO: 80 MHz / 11ac */
  193                 device_printf(sc->sc_dev, "unknown mode(2) %d!\n", mode);
  194                 return;
  195         }
  196 
  197         txd->txdw1 |= htole32(SM(R12A_TXDW1_RAID, raid));
  198 }
  199 
  200 static void
  201 r12a_tx_set_sgi(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni)
  202 {
  203         struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf;
  204         struct ieee80211vap *vap = ni->ni_vap;
  205 
  206         if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) &&     /* HT20 */
  207             (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20))
  208                 txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT);
  209         else if (ni->ni_chan != IEEE80211_CHAN_ANYC &&          /* HT40 */
  210             IEEE80211_IS_CHAN_HT40(ni->ni_chan) &&
  211             (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) &&
  212             (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40))
  213                 txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT);
  214 }
  215 
  216 static void
  217 r12a_tx_set_ldpc(struct rtwn_softc *sc, struct r12a_tx_desc *txd,
  218     struct ieee80211_node *ni)
  219 {
  220         struct ieee80211vap *vap = ni->ni_vap;
  221 
  222         if ((vap->iv_flags_ht & IEEE80211_FHT_LDPC_TX) &&
  223             (ni->ni_htcap & IEEE80211_HTCAP_LDPC))
  224                 txd->txdw5 |= htole32(R12A_TXDW5_DATA_LDPC);
  225 }
  226 
  227 void
  228 r12a_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni,
  229     struct mbuf *m, void *buf, uint8_t ridx, int maxretry)
  230 {
  231         struct ieee80211com *ic = &sc->sc_ic;
  232         struct ieee80211vap *vap = ni->ni_vap;
  233         struct rtwn_vap *uvp = RTWN_VAP(vap);
  234         struct ieee80211_frame *wh;
  235         struct r12a_tx_desc *txd;
  236         enum ieee80211_protmode prot;
  237         uint8_t type, tid, qos, qsel;
  238         int hasqos, ismcast, macid;
  239 
  240         wh = mtod(m, struct ieee80211_frame *);
  241         type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
  242         hasqos = IEEE80211_QOS_HAS_SEQ(wh);
  243         ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
  244 
  245         /* Select TX ring for this frame. */
  246         if (hasqos) {
  247                 qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0];
  248                 tid = qos & IEEE80211_QOS_TID;
  249         } else {
  250                 qos = 0;
  251                 tid = 0;
  252         }
  253 
  254         /* Fill Tx descriptor. */
  255         txd = (struct r12a_tx_desc *)buf;
  256         txd->flags0 |= R12A_FLAGS0_LSG | R12A_FLAGS0_FSG;
  257         if (ismcast)
  258                 txd->flags0 |= R12A_FLAGS0_BMCAST;
  259 
  260         if (!ismcast) {
  261                 /* Unicast frame, check if an ACK is expected. */
  262                 if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) !=
  263                     IEEE80211_QOS_ACKPOLICY_NOACK) {
  264                         txd->txdw4 = htole32(R12A_TXDW4_RETRY_LMT_ENA);
  265                         txd->txdw4 |= htole32(SM(R12A_TXDW4_RETRY_LMT,
  266                             maxretry));
  267                 }
  268 
  269                 struct rtwn_node *un = RTWN_NODE(ni);
  270                 macid = un->id;
  271 
  272                 if (type == IEEE80211_FC0_TYPE_DATA) {
  273                         qsel = tid % RTWN_MAX_TID;
  274 
  275                         if (m->m_flags & M_AMPDU_MPDU) {
  276                                 txd->txdw2 |= htole32(R12A_TXDW2_AGGEN);
  277                                 txd->txdw2 |= htole32(SM(R12A_TXDW2_AMPDU_DEN,
  278                                     vap->iv_ampdu_density));
  279                                 txd->txdw3 |= htole32(SM(R12A_TXDW3_MAX_AGG,
  280                                     0x1f));     /* XXX */
  281                         } else
  282                                 txd->txdw2 |= htole32(R12A_TXDW2_AGGBK);
  283 
  284                         if (sc->sc_ratectl == RTWN_RATECTL_NET80211) {
  285                                 txd->txdw2 |= htole32(R12A_TXDW2_SPE_RPT);
  286                                 sc->sc_tx_n_active++;
  287                         }
  288 
  289                         if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 &&
  290                             (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
  291                                 txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT);
  292 
  293                         prot = IEEE80211_PROT_NONE;
  294                         if (ridx >= RTWN_RIDX_HT_MCS(0)) {
  295                                 r12a_tx_set_ht40(sc, txd, ni);
  296                                 r12a_tx_set_sgi(sc, txd, ni);
  297                                 r12a_tx_set_ldpc(sc, txd, ni);
  298                                 prot = ic->ic_htprotmode;
  299                         } else if (ic->ic_flags & IEEE80211_F_USEPROT)
  300                                 prot = ic->ic_protmode;
  301 
  302                         /* XXX fix last comparison for A-MSDU (in net80211) */
  303                         /* XXX A-MPDU? */
  304                         if (m->m_pkthdr.len + IEEE80211_CRC_LEN >
  305                             vap->iv_rtsthreshold &&
  306                             vap->iv_rtsthreshold != IEEE80211_RTS_MAX)
  307                                 prot = IEEE80211_PROT_RTSCTS;
  308 
  309                         if (prot != IEEE80211_PROT_NONE)
  310                                 r12a_tx_protection(sc, txd, prot, ridx);
  311                 } else  /* IEEE80211_FC0_TYPE_MGT */
  312                         qsel = R12A_TXDW1_QSEL_MGNT;
  313         } else {
  314                 macid = RTWN_MACID_BC;
  315                 qsel = R12A_TXDW1_QSEL_MGNT;
  316         }
  317 
  318         txd->txdw1 |= htole32(SM(R12A_TXDW1_QSEL, qsel));
  319         txd->txdw1 |= htole32(SM(R12A_TXDW1_MACID, macid));
  320         txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE, ridx));
  321         /* Data rate fallback limit (max). */
  322         txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE_FB_LMT, 0x1f));
  323         /* XXX recheck for non-21au */
  324         txd->txdw6 |= htole32(SM(R21A_TXDW6_MBSSID, uvp->id));
  325         r12a_tx_raid(sc, txd, ni, ismcast);
  326 
  327         /* Force this rate if needed. */
  328         if (sc->sc_ratectl != RTWN_RATECTL_FW)
  329                 txd->txdw3 |= htole32(R12A_TXDW3_DRVRATE);
  330 
  331         if (!hasqos) {
  332                 /* Use HW sequence numbering for non-QoS frames. */
  333                 txd->txdw8 |= htole32(R12A_TXDW8_HWSEQ_EN);
  334                 txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, uvp->id));
  335         } else {
  336                 uint16_t seqno;
  337 
  338                 if (m->m_flags & M_AMPDU_MPDU) {
  339                         seqno = ni->ni_txseqs[tid];
  340                         ni->ni_txseqs[tid]++;
  341                 } else
  342                         seqno = M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE;
  343 
  344                 /* Set sequence number. */
  345                 txd->txdw9 |= htole32(SM(R12A_TXDW9_SEQ, seqno));
  346         }
  347 }
  348 
  349 void
  350 r12a_fill_tx_desc_raw(struct rtwn_softc *sc, struct ieee80211_node *ni,
  351     struct mbuf *m, void *buf, const struct ieee80211_bpf_params *params)
  352 {
  353         struct ieee80211vap *vap = ni->ni_vap;
  354         struct rtwn_vap *uvp = RTWN_VAP(vap);
  355         struct ieee80211_frame *wh;
  356         struct r12a_tx_desc *txd;
  357         uint8_t ridx;
  358         int ismcast;
  359 
  360         /* XXX TODO: 11n checks, matching rtwn_fill_tx_desc() */
  361 
  362         wh = mtod(m, struct ieee80211_frame *);
  363         ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
  364         ridx = rate2ridx(params->ibp_rate0);
  365 
  366         /* Fill Tx descriptor. */
  367         txd = (struct r12a_tx_desc *)buf;
  368         txd->flags0 |= R12A_FLAGS0_LSG | R12A_FLAGS0_FSG;
  369         if (ismcast)
  370                 txd->flags0 |= R12A_FLAGS0_BMCAST;
  371 
  372         if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) {
  373                 txd->txdw4 = htole32(R12A_TXDW4_RETRY_LMT_ENA);
  374                 txd->txdw4 |= htole32(SM(R12A_TXDW4_RETRY_LMT,
  375                     params->ibp_try0));
  376         }
  377         if (params->ibp_flags & IEEE80211_BPF_RTS)
  378                 r12a_tx_protection(sc, txd, IEEE80211_PROT_RTSCTS, ridx);
  379         if (params->ibp_flags & IEEE80211_BPF_CTS)
  380                 r12a_tx_protection(sc, txd, IEEE80211_PROT_CTSONLY, ridx);
  381 
  382         txd->txdw1 |= htole32(SM(R12A_TXDW1_MACID, RTWN_MACID_BC));
  383         txd->txdw1 |= htole32(SM(R12A_TXDW1_QSEL, R12A_TXDW1_QSEL_MGNT));
  384 
  385         /* Set TX rate index. */
  386         txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE, ridx));
  387         txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE_FB_LMT, 0x1f));
  388         txd->txdw6 |= htole32(SM(R21A_TXDW6_MBSSID, uvp->id));
  389         txd->txdw3 |= htole32(R12A_TXDW3_DRVRATE);
  390         r12a_tx_raid(sc, txd, ni, ismcast);
  391 
  392         if (!IEEE80211_QOS_HAS_SEQ(wh)) {
  393                 /* Use HW sequence numbering for non-QoS frames. */
  394                 txd->txdw8 |= htole32(R12A_TXDW8_HWSEQ_EN);
  395                 txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, uvp->id));
  396         } else {
  397                 /* Set sequence number. */
  398                 txd->txdw9 |= htole32(SM(R12A_TXDW9_SEQ,
  399                     M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE));
  400         }
  401 }
  402 
  403 void
  404 r12a_fill_tx_desc_null(struct rtwn_softc *sc, void *buf, int is11b, int qos,
  405     int id)
  406 {
  407         struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf;
  408 
  409         txd->flags0 = R12A_FLAGS0_FSG | R12A_FLAGS0_LSG | R12A_FLAGS0_OWN;
  410         txd->txdw1 = htole32(
  411             SM(R12A_TXDW1_QSEL, R12A_TXDW1_QSEL_MGNT));
  412 
  413         txd->txdw3 = htole32(R12A_TXDW3_DRVRATE);
  414         txd->txdw6 = htole32(SM(R21A_TXDW6_MBSSID, id));
  415         if (is11b) {
  416                 txd->txdw4 = htole32(SM(R12A_TXDW4_DATARATE,
  417                     RTWN_RIDX_CCK1));
  418         } else {
  419                 txd->txdw4 = htole32(SM(R12A_TXDW4_DATARATE,
  420                     RTWN_RIDX_OFDM6));
  421         }
  422 
  423         if (!qos) {
  424                 txd->txdw8 = htole32(R12A_TXDW8_HWSEQ_EN);
  425                 txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, id));
  426         }
  427 }
  428 
  429 uint8_t
  430 r12a_tx_radiotap_flags(const void *buf)
  431 {
  432         const struct r12a_tx_desc *txd = buf;
  433         uint8_t flags, rate;
  434 
  435         if (!(txd->txdw5 & htole32(R12A_TXDW5_DATA_SHORT)))
  436                 return (0);
  437 
  438         rate = MS(le32toh(txd->txdw4), R12A_TXDW4_DATARATE);
  439         if (RTWN_RATE_IS_CCK(rate))
  440                 flags = IEEE80211_RADIOTAP_F_SHORTPRE;
  441         else
  442                 flags = IEEE80211_RADIOTAP_F_SHORTGI;
  443         return (flags);
  444 }

Cache object: 2e5c7c4752da966fda3c17e65c0b10c5


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