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/rtl8192c/r92c_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_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $   */
    2 
    3 /*-
    4  * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
    5  * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
    6  * Copyright (c) 2015-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 #include <sys/linker.h>
   39 
   40 #include <net/if.h>
   41 #include <net/ethernet.h>
   42 #include <net/if_media.h>
   43 
   44 #include <net80211/ieee80211_var.h>
   45 #include <net80211/ieee80211_radiotap.h>
   46 
   47 #include <dev/rtwn/if_rtwnreg.h>
   48 #include <dev/rtwn/if_rtwnvar.h>
   49 
   50 #include <dev/rtwn/if_rtwn_ridx.h>
   51 #include <dev/rtwn/if_rtwn_tx.h>
   52 
   53 #include <dev/rtwn/rtl8192c/r92c.h>
   54 #include <dev/rtwn/rtl8192c/r92c_var.h>
   55 #include <dev/rtwn/rtl8192c/r92c_tx_desc.h>
   56 
   57 static int
   58 r92c_tx_get_sco(struct rtwn_softc *sc, struct ieee80211_channel *c)
   59 {
   60         if (IEEE80211_IS_CHAN_HT40U(c))
   61                 return (R92C_TXDW4_SCO_SCA);
   62         else
   63                 return (R92C_TXDW4_SCO_SCB);
   64 }
   65 
   66 static void
   67 r92c_tx_set_ht40(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni)
   68 {
   69         struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf;
   70 
   71         if (ni->ni_chan != IEEE80211_CHAN_ANYC &&
   72             IEEE80211_IS_CHAN_HT40(ni->ni_chan)) {
   73                 int extc_offset;
   74 
   75                 extc_offset = r92c_tx_get_sco(sc, ni->ni_chan);
   76                 txd->txdw4 |= htole32(R92C_TXDW4_DATA_BW40);
   77                 txd->txdw4 |= htole32(SM(R92C_TXDW4_DATA_SCO, extc_offset));
   78         }
   79 }
   80 
   81 static void
   82 r92c_tx_protection(struct rtwn_softc *sc, struct r92c_tx_desc *txd,
   83     enum ieee80211_protmode mode, uint8_t ridx)
   84 {
   85         struct ieee80211com *ic = &sc->sc_ic;
   86         uint8_t rate;
   87 
   88         switch (mode) {
   89         case IEEE80211_PROT_CTSONLY:
   90                 txd->txdw4 |= htole32(R92C_TXDW4_CTS2SELF);
   91                 break;
   92         case IEEE80211_PROT_RTSCTS:
   93                 txd->txdw4 |= htole32(R92C_TXDW4_RTSEN);
   94                 break;
   95         default:
   96                 break;
   97         }
   98 
   99         if (mode == IEEE80211_PROT_CTSONLY ||
  100             mode == IEEE80211_PROT_RTSCTS) {
  101                 if (ridx >= RTWN_RIDX_HT_MCS(0))
  102                         rate = rtwn_ctl_mcsrate(ic->ic_rt, ridx);
  103                 else
  104                         rate = ieee80211_ctl_rate(ic->ic_rt, ridx2rate[ridx]);
  105                 ridx = rate2ridx(IEEE80211_RV(rate));
  106 
  107                 txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, ridx));
  108                 /* RTS rate fallback limit (max). */
  109                 txd->txdw5 |= htole32(SM(R92C_TXDW5_RTSRATE_FB_LMT, 0xf));
  110 
  111                 if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 &&
  112                     (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
  113                         txd->txdw4 |= htole32(R92C_TXDW4_RTS_SHORT);
  114         }
  115 }
  116 
  117 static void
  118 r92c_tx_raid(struct rtwn_softc *sc, struct r92c_tx_desc *txd,
  119     struct ieee80211_node *ni, int ismcast)
  120 {
  121         struct ieee80211com *ic = &sc->sc_ic;
  122         struct ieee80211vap *vap = ni->ni_vap;
  123         struct ieee80211_channel *chan;
  124         enum ieee80211_phymode mode;
  125         uint8_t raid;
  126 
  127         chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ?
  128                 ni->ni_chan : ic->ic_curchan;
  129         mode = ieee80211_chan2mode(chan);
  130 
  131         /* NB: group addressed frames are done at 11bg rates for now */
  132         if (ismcast || !(ni->ni_flags & IEEE80211_NODE_HT)) {
  133                 switch (mode) {
  134                 case IEEE80211_MODE_11B:
  135                 case IEEE80211_MODE_11G:
  136                         break;
  137                 case IEEE80211_MODE_11NG:
  138                         mode = IEEE80211_MODE_11G;
  139                         break;
  140                 default:
  141                         device_printf(sc->sc_dev, "unknown mode(1) %d!\n",
  142                             ic->ic_curmode);
  143                         return;
  144                 }
  145         }
  146 
  147         switch (mode) {
  148         case IEEE80211_MODE_11B:
  149                 raid = R92C_RAID_11B;
  150                 break;
  151         case IEEE80211_MODE_11G:
  152                 if (vap->iv_flags & IEEE80211_F_PUREG)
  153                         raid = R92C_RAID_11G;
  154                 else
  155                         raid = R92C_RAID_11BG;
  156                 break;
  157         case IEEE80211_MODE_11NG:
  158                 if (vap->iv_flags_ht & IEEE80211_FHT_PUREN)
  159                         raid = R92C_RAID_11N;
  160                 else
  161                         raid = R92C_RAID_11BGN;
  162                 break;
  163         default:
  164                 device_printf(sc->sc_dev, "unknown mode(2) %d!\n", mode);
  165                 return;
  166         }
  167 
  168         txd->txdw1 |= htole32(SM(R92C_TXDW1_RAID, raid));
  169 }
  170 
  171 /* XXX move to device-independent layer */
  172 static void
  173 r92c_tx_set_sgi(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni)
  174 {
  175         struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf;
  176         struct ieee80211vap *vap = ni->ni_vap;
  177 
  178         if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) &&     /* HT20 */
  179             (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20))
  180                 txd->txdw5 |= htole32(R92C_TXDW5_SGI);
  181         else if (ni->ni_chan != IEEE80211_CHAN_ANYC &&          /* HT40 */
  182             IEEE80211_IS_CHAN_HT40(ni->ni_chan) &&
  183             (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) &&
  184             (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40))
  185                 txd->txdw5 |= htole32(R92C_TXDW5_SGI);
  186 }
  187 
  188 void
  189 r92c_tx_enable_ampdu(void *buf, int enable)
  190 {
  191         struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf;
  192 
  193         if (enable)
  194                 txd->txdw1 |= htole32(R92C_TXDW1_AGGEN);
  195         else
  196                 txd->txdw1 |= htole32(R92C_TXDW1_AGGBK);
  197 }
  198 
  199 void
  200 r92c_tx_setup_hwseq(void *buf)
  201 {
  202         struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf;
  203 
  204         txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ_EN);
  205 }
  206 
  207 void
  208 r92c_tx_setup_macid(void *buf, int id)
  209 {
  210         struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf;
  211 
  212         txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, id));
  213 
  214         /* XXX does not belong here */
  215         /* XXX temporary (I hope) */
  216         /* Force CCK1 for RTS / CTS frames (driver bug) */
  217         txd->txdw4 &= ~htole32(SM(R92C_TXDW4_RTSRATE, R92C_TXDW4_RTSRATE_M));
  218         txd->txdw4 &= ~htole32(R92C_TXDW4_RTS_SHORT);
  219 }
  220 
  221 void
  222 r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni,
  223     struct mbuf *m, void *buf, uint8_t ridx, int maxretry)
  224 {
  225 #ifndef RTWN_WITHOUT_UCODE
  226         struct r92c_softc *rs = sc->sc_priv;
  227 #endif
  228         struct ieee80211com *ic = &sc->sc_ic;
  229         struct ieee80211vap *vap = ni->ni_vap;
  230         struct rtwn_vap *uvp = RTWN_VAP(vap);
  231         struct ieee80211_frame *wh;
  232         struct r92c_tx_desc *txd;
  233         enum ieee80211_protmode prot;
  234         uint8_t type, tid, qos, qsel;
  235         int hasqos, ismcast, macid;
  236 
  237         wh = mtod(m, struct ieee80211_frame *);
  238         type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
  239         hasqos = IEEE80211_QOS_HAS_SEQ(wh);
  240         ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
  241 
  242         /* Select TX ring for this frame. */
  243         if (hasqos) {
  244                 qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0];
  245                 tid = qos & IEEE80211_QOS_TID;
  246         } else {
  247                 qos = 0;
  248                 tid = 0;
  249         }
  250 
  251         /* Fill Tx descriptor. */
  252         txd = (struct r92c_tx_desc *)buf;
  253         txd->flags0 |= R92C_FLAGS0_LSG | R92C_FLAGS0_FSG;
  254         if (ismcast)
  255                 txd->flags0 |= R92C_FLAGS0_BMCAST;
  256 
  257         if (!ismcast) {
  258                 /* Unicast frame, check if an ACK is expected. */
  259                 if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) !=
  260                     IEEE80211_QOS_ACKPOLICY_NOACK) {
  261                         txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA);
  262                         txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT,
  263                             maxretry));
  264                 }
  265 
  266                 struct rtwn_node *un = RTWN_NODE(ni);
  267                 macid = un->id;
  268 
  269                 if (type == IEEE80211_FC0_TYPE_DATA) {
  270                         qsel = tid % RTWN_MAX_TID;
  271 
  272                         rtwn_r92c_tx_enable_ampdu(sc, buf,
  273                             (m->m_flags & M_AMPDU_MPDU) != 0);
  274                         if (m->m_flags & M_AMPDU_MPDU) {
  275                                 txd->txdw2 |= htole32(SM(R92C_TXDW2_AMPDU_DEN,
  276                                     vap->iv_ampdu_density));
  277                                 txd->txdw6 |= htole32(SM(R92C_TXDW6_MAX_AGG,
  278                                     0x1f));     /* XXX */
  279                         }
  280                         if (sc->sc_ratectl == RTWN_RATECTL_NET80211) {
  281                                 txd->txdw2 |= htole32(R92C_TXDW2_CCX_RPT);
  282                                 sc->sc_tx_n_active++;
  283 #ifndef RTWN_WITHOUT_UCODE
  284                                 rs->rs_c2h_pending++;
  285 #endif
  286                         }
  287 
  288                         if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 &&
  289                             (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
  290                                 txd->txdw4 |= htole32(R92C_TXDW4_DATA_SHPRE);
  291 
  292                         prot = IEEE80211_PROT_NONE;
  293                         if (ridx >= RTWN_RIDX_HT_MCS(0)) {
  294                                 r92c_tx_set_ht40(sc, txd, ni);
  295                                 r92c_tx_set_sgi(sc, txd, ni);
  296                                 prot = ic->ic_htprotmode;
  297                         } else if (ic->ic_flags & IEEE80211_F_USEPROT)
  298                                 prot = ic->ic_protmode;
  299 
  300                         /* XXX fix last comparison for A-MSDU (in net80211) */
  301                         /* XXX A-MPDU? */
  302                         if (m->m_pkthdr.len + IEEE80211_CRC_LEN >
  303                             vap->iv_rtsthreshold &&
  304                             vap->iv_rtsthreshold != IEEE80211_RTS_MAX)
  305                                 prot = IEEE80211_PROT_RTSCTS;
  306 
  307                         /* NB: checks for ht40 / short bits (set above). */
  308                         if (prot != IEEE80211_PROT_NONE)
  309                                 r92c_tx_protection(sc, txd, prot, ridx);
  310                 } else  /* IEEE80211_FC0_TYPE_MGT */
  311                         qsel = R92C_TXDW1_QSEL_MGNT;
  312         } else {
  313                 macid = RTWN_MACID_BC;
  314                 qsel = R92C_TXDW1_QSEL_MGNT;
  315         }
  316 
  317         txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, qsel));
  318 
  319         rtwn_r92c_tx_setup_macid(sc, txd, macid);
  320         txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx));
  321         /* Data rate fallback limit (max). */
  322         txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE_FB_LMT, 0x1f));
  323         txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, uvp->id));
  324         r92c_tx_raid(sc, txd, ni, ismcast);
  325 
  326         /* Force this rate if needed. */
  327         if (sc->sc_ratectl != RTWN_RATECTL_FW)
  328                 txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE);
  329 
  330         if (!hasqos) {
  331                 /* Use HW sequence numbering for non-QoS frames. */
  332                 rtwn_r92c_tx_setup_hwseq(sc, txd);
  333                 txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, uvp->id));
  334         } else {
  335                 uint16_t seqno;
  336 
  337                 if (m->m_flags & M_AMPDU_MPDU) {
  338                         seqno = ni->ni_txseqs[tid] % IEEE80211_SEQ_RANGE;
  339                         ni->ni_txseqs[tid]++;
  340                 } else
  341                         seqno = M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE;
  342 
  343                 /* Set sequence number. */
  344                 txd->txdseq = htole16(seqno);
  345         }
  346 }
  347 
  348 void
  349 r92c_fill_tx_desc_raw(struct rtwn_softc *sc, struct ieee80211_node *ni,
  350     struct mbuf *m, void *buf, const struct ieee80211_bpf_params *params)
  351 {
  352         struct ieee80211vap *vap = ni->ni_vap;
  353         struct rtwn_vap *uvp = RTWN_VAP(vap);
  354         struct ieee80211_frame *wh;
  355         struct r92c_tx_desc *txd;
  356         uint8_t ridx;
  357         int ismcast;
  358 
  359         /* XXX TODO: 11n checks, matching r92c_fill_tx_desc() */
  360 
  361         wh = mtod(m, struct ieee80211_frame *);
  362         ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
  363         ridx = rate2ridx(params->ibp_rate0);
  364 
  365         /* Fill Tx descriptor. */
  366         txd = (struct r92c_tx_desc *)buf;
  367         txd->flags0 |= R92C_FLAGS0_LSG | R92C_FLAGS0_FSG;
  368         if (ismcast)
  369                 txd->flags0 |= R92C_FLAGS0_BMCAST;
  370 
  371         if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) {
  372                 txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA);
  373                 txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT,
  374                     params->ibp_try0));
  375         }
  376         if (params->ibp_flags & IEEE80211_BPF_RTS)
  377                 r92c_tx_protection(sc, txd, IEEE80211_PROT_RTSCTS, ridx);
  378         if (params->ibp_flags & IEEE80211_BPF_CTS)
  379                 r92c_tx_protection(sc, txd, IEEE80211_PROT_CTSONLY, ridx);
  380 
  381         rtwn_r92c_tx_setup_macid(sc, txd, RTWN_MACID_BC);
  382         txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT));
  383 
  384         /* Set TX rate index. */
  385         txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx));
  386         txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE_FB_LMT, 0x1f));
  387         txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, uvp->id));
  388         txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE);
  389         r92c_tx_raid(sc, txd, ni, ismcast);
  390 
  391         if (!IEEE80211_QOS_HAS_SEQ(wh)) {
  392                 /* Use HW sequence numbering for non-QoS frames. */
  393                 rtwn_r92c_tx_setup_hwseq(sc, txd);
  394                 txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, uvp->id));
  395         } else {
  396                 /* Set sequence number. */
  397                 txd->txdseq |= htole16(M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE);
  398         }
  399 }
  400 
  401 void
  402 r92c_fill_tx_desc_null(struct rtwn_softc *sc, void *buf, int is11b,
  403     int qos, int id)
  404 {
  405         struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf;
  406 
  407         txd->flags0 = R92C_FLAGS0_FSG | R92C_FLAGS0_LSG | R92C_FLAGS0_OWN;
  408         txd->txdw1 = htole32(
  409             SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT));
  410 
  411         txd->txdw4 = htole32(R92C_TXDW4_DRVRATE);
  412         txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, id));
  413         if (is11b) {
  414                 txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE,
  415                     RTWN_RIDX_CCK1));
  416         } else {
  417                 txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE,
  418                     RTWN_RIDX_OFDM6));
  419         }
  420 
  421         if (!qos) {
  422                 rtwn_r92c_tx_setup_hwseq(sc, txd);
  423                 txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, id));
  424         }
  425 }
  426 
  427 uint8_t
  428 r92c_tx_radiotap_flags(const void *buf)
  429 {
  430         const struct r92c_tx_desc *txd = buf;
  431         uint8_t flags;
  432 
  433         flags = 0;
  434         if (txd->txdw4 & htole32(R92C_TXDW4_DATA_SHPRE))
  435                 flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
  436         if (txd->txdw5 & htole32(R92C_TXDW5_SGI))
  437                 flags |= IEEE80211_RADIOTAP_F_SHORTGI;
  438         return (flags);
  439 }

Cache object: 72a0df2a97d065def1eb87345aa573f4


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