Index: head/sys/dev/rtwn/if_rtwn.c =================================================================== --- head/sys/dev/rtwn/if_rtwn.c +++ head/sys/dev/rtwn/if_rtwn.c @@ -1999,6 +1999,7 @@ sc->fwver = 0; sc->thcal_temp = 0; sc->cur_bcnq_id = RTWN_VAP_ID_INVALID; + bzero(&sc->last_physt, sizeof(sc->last_physt)); #ifdef D4054 ieee80211_tx_watchdog_stop(&sc->sc_ic); Index: head/sys/dev/rtwn/if_rtwn_rx.h =================================================================== --- head/sys/dev/rtwn/if_rtwn_rx.h +++ head/sys/dev/rtwn/if_rtwn_rx.h @@ -26,7 +26,7 @@ const struct ieee80211_htrateset *, uint32_t *, int *, int); void rtwn_set_basicrates(struct rtwn_softc *, uint32_t); struct ieee80211_node * rtwn_rx_common(struct rtwn_softc *, struct mbuf *, - void *, int8_t *); + void *); void rtwn_adhoc_recv_mgmt(struct ieee80211_node *, struct mbuf *, int, const struct ieee80211_rx_stats *, int, int); void rtwn_set_multi(struct rtwn_softc *); Index: head/sys/dev/rtwn/if_rtwn_rx.c =================================================================== --- head/sys/dev/rtwn/if_rtwn_rx.c +++ head/sys/dev/rtwn/if_rtwn_rx.c @@ -117,18 +117,19 @@ } static void -rtwn_update_avgrssi(struct rtwn_softc *sc, struct rtwn_node *un, int rate) +rtwn_update_avgrssi(struct rtwn_softc *sc, struct rtwn_node *un, int8_t rssi, + int is_cck) { int pwdb; /* Convert antenna signal to percentage. */ - if (un->last_rssi <= -100 || un->last_rssi >= 20) + if (rssi <= -100 || rssi >= 20) pwdb = 0; - else if (un->last_rssi >= 0) + else if (rssi >= 0) pwdb = 100; else - pwdb = 100 + un->last_rssi; - if (RTWN_RATE_IS_CCK(rate)) { + pwdb = 100 + rssi; + if (is_cck) { /* CCK gain is smaller than OFDM/MCS gain. */ pwdb += 6; if (pwdb > 100) @@ -155,11 +156,11 @@ } static int8_t -rtwn_get_rssi(struct rtwn_softc *sc, int rate, void *physt) +rtwn_get_rssi(struct rtwn_softc *sc, void *physt, int is_cck) { int8_t rssi; - if (RTWN_RATE_IS_CCK(rate)) + if (is_cck) rssi = rtwn_get_rssi_cck(sc, physt); else /* OFDM/HT. */ rssi = rtwn_get_rssi_ofdm(sc, physt); @@ -188,81 +189,133 @@ *buf += rtwn_get_tsf_low(sc, id); } +static uint64_t +rtwn_extend_rx_tsf(struct rtwn_softc *sc, const struct r92c_rx_stat *stat) +{ + uint64_t tsft; + uint32_t rxdw3, tsfl, tsfl_curr; + int id; + + rxdw3 = le32toh(stat->rxdw3); + tsfl = le32toh(stat->tsf_low); + id = MS(rxdw3, R92C_RXDW3_BSSID_FIT); + + switch (id) { + case 1: + case 2: + id >>= 1; + tsfl_curr = rtwn_get_tsf_low(sc, id); + break; + default: + { + uint32_t tsfl0, tsfl1; + + tsfl0 = rtwn_get_tsf_low(sc, 0); + tsfl1 = rtwn_get_tsf_low(sc, 1); + + if (abs(tsfl0 - tsfl) < abs(tsfl1 - tsfl)) { + id = 0; + tsfl_curr = tsfl0; + } else { + id = 1; + tsfl_curr = tsfl1; + } + break; + } + } + + tsft = rtwn_get_tsf_high(sc, id); + if (tsfl > tsfl_curr && tsfl > 0xffff0000) + tsft--; + tsft <<= 32; + tsft += tsfl; + + return (tsft); +} + struct ieee80211_node * -rtwn_rx_common(struct rtwn_softc *sc, struct mbuf *m, void *desc, - int8_t *rssi) +rtwn_rx_common(struct rtwn_softc *sc, struct mbuf *m, void *desc) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni; struct ieee80211_frame_min *wh; + struct ieee80211_rx_stats rxs; struct rtwn_node *un; struct r92c_rx_stat *stat; - uint32_t rxdw0, rxdw3; - int cipher, infosz, pktlen, rate, shift; + void *physt; + uint32_t rxdw0; + int8_t rssi; + int cipher, infosz, is_cck, pktlen, shift; stat = desc; rxdw0 = le32toh(stat->rxdw0); - rxdw3 = le32toh(stat->rxdw3); cipher = MS(rxdw0, R92C_RXDW0_CIPHER); infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN); shift = MS(rxdw0, R92C_RXDW0_SHIFT); - rate = MS(rxdw3, R92C_RXDW3_RATE); wh = (struct ieee80211_frame_min *)(mtodo(m, shift + infosz)); if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) && cipher != R92C_CAM_ALGO_NONE) m->m_flags |= M_WEP; - if (pktlen >= sizeof(*wh)) + if (pktlen >= sizeof(*wh)) { ni = ieee80211_find_rxnode(ic, wh); - else + if (ni != NULL && (ni->ni_flags & IEEE80211_NODE_HT)) + m->m_flags |= M_AMPDU; + } else ni = NULL; un = RTWN_NODE(ni); - /* Get RSSI from PHY status descriptor if present. */ - if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) { - *rssi = rtwn_get_rssi(sc, rate, mtod(m, void *)); - RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI, "%s: rssi %d, ridx %d\n", - __func__, *rssi, rate); - - sc->last_rssi = *rssi; - if (un != NULL) { - un->last_rssi = *rssi; + if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) + physt = (void *)mtodo(m, shift); + else + physt = (un != NULL) ? &un->last_physt : &sc->last_physt; - /* Update our average RSSI. */ - rtwn_update_avgrssi(sc, un, rate); - } - } else - *rssi = (un != NULL) ? un->last_rssi : sc->last_rssi; + bzero(&rxs, sizeof(rxs)); + rtwn_get_rx_stats(sc, &rxs, desc, physt); + if (rxs.c_pktflags & IEEE80211_RX_F_AMPDU) { + /* Next MPDU will come without PHY info. */ + memcpy(&sc->last_physt, physt, sizeof(sc->last_physt)); + if (un != NULL) + memcpy(&un->last_physt, physt, sizeof(sc->last_physt)); + } + + /* Add some common bits. */ + /* NB: should not happen. */ + if (rxdw0 & R92C_RXDW0_CRCERR) + rxs.c_pktflags |= IEEE80211_RX_F_FAIL_FCSCRC; + + rxs.r_flags |= IEEE80211_R_TSF_START; /* XXX undocumented */ + rxs.r_flags |= IEEE80211_R_TSF64; + rxs.c_rx_tsf = rtwn_extend_rx_tsf(sc, stat); + + /* Get RSSI from PHY status descriptor. */ + is_cck = (rxs.c_pktflags & IEEE80211_RX_F_CCK) != 0; + rssi = rtwn_get_rssi(sc, physt, is_cck); + + /* XXX TODO: we really need a rate-to-string method */ + RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI, "%s: rssi %d, rate %d\n", + __func__, rssi, rxs.c_rate); + if (un != NULL && infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) { + /* Update our average RSSI. */ + rtwn_update_avgrssi(sc, un, rssi, is_cck); + } + + rxs.r_flags |= IEEE80211_R_NF | IEEE80211_R_RSSI; + rxs.c_nf = RTWN_NOISE_FLOOR; + rxs.c_rssi = rssi - rxs.c_nf; + (void) ieee80211_add_rx_params(m, &rxs); if (ieee80211_radiotap_active(ic)) { struct rtwn_rx_radiotap_header *tap = &sc->sc_rxtap; - int id = RTWN_VAP_ID_INVALID; - - if (ni != NULL) - id = RTWN_VAP(ni->ni_vap)->id; - if (id == RTWN_VAP_ID_INVALID) - id = 0; tap->wr_flags = rtwn_rx_radiotap_flags(sc, desc); - tap->wr_tsft = rtwn_get_tsf_high(sc, id); - if (le32toh(stat->tsf_low) > rtwn_get_tsf_low(sc, id)) - tap->wr_tsft--; - tap->wr_tsft = (uint64_t)htole32(tap->wr_tsft) << 32; - tap->wr_tsft += stat->tsf_low; - - /* XXX 20/40? */ - - /* Map HW rate index to 802.11 rate. */ - if (rate < RTWN_RIDX_MCS(0)) - tap->wr_rate = ridx2rate[rate]; - else /* MCS0~15. */ - tap->wr_rate = IEEE80211_RATE_MCS | (rate - 12); - - tap->wr_dbm_antsignal = *rssi; - tap->wr_dbm_antnoise = RTWN_NOISE_FLOOR; + tap->wr_tsft = htole64(rxs.c_rx_tsf); + tap->wr_rate = rxs.c_rate; + tap->wr_dbm_antsignal = rssi; + tap->wr_dbm_antnoise = rxs.c_nf; } /* Drop PHY descriptor. */ Index: head/sys/dev/rtwn/if_rtwnvar.h =================================================================== --- head/sys/dev/rtwn/if_rtwnvar.h +++ head/sys/dev/rtwn/if_rtwnvar.h @@ -76,6 +76,12 @@ uint8_t txd[RTWN_TX_DESC_SIZE]; } __attribute__((aligned(4))); +#define RTWN_PHY_STATUS_SIZE 32 +struct rtwn_tx_phystat { + uint32_t phydw[RTWN_PHY_STATUS_SIZE / sizeof(uint32_t)]; +}; + + struct rtwn_softc; union sec_param { @@ -95,7 +101,8 @@ struct rtwn_node { struct ieee80211_node ni; /* must be the first */ int id; - int8_t last_rssi; + + struct rtwn_tx_phystat last_physt; int avg_pwdb; }; #define RTWN_NODE(ni) ((struct rtwn_node *)(ni)) @@ -195,7 +202,7 @@ const char *name; int sc_ant; - int8_t last_rssi; + struct rtwn_tx_phystat last_physt; uint8_t thcal_temp; int cur_bcnq_id; @@ -336,6 +343,9 @@ struct ieee80211vap *, int); void (*sc_set_rssi)(struct rtwn_softc *); #endif + void (*sc_get_rx_stats)(struct rtwn_softc *, + struct ieee80211_rx_stats *, const void *, + const void *); int8_t (*sc_get_rssi_cck)(struct rtwn_softc *, void *); int8_t (*sc_get_rssi_ofdm)(struct rtwn_softc *, void *); int (*sc_classify_intr)(struct rtwn_softc *, void *, int); @@ -478,6 +488,8 @@ (((_sc)->sc_parse_rom)((_sc), (_rom))) #define rtwn_set_led(_sc, _led, _on) \ (((_sc)->sc_set_led)((_sc), (_led), (_on))) +#define rtwn_get_rx_stats(_sc, _rxs, _desc, _physt) \ + (((_sc)->sc_get_rx_stats((_sc), (_rxs), (_desc), (_physt)))) #define rtwn_get_rssi_cck(_sc, _physt) \ (((_sc)->sc_get_rssi_cck)((_sc), (_physt))) #define rtwn_get_rssi_ofdm(_sc, _physt) \ Index: head/sys/dev/rtwn/pci/rtwn_pci_rx.c =================================================================== --- head/sys/dev/rtwn/pci/rtwn_pci_rx.c +++ head/sys/dev/rtwn/pci/rtwn_pci_rx.c @@ -95,7 +95,6 @@ struct ieee80211_node *ni; uint32_t rxdw0; struct mbuf *m, *m1; - int8_t rssi = 0, nf; int infosz, pktlen, shift, error; /* Dump Rx descriptor. */ @@ -162,12 +161,11 @@ rx_data->m = m1; m->m_pkthdr.len = m->m_len = pktlen + infosz + shift; - nf = RTWN_NOISE_FLOOR; - ni = rtwn_rx_common(sc, m, rx_desc, &rssi); + ni = rtwn_rx_common(sc, m, rx_desc); RTWN_DPRINTF(sc, RTWN_DEBUG_RECV, - "%s: Rx frame len %d, infosz %d, shift %d, rssi %d\n", - __func__, pktlen, infosz, shift, rssi); + "%s: Rx frame len %d, infosz %d, shift %d\n", + __func__, pktlen, infosz, shift); /* Update RX descriptor. */ rtwn_pci_setup_rx_desc(pc, rx_desc, rx_data->paddr, MJUMPAGESIZE, @@ -176,11 +174,11 @@ /* Send the frame to the 802.11 layer. */ RTWN_UNLOCK(sc); if (ni != NULL) { - (void)ieee80211_input(ni, m, rssi - nf, nf); + (void)ieee80211_input_mimo(ni, m); /* Node is no longer needed. */ ieee80211_free_node(ni); } else - (void)ieee80211_input_all(ic, m, rssi - nf, nf); + (void)ieee80211_input_mimo_all(ic, m); RTWN_LOCK(sc); Index: head/sys/dev/rtwn/rtl8188e/r88e.h =================================================================== --- head/sys/dev/rtwn/rtl8188e/r88e.h +++ head/sys/dev/rtwn/rtl8188e/r88e.h @@ -85,6 +85,8 @@ void r88e_handle_c2h_report(struct rtwn_softc *, uint8_t *, int); int8_t r88e_get_rssi_cck(struct rtwn_softc *, void *); int8_t r88e_get_rssi_ofdm(struct rtwn_softc *, void *); +void r88e_get_rx_stats(struct rtwn_softc *, struct ieee80211_rx_stats *, + const void *, const void *); /* r88e_tx.c */ void r88e_tx_enable_ampdu(void *, int); Index: head/sys/dev/rtwn/rtl8188e/r88e_rx.c =================================================================== --- head/sys/dev/rtwn/rtl8188e/r88e_rx.c +++ head/sys/dev/rtwn/rtl8188e/r88e_rx.c @@ -51,6 +51,7 @@ #include #include +#include #include #include @@ -209,3 +210,19 @@ return (rssi); } + +void +r88e_get_rx_stats(struct rtwn_softc *sc, struct ieee80211_rx_stats *rxs, + const void *desc, const void *physt_ptr) +{ + const struct r88e_rx_phystat *physt = physt_ptr; + + r92c_get_rx_stats(sc, rxs, desc, physt_ptr); + + if (!sc->sc_ht40) { /* XXX center channel */ + rxs->r_flags |= IEEE80211_R_IEEE | IEEE80211_R_FREQ; + rxs->c_ieee = le16toh(physt->chan); + rxs->c_freq = ieee80211_ieee2mhz(rxs->c_ieee, + IEEE80211_CHAN_2GHZ); + } +} Index: head/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c =================================================================== --- head/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c +++ head/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c @@ -127,6 +127,7 @@ sc->sc_dump_tx_desc = r92cu_dump_tx_desc; sc->sc_tx_radiotap_flags = r92c_tx_radiotap_flags; sc->sc_rx_radiotap_flags = r92c_rx_radiotap_flags; + sc->sc_get_rx_stats = r88e_get_rx_stats; sc->sc_get_rssi_cck = r88e_get_rssi_cck; sc->sc_get_rssi_ofdm = r88e_get_rssi_ofdm; sc->sc_classify_intr = r88eu_classify_intr; Index: head/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c =================================================================== --- head/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c +++ head/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c @@ -172,6 +172,7 @@ sc->sc_dump_tx_desc = r92ce_dump_tx_desc; sc->sc_tx_radiotap_flags = r92c_tx_radiotap_flags; sc->sc_rx_radiotap_flags = r92c_rx_radiotap_flags; + sc->sc_get_rx_stats = r92c_get_rx_stats; sc->sc_get_rssi_cck = r92c_get_rssi_cck; sc->sc_get_rssi_ofdm = r92c_get_rssi_ofdm; sc->sc_classify_intr = r92ce_classify_intr; Index: head/sys/dev/rtwn/rtl8192c/r92c.h =================================================================== --- head/sys/dev/rtwn/rtl8192c/r92c.h +++ head/sys/dev/rtwn/rtl8192c/r92c.h @@ -99,6 +99,8 @@ int8_t r92c_get_rssi_cck(struct rtwn_softc *, void *); int8_t r92c_get_rssi_ofdm(struct rtwn_softc *, void *); uint8_t r92c_rx_radiotap_flags(const void *); +void r92c_get_rx_stats(struct rtwn_softc *, struct ieee80211_rx_stats *, + const void *, const void *); /* r92c_tx.c */ void r92c_tx_enable_ampdu(void *, int); Index: head/sys/dev/rtwn/rtl8192c/r92c_reg.h =================================================================== --- head/sys/dev/rtwn/rtl8192c/r92c_reg.h +++ head/sys/dev/rtwn/rtl8192c/r92c_reg.h @@ -420,6 +420,7 @@ #define R92C_PBP_1024 4 /* Bits for R92C_TRXDMA_CTRL. */ +#define R92C_TRXDMA_CTRL_RX_SHIFT_EN 0x0002 #define R92C_TRXDMA_CTRL_RXDMA_AGG_EN 0x0004 #define R92C_TRXDMA_CTRL_TXDMA_VOQ_MAP_M 0x0030 #define R92C_TRXDMA_CTRL_TXDMA_VOQ_MAP_S 4 @@ -593,7 +594,8 @@ #define R92C_RCR_APPFCS 0x80000000 /* Bits for R92C_RX_DRVINFO_SZ. */ -#define R92C_RX_DRVINFO_SZ_DEF 4 /* XXX other values will not work */ +/* XXX other values will not work */ +#define R92C_RX_DRVINFO_SZ_DEF ((RTWN_PHY_STATUS_SIZE) / 8) /* Bits for R92C_WMAC_TRXPTCL_CTL. */ #define R92C_WMAC_TRXPTCL_SHPRE 0x00020000 Index: head/sys/dev/rtwn/rtl8192c/r92c_rx.c =================================================================== --- head/sys/dev/rtwn/rtl8192c/r92c_rx.c +++ head/sys/dev/rtwn/rtl8192c/r92c_rx.c @@ -100,3 +100,47 @@ flags = IEEE80211_RADIOTAP_F_SHORTGI; return (flags); } + +void +r92c_get_rx_stats(struct rtwn_softc *sc, struct ieee80211_rx_stats *rxs, + const void *desc, const void *physt_ptr) +{ + const struct r92c_rx_stat *stat = desc; + uint32_t rxdw1, rxdw3; + uint8_t rate; + + rxdw1 = le32toh(stat->rxdw1); + rxdw3 = le32toh(stat->rxdw3); + rate = MS(rxdw3, R92C_RXDW3_RATE); + + if (rxdw1 & R92C_RXDW1_AMPDU) + rxs->c_pktflags |= IEEE80211_RX_F_AMPDU; + else if (rxdw1 & R92C_RXDW1_AMPDU_MORE) + rxs->c_pktflags |= IEEE80211_RX_F_AMPDU_MORE; + if ((rxdw3 & R92C_RXDW3_SPLCP) && rate >= RTWN_RIDX_MCS(0)) + rxs->c_pktflags |= IEEE80211_RX_F_SHORTGI; + + if (rxdw3 & R92C_RXDW3_HT40) + rxs->c_width = IEEE80211_RX_FW_40MHZ; + else + rxs->c_width = IEEE80211_RX_FW_20MHZ; + + if (RTWN_RATE_IS_CCK(rate)) + rxs->c_phytype = IEEE80211_RX_FP_11B; + else if (rate < RTWN_RIDX_MCS(0)) + rxs->c_phytype = IEEE80211_RX_FP_11G; + else + rxs->c_phytype = IEEE80211_RX_FP_11NG; + + /* Map HW rate index to 802.11 rate. */ + if (rate < RTWN_RIDX_MCS(0)) { + rxs->c_rate = ridx2rate[rate]; + if (RTWN_RATE_IS_CCK(rate)) + rxs->c_pktflags |= IEEE80211_RX_F_CCK; + else + rxs->c_pktflags |= IEEE80211_RX_F_OFDM; + } else { /* MCS0~15. */ + rxs->c_rate = IEEE80211_RATE_MCS | (rate - 12); + rxs->c_pktflags |= IEEE80211_RX_F_HT; + } +} Index: head/sys/dev/rtwn/rtl8192c/r92c_rx_desc.h =================================================================== --- head/sys/dev/rtwn/rtl8192c/r92c_rx_desc.h +++ head/sys/dev/rtwn/rtl8192c/r92c_rx_desc.h @@ -45,6 +45,9 @@ uint32_t rxdw1; #define R92C_RXDW1_MACID_M 0x0000001f #define R92C_RXDW1_MACID_S 0 +#define R92C_RXDW1_AMSDU 0x00002000 +#define R92C_RXDW1_AMPDU_MORE 0x00004000 +#define R92C_RXDW1_AMPDU 0x00008000 #define R92C_RXDW1_MC 0x40000000 #define R92C_RXDW1_BC 0x80000000 @@ -56,6 +59,8 @@ #define R92C_RXDW3_SPLCP 0x00000100 #define R92C_RXDW3_HT40 0x00000200 #define R92C_RXDW3_HTC 0x00000400 +#define R92C_RXDW3_BSSID_FIT_M 0x00003000 +#define R92C_RXDW3_BSSID_FIT_S 12 uint32_t rxdw4; uint32_t tsf_low; Index: head/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c =================================================================== --- head/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c +++ head/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c @@ -165,6 +165,7 @@ sc->sc_dump_tx_desc = r92cu_dump_tx_desc; sc->sc_tx_radiotap_flags = r92c_tx_radiotap_flags; sc->sc_rx_radiotap_flags = r92c_rx_radiotap_flags; + sc->sc_get_rx_stats = r92c_get_rx_stats; sc->sc_get_rssi_cck = r92c_get_rssi_cck; sc->sc_get_rssi_ofdm = r92c_get_rssi_ofdm; sc->sc_classify_intr = r92cu_classify_intr; Index: head/sys/dev/rtwn/rtl8812a/r12a.h =================================================================== --- head/sys/dev/rtwn/rtl8812a/r12a.h +++ head/sys/dev/rtwn/rtl8812a/r12a.h @@ -128,6 +128,8 @@ void r12a_handle_c2h_report(struct rtwn_softc *, uint8_t *, int); int r12a_check_frame_checksum(struct rtwn_softc *, struct mbuf *); uint8_t r12a_rx_radiotap_flags(const void *); +void r12a_get_rx_stats(struct rtwn_softc *, struct ieee80211_rx_stats *, + const void *, const void *); /* r12a_tx.c */ void r12a_fill_tx_desc(struct rtwn_softc *, struct ieee80211_node *, Index: head/sys/dev/rtwn/rtl8812a/r12a_rx.c =================================================================== --- head/sys/dev/rtwn/rtl8812a/r12a_rx.c +++ head/sys/dev/rtwn/rtl8812a/r12a_rx.c @@ -229,10 +229,97 @@ if (!(stat->rxdw4 & htole32(R12A_RXDW4_SPLCP))) return (0); - rate = MS(le32toh(stat->rxdw3), R92C_RXDW3_RATE); + rate = MS(le32toh(stat->rxdw3), R12A_RXDW3_RATE); if (RTWN_RATE_IS_CCK(rate)) flags = IEEE80211_RADIOTAP_F_SHORTPRE; else flags = IEEE80211_RADIOTAP_F_SHORTGI; return (flags); } + +void +r12a_get_rx_stats(struct rtwn_softc *sc, struct ieee80211_rx_stats *rxs, + const void *desc, const void *physt_ptr) +{ + const struct r92c_rx_stat *stat = desc; + const struct r12a_rx_phystat *physt = physt_ptr; + uint32_t rxdw0, rxdw1, rxdw3, rxdw4; + uint8_t rate; + + rxdw0 = le32toh(stat->rxdw0); + rxdw1 = le32toh(stat->rxdw1); + rxdw3 = le32toh(stat->rxdw3); + rxdw4 = le32toh(stat->rxdw4); + rate = MS(rxdw3, R12A_RXDW3_RATE); + + /* TODO: STBC, LDPC */ + if (rxdw1 & R12A_RXDW1_AMPDU) { + if (rxdw0 & R92C_RXDW0_PHYST) + rxs->c_pktflags |= IEEE80211_RX_F_AMPDU; + else + rxs->c_pktflags |= IEEE80211_RX_F_AMPDU_MORE; + } + + if ((rxdw4 & R12A_RXDW4_SPLCP) && rate >= RTWN_RIDX_MCS(0)) + rxs->c_pktflags |= IEEE80211_RX_F_SHORTGI; + + switch (MS(rxdw4, R12A_RXDW4_BW)) { + case R12A_RXDW4_BW20: + rxs->c_width = IEEE80211_RX_FW_20MHZ; + break; + case R12A_RXDW4_BW40: + rxs->c_width = IEEE80211_RX_FW_40MHZ; + break; + case R12A_RXDW4_BW80: + rxs->c_width = IEEE80211_RX_FW_80MHZ; + break; + default: + break; + } + + if (RTWN_RATE_IS_CCK(rate)) + rxs->c_phytype = IEEE80211_RX_FP_11B; + else { + int is5ghz; + + /* XXX magic */ + /* XXX check with RTL8812AU */ + is5ghz = (physt->cfosho[2] != 0x01); + + if (rate < RTWN_RIDX_MCS(0)) { + if (is5ghz) + rxs->c_phytype = IEEE80211_RX_FP_11A; + else + rxs->c_phytype = IEEE80211_RX_FP_11G; + } else { + if (is5ghz) + rxs->c_phytype = IEEE80211_RX_FP_11NA; + else + rxs->c_phytype = IEEE80211_RX_FP_11NG; + } + } + + /* Map HW rate index to 802.11 rate. */ + if (rate < RTWN_RIDX_MCS(0)) { + rxs->c_rate = ridx2rate[rate]; + if (RTWN_RATE_IS_CCK(rate)) + rxs->c_pktflags |= IEEE80211_RX_F_CCK; + else + rxs->c_pktflags |= IEEE80211_RX_F_OFDM; + } else { /* MCS0~15. */ + /* TODO: VHT rates */ + rxs->c_rate = IEEE80211_RATE_MCS | (rate - 12); + rxs->c_pktflags |= IEEE80211_RX_F_HT; + } + + /* + * XXX always zero for RTL8821AU + * (vendor driver does not check this field) + */ +#if 0 + rxs->r_flags |= IEEE80211_R_IEEE | IEEE80211_R_FREQ; + rxs->c_ieee = MS(le16toh(physt->phyw1), R12A_PHYW1_CHAN); + rxs->c_freq = ieee80211_ieee2mhz(rxs->c_ieee, + (rxs->c_ieee < 36) ? IEEE80211_CHAN_2GHZ : IEEE80211_CHAN_5GHZ); +#endif +} Index: head/sys/dev/rtwn/rtl8812a/r12a_rx_desc.h =================================================================== --- head/sys/dev/rtwn/rtl8812a/r12a_rx_desc.h +++ head/sys/dev/rtwn/rtl8812a/r12a_rx_desc.h @@ -34,18 +34,26 @@ /* Rx MAC descriptor defines (chip-specific). */ /* Rx dword 1 */ #define R12A_RXDW1_AMSDU 0x00002000 +#define R12A_RXDW1_AMPDU 0x00008000 #define R12A_RXDW1_CKSUM_ERR 0x00100000 #define R12A_RXDW1_IPV6 0x00200000 #define R12A_RXDW1_UDP 0x00400000 #define R12A_RXDW1_CKSUM 0x00800000 /* Rx dword 2 */ #define R12A_RXDW2_RPT_C2H 0x10000000 +/* Rx dword 3 */ +#define R12A_RXDW3_RATE_M 0x0000007f +#define R12A_RXDW3_RATE_S 0 /* Rx dword 4 */ #define R12A_RXDW4_SPLCP 0x00000001 #define R12A_RXDW4_LDPC 0x00000002 #define R12A_RXDW4_STBC 0x00000004 #define R12A_RXDW4_BW_M 0x00000030 #define R12A_RXDW4_BW_S 4 +#define R12A_RXDW4_BW20 0 +#define R12A_RXDW4_BW40 1 +#define R12A_RXDW4_BW80 2 +#define R12A_RXDW4_BW160 3 /* Rx PHY descriptor. */ struct r12a_rx_phystat { Index: head/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c =================================================================== --- head/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c +++ head/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c @@ -190,6 +190,7 @@ sc->sc_dump_tx_desc = r12au_dump_tx_desc; sc->sc_tx_radiotap_flags = r12a_tx_radiotap_flags; sc->sc_rx_radiotap_flags = r12a_rx_radiotap_flags; + sc->sc_get_rx_stats = r12a_get_rx_stats; sc->sc_get_rssi_cck = r88e_get_rssi_cck; sc->sc_get_rssi_ofdm = r88e_get_rssi_ofdm; sc->sc_classify_intr = r12au_classify_intr; Index: head/sys/dev/rtwn/rtl8821a/usb/r21au_attach.c =================================================================== --- head/sys/dev/rtwn/rtl8821a/usb/r21au_attach.c +++ head/sys/dev/rtwn/rtl8821a/usb/r21au_attach.c @@ -182,6 +182,7 @@ sc->sc_dump_tx_desc = r12au_dump_tx_desc; sc->sc_tx_radiotap_flags = r12a_tx_radiotap_flags; sc->sc_rx_radiotap_flags = r12a_rx_radiotap_flags; + sc->sc_get_rx_stats = r12a_get_rx_stats; sc->sc_get_rssi_cck = r21a_get_rssi_cck; sc->sc_get_rssi_ofdm = r88e_get_rssi_ofdm; sc->sc_classify_intr = r12au_classify_intr; Index: head/sys/dev/rtwn/usb/rtwn_usb_rx.c =================================================================== --- head/sys/dev/rtwn/usb/rtwn_usb_rx.c +++ head/sys/dev/rtwn/usb/rtwn_usb_rx.c @@ -236,7 +236,7 @@ } static struct ieee80211_node * -rtwn_rx_frame(struct rtwn_softc *sc, struct mbuf *m, int8_t *rssi) +rtwn_rx_frame(struct rtwn_softc *sc, struct mbuf *m) { struct r92c_rx_stat stat; @@ -244,7 +244,7 @@ m_copydata(m, 0, sizeof(struct r92c_rx_stat), (caddr_t)&stat); m_adj(m, sizeof(struct r92c_rx_stat)); - return (rtwn_rx_common(sc, m, &stat, rssi)); + return (rtwn_rx_common(sc, m, &stat)); } void @@ -256,7 +256,6 @@ struct ieee80211_node *ni; struct mbuf *m = NULL, *next; struct rtwn_data *data; - int8_t nf, rssi; RTWN_ASSERT_LOCKED(sc); @@ -291,19 +290,15 @@ next = m->m_next; m->m_next = NULL; - ni = rtwn_rx_frame(sc, m, &rssi); + ni = rtwn_rx_frame(sc, m); RTWN_UNLOCK(sc); - nf = RTWN_NOISE_FLOOR; if (ni != NULL) { - if (ni->ni_flags & IEEE80211_NODE_HT) - m->m_flags |= M_AMPDU; - (void)ieee80211_input(ni, m, rssi - nf, nf); + (void)ieee80211_input_mimo(ni, m); ieee80211_free_node(ni); } else { - (void)ieee80211_input_all(ic, m, - rssi - nf, nf); + (void)ieee80211_input_mimo_all(ic, m); } RTWN_LOCK(sc); m = next;