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_rx.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 #include <net80211/ieee80211_ratectl.h>
   53 
   54 #include <dev/rtwn/if_rtwnreg.h>
   55 #include <dev/rtwn/if_rtwnvar.h>
   56 
   57 #include <dev/rtwn/if_rtwn_debug.h>
   58 #include <dev/rtwn/if_rtwn_ridx.h>
   59 
   60 #include <dev/rtwn/rtl8812a/r12a.h>
   61 #include <dev/rtwn/rtl8812a/r12a_var.h>
   62 #include <dev/rtwn/rtl8812a/r12a_fw_cmd.h>
   63 #include <dev/rtwn/rtl8812a/r12a_rx_desc.h>
   64 
   65 #ifndef RTWN_WITHOUT_UCODE
   66 void
   67 r12a_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len)
   68 {
   69 #if __FreeBSD_version >= 1200012
   70         struct ieee80211_ratectl_tx_status txs;
   71 #endif
   72         struct r12a_c2h_tx_rpt *rpt;
   73         struct ieee80211_node *ni;
   74         int ntries;
   75 
   76         /* Skip Rx descriptor / report id / sequence fields. */
   77         buf += sizeof(struct r92c_rx_stat) + 2;
   78         len -= sizeof(struct r92c_rx_stat) + 2;
   79 
   80         rpt = (struct r12a_c2h_tx_rpt *)buf;
   81         if (len != sizeof(*rpt)) {
   82                 device_printf(sc->sc_dev,
   83                     "%s: wrong report size (%d, must be %zu)\n",
   84                     __func__, len, sizeof(*rpt));
   85                 return;
   86         }
   87 
   88         RTWN_DPRINTF(sc, RTWN_DEBUG_INTR,
   89             "%s: ccx report dump: 0: %02X, id: %02X, 2: %02X, queue time: "
   90             "low %02X, high %02X, final ridx: %02X, rsvd: %04X\n",
   91             __func__, rpt->txrptb0, rpt->macid, rpt->txrptb2,
   92             rpt->queue_time_low, rpt->queue_time_high, rpt->final_rate,
   93             rpt->reserved);
   94 
   95         if (rpt->macid > sc->macid_limit) {
   96                 device_printf(sc->sc_dev,
   97                     "macid %u is too big; increase MACID_MAX limit\n",
   98                     rpt->macid);
   99                 return;
  100         }
  101 
  102         ntries = MS(rpt->txrptb2, R12A_TXRPTB2_RETRY_CNT);
  103 
  104         ni = sc->node_list[rpt->macid];
  105         if (ni != NULL) {
  106                 RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: frame for macid %u was"
  107                     "%s sent (%d retries)\n", __func__, rpt->macid,
  108                     (rpt->txrptb0 & (R12A_TXRPTB0_RETRY_OVER |
  109                     R12A_TXRPTB0_LIFE_EXPIRE)) ? " not" : "", ntries);
  110 
  111 #if __FreeBSD_version >= 1200012
  112                 txs.flags = IEEE80211_RATECTL_STATUS_LONG_RETRY |
  113                             IEEE80211_RATECTL_STATUS_FINAL_RATE;
  114                 txs.long_retries = ntries;
  115                 if (rpt->final_rate > RTWN_RIDX_OFDM54) {       /* MCS */
  116                         txs.final_rate =
  117                             rpt->final_rate - RTWN_RIDX_HT_MCS_SHIFT;
  118                         txs.final_rate |= IEEE80211_RATE_MCS;
  119                 } else
  120                         txs.final_rate = ridx2rate[rpt->final_rate];
  121                 if (rpt->txrptb0 & R12A_TXRPTB0_RETRY_OVER)
  122                         txs.status = IEEE80211_RATECTL_TX_FAIL_LONG;
  123                 else if (rpt->txrptb0 & R12A_TXRPTB0_LIFE_EXPIRE)
  124                         txs.status = IEEE80211_RATECTL_TX_FAIL_EXPIRED;
  125                 else
  126                         txs.status = IEEE80211_RATECTL_TX_SUCCESS;
  127                 ieee80211_ratectl_tx_complete(ni, &txs);
  128 #else
  129                 struct ieee80211vap *vap = ni->ni_vap;
  130                 if (rpt->txrptb0 & R12A_TXRPTB0_RETRY_OVER) {
  131                         ieee80211_ratectl_tx_complete(vap, ni,
  132                             IEEE80211_RATECTL_TX_FAILURE, &ntries, NULL);
  133                 } else {
  134                         ieee80211_ratectl_tx_complete(vap, ni,
  135                             IEEE80211_RATECTL_TX_SUCCESS, &ntries, NULL);
  136                 }
  137 #endif
  138         } else {
  139                 RTWN_DPRINTF(sc, RTWN_DEBUG_INTR,
  140                     "%s: macid %u, ni is NULL\n", __func__, rpt->macid);
  141         }
  142 }
  143 
  144 void
  145 r12a_handle_c2h_report(struct rtwn_softc *sc, uint8_t *buf, int len)
  146 {
  147         struct r12a_softc *rs = sc->sc_priv;
  148 
  149         /* Skip Rx descriptor. */
  150         buf += sizeof(struct r92c_rx_stat);
  151         len -= sizeof(struct r92c_rx_stat);
  152 
  153         if (len < 2) {
  154                 device_printf(sc->sc_dev, "C2H report too short (len %d)\n",
  155                     len);
  156                 return;
  157         }
  158         len -= 2;
  159 
  160         switch (buf[0]) {       /* command id */
  161         case R12A_C2H_TX_REPORT:
  162                 /* NOTREACHED */
  163                 KASSERT(0, ("use handle_tx_report() instead of %s\n",
  164                     __func__));
  165                 break;
  166         case R12A_C2H_IQK_FINISHED:
  167                 RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
  168                     "FW IQ calibration finished\n");
  169                 rs->rs_flags &= ~R12A_IQK_RUNNING;
  170                 break;
  171         default:
  172                 device_printf(sc->sc_dev,
  173                     "%s: C2H report %u was not handled\n",
  174                     __func__, buf[0]);
  175         }
  176 }
  177 #else
  178 void
  179 r12a_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len)
  180 {
  181         /* Should not happen. */
  182         device_printf(sc->sc_dev, "%s: called\n", __func__);
  183 }
  184 
  185 void
  186 r12a_handle_c2h_report(struct rtwn_softc *sc, uint8_t *buf, int len)
  187 {
  188         /* Should not happen. */
  189         device_printf(sc->sc_dev, "%s: called\n", __func__);
  190 }
  191 #endif
  192 
  193 int
  194 r12a_check_frame_checksum(struct rtwn_softc *sc, struct mbuf *m)
  195 {
  196         struct r12a_softc *rs = sc->sc_priv;
  197         struct r92c_rx_stat *stat;
  198         uint32_t rxdw1;
  199 
  200         stat = mtod(m, struct r92c_rx_stat *);
  201         rxdw1 = le32toh(stat->rxdw1);
  202         if (rxdw1 & R12A_RXDW1_CKSUM) {
  203                 RTWN_DPRINTF(sc, RTWN_DEBUG_RECV,
  204                     "%s: %s/%s checksum is %s\n", __func__,
  205                     (rxdw1 & R12A_RXDW1_UDP) ? "UDP" : "TCP",
  206                     (rxdw1 & R12A_RXDW1_IPV6) ? "IPv6" : "IP",
  207                     (rxdw1 & R12A_RXDW1_CKSUM_ERR) ? "invalid" : "valid");
  208 
  209                 if (rxdw1 & R12A_RXDW1_CKSUM_ERR)
  210                         return (-1);
  211 
  212                 if ((rxdw1 & R12A_RXDW1_IPV6) ?
  213                     (rs->rs_flags & R12A_RXCKSUM6_EN) :
  214                     (rs->rs_flags & R12A_RXCKSUM_EN)) {
  215                         m->m_pkthdr.csum_flags = CSUM_IP_CHECKED |
  216                             CSUM_IP_VALID | CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
  217                         m->m_pkthdr.csum_data = 0xffff;
  218                 }
  219         }
  220 
  221         return (0);
  222 }
  223 
  224 uint8_t
  225 r12a_rx_radiotap_flags(const void *buf)
  226 {
  227         const struct r92c_rx_stat *stat = buf;
  228         uint8_t flags, rate;
  229 
  230         if (!(stat->rxdw4 & htole32(R12A_RXDW4_SPLCP)))
  231                 return (0);
  232         rate = MS(le32toh(stat->rxdw3), R12A_RXDW3_RATE);
  233         if (RTWN_RATE_IS_CCK(rate))
  234                 flags = IEEE80211_RADIOTAP_F_SHORTPRE;
  235         else
  236                 flags = IEEE80211_RADIOTAP_F_SHORTGI;
  237         return (flags);
  238 }
  239 
  240 void
  241 r12a_get_rx_stats(struct rtwn_softc *sc, struct ieee80211_rx_stats *rxs,
  242     const void *desc, const void *physt_ptr)
  243 {
  244         const struct r92c_rx_stat *stat = desc;
  245         const struct r12a_rx_phystat *physt = physt_ptr;
  246         uint32_t rxdw0, rxdw1, rxdw3, rxdw4;
  247         uint8_t rate;
  248 
  249         rxdw0 = le32toh(stat->rxdw0);
  250         rxdw1 = le32toh(stat->rxdw1);
  251         rxdw3 = le32toh(stat->rxdw3);
  252         rxdw4 = le32toh(stat->rxdw4);
  253         rate = MS(rxdw3, R12A_RXDW3_RATE);
  254 
  255         /* TODO: STBC */
  256         if (rxdw4 & R12A_RXDW4_LDPC)
  257                 rxs->c_pktflags |= IEEE80211_RX_F_LDPC;
  258         if (rxdw1 & R12A_RXDW1_AMPDU) {
  259                 if (rxdw0 & R92C_RXDW0_PHYST)
  260                         rxs->c_pktflags |= IEEE80211_RX_F_AMPDU;
  261                 else
  262                         rxs->c_pktflags |= IEEE80211_RX_F_AMPDU_MORE;
  263         }
  264 
  265         if ((rxdw4 & R12A_RXDW4_SPLCP) && rate >= RTWN_RIDX_HT_MCS(0))
  266                 rxs->c_pktflags |= IEEE80211_RX_F_SHORTGI;
  267 
  268         switch (MS(rxdw4, R12A_RXDW4_BW)) {
  269         case R12A_RXDW4_BW20:
  270                 rxs->c_width = IEEE80211_RX_FW_20MHZ;
  271                 break;
  272         case R12A_RXDW4_BW40:
  273                 rxs->c_width = IEEE80211_RX_FW_40MHZ;
  274                 break;
  275         case R12A_RXDW4_BW80:
  276                 rxs->c_width = IEEE80211_RX_FW_80MHZ;
  277                 break;
  278         default:
  279                 break;
  280         }
  281 
  282         if (RTWN_RATE_IS_CCK(rate))
  283                 rxs->c_phytype = IEEE80211_RX_FP_11B;
  284         else {
  285                 int is5ghz;
  286 
  287                 /* XXX magic */
  288                 /* XXX check with RTL8812AU */
  289                 is5ghz = (physt->cfosho[2] != 0x01);
  290 
  291                 if (rate < RTWN_RIDX_HT_MCS(0)) {
  292                         if (is5ghz)
  293                                 rxs->c_phytype = IEEE80211_RX_FP_11A;
  294                         else
  295                                 rxs->c_phytype = IEEE80211_RX_FP_11G;
  296                 } else {
  297                         if (is5ghz)
  298                                 rxs->c_phytype = IEEE80211_RX_FP_11NA;
  299                         else
  300                                 rxs->c_phytype = IEEE80211_RX_FP_11NG;
  301                 }
  302         }
  303 
  304         /* Map HW rate index to 802.11 rate. */
  305         if (rate < RTWN_RIDX_HT_MCS(0)) {
  306                 rxs->c_rate = ridx2rate[rate];
  307                 if (RTWN_RATE_IS_CCK(rate))
  308                         rxs->c_pktflags |= IEEE80211_RX_F_CCK;
  309                 else
  310                         rxs->c_pktflags |= IEEE80211_RX_F_OFDM;
  311         } else {        /* MCS0~15. */
  312                 /* TODO: VHT rates */
  313                 rxs->c_rate =
  314                     IEEE80211_RATE_MCS | (rate - RTWN_RIDX_HT_MCS_SHIFT);
  315                 rxs->c_pktflags |= IEEE80211_RX_F_HT;
  316         }
  317 
  318         /*
  319          * XXX always zero for RTL8821AU
  320          * (vendor driver does not check this field)
  321          */
  322 #if 0
  323         rxs->r_flags |= IEEE80211_R_IEEE | IEEE80211_R_FREQ;
  324         rxs->r_flags |= IEEE80211_R_BAND;
  325         rxs->c_ieee = MS(le16toh(physt->phyw1), R12A_PHYW1_CHAN);
  326         rxs->c_freq = ieee80211_ieee2mhz(rxs->c_ieee,
  327             (rxs->c_ieee < 36) ? IEEE80211_CHAN_2GHZ : IEEE80211_CHAN_5GHZ);
  328         rxs->c_band = (rxs->c_ieee < 36) ? IEEE80211_CHAN_2GHZ : IEEE80211_CHAN_5GHZ;
  329 #endif
  330 }

Cache object: 3be96bdddc68d6c6f99edcebdc95e99f


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