Index: head/sys/dev/rtwn/if_rtwn_ridx.h =================================================================== --- head/sys/dev/rtwn/if_rtwn_ridx.h (revision 322987) +++ head/sys/dev/rtwn/if_rtwn_ridx.h (revision 322988) @@ -1,94 +1,94 @@ /* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini * Copyright (c) 2014 Kevin Lo * Copyright (c) 2015-2016 Andriy Voskoboinyk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $FreeBSD$ */ #ifndef IF_RTWN_RIDX_H #define IF_RTWN_RIDX_H /* HW rate indices. */ #define RTWN_RIDX_CCK1 0 #define RTWN_RIDX_CCK2 1 #define RTWN_RIDX_CCK55 2 #define RTWN_RIDX_CCK11 3 #define RTWN_RIDX_OFDM6 4 #define RTWN_RIDX_OFDM9 5 #define RTWN_RIDX_OFDM12 6 #define RTWN_RIDX_OFDM18 7 #define RTWN_RIDX_OFDM24 8 #define RTWN_RIDX_OFDM36 9 #define RTWN_RIDX_OFDM48 10 #define RTWN_RIDX_OFDM54 11 -#define RTWN_RIDX_MCS(i) (12 + (i)) +#define RTWN_RIDX_HT_MCS(i) (12 + (i)) #define RTWN_RIDX_COUNT 28 #define RTWN_RIDX_UNKNOWN (uint8_t)-1 #define RTWN_RATE_IS_CCK(rate) ((rate) <= RTWN_RIDX_CCK11) #define RTWN_RATE_IS_OFDM(rate) \ ((rate) >= RTWN_RIDX_OFDM6 && (rate) != RTWN_RIDX_UNKNOWN) static const uint8_t ridx2rate[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }; static __inline uint8_t rate2ridx(uint8_t rate) { if (rate & IEEE80211_RATE_MCS) { /* 11n rates start at idx 12 */ return ((rate & 0xf) + 12); } switch (rate) { /* 11g */ case 12: return 4; case 18: return 5; case 24: return 6; case 36: return 7; case 48: return 8; case 72: return 9; case 96: return 10; case 108: return 11; /* 11b */ case 2: return 0; case 4: return 1; case 11: return 2; case 22: return 3; default: return RTWN_RIDX_UNKNOWN; } } /* XXX move to net80211 */ static __inline__ uint8_t rtwn_ctl_mcsrate(const struct ieee80211_rate_table *rt, uint8_t ridx) { uint8_t cix, rate; /* Check if we are using MCS rate. */ - KASSERT(ridx >= RTWN_RIDX_MCS(0) && ridx != RTWN_RIDX_UNKNOWN, + KASSERT(ridx >= RTWN_RIDX_HT_MCS(0) && ridx != RTWN_RIDX_UNKNOWN, ("bad mcs rate index %d", ridx)); - rate = (ridx - RTWN_RIDX_MCS(0)) | IEEE80211_RATE_MCS; + rate = (ridx - RTWN_RIDX_HT_MCS(0)) | IEEE80211_RATE_MCS; cix = rt->info[rt->rateCodeToIndex[rate]].ctlRateIndex; KASSERT(cix != (uint8_t)-1, ("rate %d (%d) has no info", rate, ridx)); return rt->info[cix].dot11Rate; } #endif /* IF_RTWN_RIDX_H */ Index: head/sys/dev/rtwn/if_rtwn_rx.c =================================================================== --- head/sys/dev/rtwn/if_rtwn_rx.c (revision 322987) +++ head/sys/dev/rtwn/if_rtwn_rx.c (revision 322988) @@ -1,517 +1,517 @@ /* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini * Copyright (c) 2014 Kevin Lo * Copyright (c) 2015-2016 Andriy Voskoboinyk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void rtwn_get_rates(struct rtwn_softc *sc, const struct ieee80211_rateset *rs, const struct ieee80211_htrateset *rs_ht, uint32_t *rates_p, int *maxrate_p, int basic_rates) { uint32_t rates; uint8_t ridx; int i, maxrate; /* Get rates mask. */ rates = 0; maxrate = 0; /* This is for 11bg */ for (i = 0; i < rs->rs_nrates; i++) { /* Convert 802.11 rate to HW rate index. */ ridx = rate2ridx(IEEE80211_RV(rs->rs_rates[i])); if (ridx == RTWN_RIDX_UNKNOWN) /* Unknown rate, skip. */ continue; if (((rs->rs_rates[i] & IEEE80211_RATE_BASIC) != 0) || !basic_rates) { rates |= 1 << ridx; if (ridx > maxrate) maxrate = ridx; } } /* If we're doing 11n, enable 11n rates */ if (rs_ht != NULL && !basic_rates) { for (i = 0; i < rs_ht->rs_nrates; i++) { if ((rs_ht->rs_rates[i] & 0x7f) > 0xf) continue; /* 11n rates start at index 12 */ - ridx = RTWN_RIDX_MCS((rs_ht->rs_rates[i]) & 0xf); + ridx = RTWN_RIDX_HT_MCS((rs_ht->rs_rates[i]) & 0xf); rates |= (1 << ridx); /* Guard against the rate table being oddly ordered */ if (ridx > maxrate) maxrate = ridx; } } RTWN_DPRINTF(sc, RTWN_DEBUG_RA, "%s: rates 0x%08X, maxrate %d\n", __func__, rates, maxrate); if (rates_p != NULL) *rates_p = rates; if (maxrate_p != NULL) *maxrate_p = maxrate; } void rtwn_set_basicrates(struct rtwn_softc *sc, uint32_t rates) { RTWN_DPRINTF(sc, RTWN_DEBUG_RA, "%s: rates 0x%08X\n", __func__, rates); rtwn_setbits_4(sc, R92C_RRSR, R92C_RRSR_RATE_BITMAP_M, rates); } static void 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 (rssi <= -100 || rssi >= 20) pwdb = 0; else if (rssi >= 0) pwdb = 100; else pwdb = 100 + rssi; if (is_cck) { /* CCK gain is smaller than OFDM/MCS gain. */ pwdb += 6; if (pwdb > 100) pwdb = 100; if (pwdb <= 14) pwdb -= 4; else if (pwdb <= 26) pwdb -= 8; else if (pwdb <= 34) pwdb -= 6; else if (pwdb <= 42) pwdb -= 2; } if (un->avg_pwdb == -1) /* Init. */ un->avg_pwdb = pwdb; else if (un->avg_pwdb < pwdb) un->avg_pwdb = ((un->avg_pwdb * 19 + pwdb) / 20) + 1; else un->avg_pwdb = ((un->avg_pwdb * 19 + pwdb) / 20); RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI, "MACID %d, PWDB %d, EMA %d\n", un->id, pwdb, un->avg_pwdb); } static int8_t rtwn_get_rssi(struct rtwn_softc *sc, void *physt, int is_cck) { int8_t rssi; if (is_cck) rssi = rtwn_get_rssi_cck(sc, physt); else /* OFDM/HT. */ rssi = rtwn_get_rssi_ofdm(sc, physt); return (rssi); } static uint32_t rtwn_get_tsf_low(struct rtwn_softc *sc, int id) { return (rtwn_read_4(sc, R92C_TSFTR(id))); } static uint32_t rtwn_get_tsf_high(struct rtwn_softc *sc, int id) { return (rtwn_read_4(sc, R92C_TSFTR(id) + 4)); } static void rtwn_get_tsf(struct rtwn_softc *sc, uint64_t *buf, int id) { /* NB: we cannot read it at once. */ *buf = rtwn_get_tsf_high(sc, id); *buf <<= 32; *buf += rtwn_get_tsf_low(sc, id); } static uint64_t rtwn_extend_rx_tsf(struct rtwn_softc *sc, const struct rtwn_rx_stat_common *stat) { uint64_t tsft; uint32_t rxdw3, tsfl, tsfl_curr; int id; rxdw3 = le32toh(stat->rxdw3); tsfl = le32toh(stat->tsf_low); id = MS(rxdw3, RTWN_RXDW3_BSSID01_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) { 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 rtwn_rx_stat_common *stat; void *physt; uint32_t rxdw0; int8_t rssi; int cipher, infosz, is_cck, pktlen, shift; stat = desc; rxdw0 = le32toh(stat->rxdw0); cipher = MS(rxdw0, RTWN_RXDW0_CIPHER); infosz = MS(rxdw0, RTWN_RXDW0_INFOSZ) * 8; pktlen = MS(rxdw0, RTWN_RXDW0_PKTLEN); shift = MS(rxdw0, RTWN_RXDW0_SHIFT); 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)) { ni = ieee80211_find_rxnode(ic, wh); if (ni != NULL && (ni->ni_flags & IEEE80211_NODE_HT)) m->m_flags |= M_AMPDU; } else ni = NULL; un = RTWN_NODE(ni); if (infosz != 0 && (rxdw0 & RTWN_RXDW0_PHYST)) physt = (void *)mtodo(m, shift); else physt = (un != NULL) ? &un->last_physt : &sc->last_physt; 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 & RTWN_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 & RTWN_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; tap->wr_flags = rtwn_rx_radiotap_flags(sc, desc); 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. */ m_adj(m, infosz + shift); return (ni); } void rtwn_adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf) { struct ieee80211vap *vap = ni->ni_vap; struct rtwn_softc *sc = vap->iv_ic->ic_softc; struct rtwn_vap *uvp = RTWN_VAP(vap); uint64_t ni_tstamp, curr_tstamp; uvp->recv_mgmt(ni, m, subtype, rxs, rssi, nf); if (vap->iv_state == IEEE80211_S_RUN && (subtype == IEEE80211_FC0_SUBTYPE_BEACON || subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) { ni_tstamp = le64toh(ni->ni_tstamp.tsf); RTWN_LOCK(sc); rtwn_get_tsf(sc, &curr_tstamp, uvp->id); RTWN_UNLOCK(sc); if (ni_tstamp >= curr_tstamp) (void) ieee80211_ibss_merge(ni); } } static uint8_t rtwn_get_multi_pos(const uint8_t maddr[]) { uint64_t mask = 0x00004d101df481b4; uint8_t pos = 0x27; /* initial value */ int i, j; for (i = 0; i < IEEE80211_ADDR_LEN; i++) for (j = (i == 0) ? 1 : 0; j < 8; j++) if ((maddr[i] >> j) & 1) pos ^= (mask >> (i * 8 + j - 1)); pos &= 0x3f; return (pos); } void rtwn_set_multi(struct rtwn_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; uint32_t mfilt[2]; RTWN_ASSERT_LOCKED(sc); /* general structure was copied from ath(4). */ if (ic->ic_allmulti == 0) { struct ieee80211vap *vap; struct ifnet *ifp; struct ifmultiaddr *ifma; /* * Merge multicast addresses to form the hardware filter. */ mfilt[0] = mfilt[1] = 0; TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { ifp = vap->iv_ifp; if_maddr_rlock(ifp); TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { caddr_t dl; uint8_t pos; dl = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); pos = rtwn_get_multi_pos(dl); mfilt[pos / 32] |= (1 << (pos % 32)); } if_maddr_runlock(ifp); } } else mfilt[0] = mfilt[1] = ~0; rtwn_write_4(sc, R92C_MAR + 0, mfilt[0]); rtwn_write_4(sc, R92C_MAR + 4, mfilt[1]); RTWN_DPRINTF(sc, RTWN_DEBUG_STATE, "%s: MC filter %08x:%08x\n", __func__, mfilt[0], mfilt[1]); } static void rtwn_rxfilter_update_mgt(struct rtwn_softc *sc) { uint16_t filter; filter = 0x7f7f; if (sc->bcn_vaps == 0) { /* STA and/or MONITOR mode vaps */ filter &= ~( R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_REQ) | R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_REQ) | R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_PROBE_REQ)); } if (sc->ap_vaps == sc->nvaps - sc->mon_vaps) { /* AP vaps only */ filter &= ~( R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_RESP) | R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_RESP)); } rtwn_write_2(sc, R92C_RXFLTMAP0, filter); } void rtwn_rxfilter_update(struct rtwn_softc *sc) { RTWN_ASSERT_LOCKED(sc); /* Filter for management frames. */ rtwn_rxfilter_update_mgt(sc); /* Update Rx filter. */ rtwn_set_promisc(sc); } void rtwn_rxfilter_init(struct rtwn_softc *sc) { RTWN_ASSERT_LOCKED(sc); /* Setup multicast filter. */ rtwn_set_multi(sc); /* Reject all control frames. */ rtwn_write_2(sc, R92C_RXFLTMAP1, 0x0000); /* Reject all data frames. */ rtwn_write_2(sc, R92C_RXFLTMAP2, 0x0000); /* Append generic Rx filter bits. */ sc->rcr |= R92C_RCR_AM | R92C_RCR_AB | R92C_RCR_APM | R92C_RCR_HTC_LOC_CTRL | R92C_RCR_APP_PHYSTS | R92C_RCR_APP_ICV | R92C_RCR_APP_MIC; /* Update dynamic Rx filter parts. */ rtwn_rxfilter_update(sc); } void rtwn_rxfilter_set(struct rtwn_softc *sc) { if (!(sc->sc_flags & RTWN_RCR_LOCKED)) rtwn_write_4(sc, R92C_RCR, sc->rcr); } void rtwn_set_rx_bssid_all(struct rtwn_softc *sc, int enable) { if (enable) sc->rcr &= ~R92C_RCR_CBSSID_BCN; else sc->rcr |= R92C_RCR_CBSSID_BCN; rtwn_rxfilter_set(sc); } void rtwn_set_promisc(struct rtwn_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; uint32_t mask_all, mask_min; RTWN_ASSERT_LOCKED(sc); mask_all = R92C_RCR_ACF | R92C_RCR_ADF | R92C_RCR_AMF | R92C_RCR_AAP; mask_min = R92C_RCR_APM; if (sc->bcn_vaps == 0) mask_min |= R92C_RCR_CBSSID_BCN; if (sc->ap_vaps == 0) mask_min |= R92C_RCR_CBSSID_DATA; if (ic->ic_promisc == 0 && sc->mon_vaps == 0) { if (sc->bcn_vaps != 0) mask_all |= R92C_RCR_CBSSID_BCN; if (sc->ap_vaps != 0) /* for Null data frames */ mask_all |= R92C_RCR_CBSSID_DATA; sc->rcr &= ~mask_all; sc->rcr |= mask_min; } else { sc->rcr &= ~mask_min; sc->rcr |= mask_all; } rtwn_rxfilter_set(sc); } Index: head/sys/dev/rtwn/rtl8188e/r88e_chan.c =================================================================== --- head/sys/dev/rtwn/rtl8188e/r88e_chan.c (revision 322987) +++ head/sys/dev/rtwn/rtl8188e/r88e_chan.c (revision 322988) @@ -1,155 +1,155 @@ /* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini * Copyright (c) 2014 Kevin Lo * Copyright (c) 2015-2016 Andriy Voskoboinyk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int r88e_get_power_group(struct rtwn_softc *sc, struct ieee80211_channel *c) { uint8_t chan; int group; chan = rtwn_chan2centieee(c); if (IEEE80211_IS_CHAN_2GHZ(c)) { if (chan <= 2) group = 0; else if (chan <= 5) group = 1; else if (chan <= 8) group = 2; else if (chan <= 11) group = 3; else if (chan <= 13) group = 4; else if (chan <= 14) group = 5; else { KASSERT(0, ("wrong 2GHz channel %d!\n", chan)); return (-1); } } else { KASSERT(0, ("wrong channel band (flags %08X)\n", c->ic_flags)); return (-1); } return (group); } void r88e_get_txpower(struct rtwn_softc *sc, int chain, struct ieee80211_channel *c, uint8_t power[RTWN_RIDX_COUNT]) { struct r92c_softc *rs = sc->sc_priv; const struct rtwn_r88e_txpwr *rt = rs->rs_txpwr; uint8_t cckpow, ofdmpow, bw20pow, htpow = 0; int max_mcs, ridx, group; /* Determine channel group. */ group = r88e_get_power_group(sc, c); if (group == -1) { /* shouldn't happen */ device_printf(sc->sc_dev, "%s: incorrect channel\n", __func__); return; } /* XXX net80211 regulatory */ - max_mcs = RTWN_RIDX_MCS(sc->ntxchains * 8 - 1); + max_mcs = RTWN_RIDX_HT_MCS(sc->ntxchains * 8 - 1); KASSERT(max_mcs <= RTWN_RIDX_COUNT, ("increase ridx limit\n")); memset(power, 0, max_mcs * sizeof(power[0])); /* Compute per-CCK rate Tx power. */ cckpow = rt->cck_tx_pwr[group]; for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++) { power[ridx] = (ridx == RTWN_RIDX_CCK2) ? cckpow - 9 : cckpow; } if (group < 5) htpow = rt->ht40_tx_pwr[group]; /* Compute per-OFDM rate Tx power. */ ofdmpow = htpow + rt->ofdm_tx_pwr_diff; for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++) power[ridx] = ofdmpow; bw20pow = htpow + rt->bw20_tx_pwr_diff; - for (ridx = RTWN_RIDX_MCS(0); ridx <= max_mcs; ridx++) + for (ridx = RTWN_RIDX_HT_MCS(0); ridx <= max_mcs; ridx++) power[ridx] = bw20pow; /* Apply max limit. */ for (ridx = RTWN_RIDX_CCK1; ridx <= max_mcs; ridx++) { if (power[ridx] > R92C_MAX_TX_PWR) power[ridx] = R92C_MAX_TX_PWR; } } void r88e_set_bw20(struct rtwn_softc *sc, uint8_t chan) { struct r92c_softc *rs = sc->sc_priv; rtwn_setbits_1(sc, R92C_BWOPMODE, 0, R92C_BWOPMODE_20MHZ); rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, R92C_RFMOD_40MHZ, 0); rtwn_bb_setbits(sc, R92C_FPGA1_RFMOD, R92C_RFMOD_40MHZ, 0); /* Select 20MHz bandwidth. */ rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, (rs->rf_chnlbw[0] & ~0xfff) | chan | R88E_RF_CHNLBW_BW20); } void r88e_set_gain(struct rtwn_softc *sc, uint8_t gain) { rtwn_bb_setbits(sc, R92C_OFDM0_AGCCORE1(0), R92C_OFDM0_AGCCORE1_GAIN_M, gain); } Index: head/sys/dev/rtwn/rtl8192c/r92c_chan.c =================================================================== --- head/sys/dev/rtwn/rtl8192c/r92c_chan.c (revision 322987) +++ head/sys/dev/rtwn/rtl8192c/r92c_chan.c (revision 322988) @@ -1,351 +1,351 @@ /* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini * Copyright (c) 2014 Kevin Lo * Copyright (c) 2016 Andriy Voskoboinyk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int r92c_get_power_group(struct rtwn_softc *sc, struct ieee80211_channel *c) { uint8_t chan; int group; chan = rtwn_chan2centieee(c); if (IEEE80211_IS_CHAN_2GHZ(c)) { if (chan <= 3) group = 0; else if (chan <= 9) group = 1; else if (chan <= 14) group = 2; else { KASSERT(0, ("wrong 2GHz channel %d!\n", chan)); return (-1); } } else { KASSERT(0, ("wrong channel band (flags %08X)\n", c->ic_flags)); return (-1); } return (group); } /* XXX recheck */ void r92c_get_txpower(struct rtwn_softc *sc, int chain, struct ieee80211_channel *c, uint8_t power[RTWN_RIDX_COUNT]) { struct r92c_softc *rs = sc->sc_priv; struct rtwn_r92c_txpwr *rt = rs->rs_txpwr; const struct rtwn_r92c_txagc *base = rs->rs_txagc; uint8_t ofdmpow, htpow, diff, max; int max_mcs, ridx, group; /* Determine channel group. */ group = r92c_get_power_group(sc, c); if (group == -1) { /* shouldn't happen */ device_printf(sc->sc_dev, "%s: incorrect channel\n", __func__); return; } /* XXX net80211 regulatory */ - max_mcs = RTWN_RIDX_MCS(sc->ntxchains * 8 - 1); + max_mcs = RTWN_RIDX_HT_MCS(sc->ntxchains * 8 - 1); KASSERT(max_mcs <= RTWN_RIDX_COUNT, ("increase ridx limit\n")); memset(power, 0, max_mcs * sizeof(power[0])); if (rs->regulatory == 0) { for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++) power[ridx] = base[chain].pwr[0][ridx]; } for (ridx = RTWN_RIDX_OFDM6; ridx < RTWN_RIDX_COUNT; ridx++) { if (rs->regulatory == 3) { power[ridx] = base[chain].pwr[0][ridx]; /* Apply vendor limits. */ if (IEEE80211_IS_CHAN_HT40(c)) max = rt->ht40_max_pwr[chain][group]; else max = rt->ht20_max_pwr[chain][group]; if (power[ridx] > max) power[ridx] = max; } else if (rs->regulatory == 1) { if (!IEEE80211_IS_CHAN_HT40(c)) power[ridx] = base[chain].pwr[group][ridx]; } else if (rs->regulatory != 2) power[ridx] = base[chain].pwr[0][ridx]; } /* Compute per-CCK rate Tx power. */ for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++) power[ridx] += rt->cck_tx_pwr[chain][group]; htpow = rt->ht40_1s_tx_pwr[chain][group]; if (sc->ntxchains > 1) { /* Apply reduction for 2 spatial streams. */ diff = rt->ht40_2s_tx_pwr_diff[chain][group]; htpow = (htpow > diff) ? htpow - diff : 0; } /* Compute per-OFDM rate Tx power. */ diff = rt->ofdm_tx_pwr_diff[chain][group]; ofdmpow = htpow + diff; /* HT->OFDM correction. */ for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++) power[ridx] += ofdmpow; /* Compute per-MCS Tx power. */ if (!IEEE80211_IS_CHAN_HT40(c)) { diff = rt->ht20_tx_pwr_diff[chain][group]; htpow += diff; /* HT40->HT20 correction. */ } - for (ridx = RTWN_RIDX_MCS(0); ridx <= max_mcs; ridx++) + for (ridx = RTWN_RIDX_HT_MCS(0); ridx <= max_mcs; ridx++) power[ridx] += htpow; /* Apply max limit. */ for (ridx = RTWN_RIDX_CCK1; ridx <= max_mcs; ridx++) { if (power[ridx] > R92C_MAX_TX_PWR) power[ridx] = R92C_MAX_TX_PWR; } } void r92c_write_txpower(struct rtwn_softc *sc, int chain, uint8_t power[RTWN_RIDX_COUNT]) { uint32_t reg; /* Write per-CCK rate Tx power. */ if (chain == 0) { reg = rtwn_bb_read(sc, R92C_TXAGC_A_CCK1_MCS32); reg = RW(reg, R92C_TXAGC_A_CCK1, power[RTWN_RIDX_CCK1]); rtwn_bb_write(sc, R92C_TXAGC_A_CCK1_MCS32, reg); reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11); reg = RW(reg, R92C_TXAGC_A_CCK2, power[RTWN_RIDX_CCK2]); reg = RW(reg, R92C_TXAGC_A_CCK55, power[RTWN_RIDX_CCK55]); reg = RW(reg, R92C_TXAGC_A_CCK11, power[RTWN_RIDX_CCK11]); rtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg); } else { reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK1_55_MCS32); reg = RW(reg, R92C_TXAGC_B_CCK1, power[RTWN_RIDX_CCK1]); reg = RW(reg, R92C_TXAGC_B_CCK2, power[RTWN_RIDX_CCK2]); reg = RW(reg, R92C_TXAGC_B_CCK55, power[RTWN_RIDX_CCK55]); rtwn_bb_write(sc, R92C_TXAGC_B_CCK1_55_MCS32, reg); reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11); reg = RW(reg, R92C_TXAGC_B_CCK11, power[RTWN_RIDX_CCK11]); rtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg); } /* Write per-OFDM rate Tx power. */ rtwn_bb_write(sc, R92C_TXAGC_RATE18_06(chain), SM(R92C_TXAGC_RATE06, power[RTWN_RIDX_OFDM6]) | SM(R92C_TXAGC_RATE09, power[RTWN_RIDX_OFDM9]) | SM(R92C_TXAGC_RATE12, power[RTWN_RIDX_OFDM12]) | SM(R92C_TXAGC_RATE18, power[RTWN_RIDX_OFDM18])); rtwn_bb_write(sc, R92C_TXAGC_RATE54_24(chain), SM(R92C_TXAGC_RATE24, power[RTWN_RIDX_OFDM24]) | SM(R92C_TXAGC_RATE36, power[RTWN_RIDX_OFDM36]) | SM(R92C_TXAGC_RATE48, power[RTWN_RIDX_OFDM48]) | SM(R92C_TXAGC_RATE54, power[RTWN_RIDX_OFDM54])); /* Write per-MCS Tx power. */ rtwn_bb_write(sc, R92C_TXAGC_MCS03_MCS00(chain), - SM(R92C_TXAGC_MCS00, power[RTWN_RIDX_MCS(0)]) | - SM(R92C_TXAGC_MCS01, power[RTWN_RIDX_MCS(1)]) | - SM(R92C_TXAGC_MCS02, power[RTWN_RIDX_MCS(2)]) | - SM(R92C_TXAGC_MCS03, power[RTWN_RIDX_MCS(3)])); + SM(R92C_TXAGC_MCS00, power[RTWN_RIDX_HT_MCS(0)]) | + SM(R92C_TXAGC_MCS01, power[RTWN_RIDX_HT_MCS(1)]) | + SM(R92C_TXAGC_MCS02, power[RTWN_RIDX_HT_MCS(2)]) | + SM(R92C_TXAGC_MCS03, power[RTWN_RIDX_HT_MCS(3)])); rtwn_bb_write(sc, R92C_TXAGC_MCS07_MCS04(chain), - SM(R92C_TXAGC_MCS04, power[RTWN_RIDX_MCS(4)]) | - SM(R92C_TXAGC_MCS05, power[RTWN_RIDX_MCS(5)]) | - SM(R92C_TXAGC_MCS06, power[RTWN_RIDX_MCS(6)]) | - SM(R92C_TXAGC_MCS07, power[RTWN_RIDX_MCS(7)])); + SM(R92C_TXAGC_MCS04, power[RTWN_RIDX_HT_MCS(4)]) | + SM(R92C_TXAGC_MCS05, power[RTWN_RIDX_HT_MCS(5)]) | + SM(R92C_TXAGC_MCS06, power[RTWN_RIDX_HT_MCS(6)]) | + SM(R92C_TXAGC_MCS07, power[RTWN_RIDX_HT_MCS(7)])); if (sc->ntxchains >= 2) { rtwn_bb_write(sc, R92C_TXAGC_MCS11_MCS08(chain), - SM(R92C_TXAGC_MCS08, power[RTWN_RIDX_MCS(8)]) | - SM(R92C_TXAGC_MCS09, power[RTWN_RIDX_MCS(9)]) | - SM(R92C_TXAGC_MCS10, power[RTWN_RIDX_MCS(10)]) | - SM(R92C_TXAGC_MCS11, power[RTWN_RIDX_MCS(11)])); + SM(R92C_TXAGC_MCS08, power[RTWN_RIDX_HT_MCS(8)]) | + SM(R92C_TXAGC_MCS09, power[RTWN_RIDX_HT_MCS(9)]) | + SM(R92C_TXAGC_MCS10, power[RTWN_RIDX_HT_MCS(10)]) | + SM(R92C_TXAGC_MCS11, power[RTWN_RIDX_HT_MCS(11)])); rtwn_bb_write(sc, R92C_TXAGC_MCS15_MCS12(chain), - SM(R92C_TXAGC_MCS12, power[RTWN_RIDX_MCS(12)]) | - SM(R92C_TXAGC_MCS13, power[RTWN_RIDX_MCS(13)]) | - SM(R92C_TXAGC_MCS14, power[RTWN_RIDX_MCS(14)]) | - SM(R92C_TXAGC_MCS15, power[RTWN_RIDX_MCS(15)])); + SM(R92C_TXAGC_MCS12, power[RTWN_RIDX_HT_MCS(12)]) | + SM(R92C_TXAGC_MCS13, power[RTWN_RIDX_HT_MCS(13)]) | + SM(R92C_TXAGC_MCS14, power[RTWN_RIDX_HT_MCS(14)]) | + SM(R92C_TXAGC_MCS15, power[RTWN_RIDX_HT_MCS(15)])); } } static void r92c_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c) { uint8_t power[RTWN_RIDX_COUNT]; int i; for (i = 0; i < sc->ntxchains; i++) { /* Compute per-rate Tx power values. */ rtwn_r92c_get_txpower(sc, i, c, power); #ifdef RTWN_DEBUG if (sc->sc_debug & RTWN_DEBUG_TXPWR) { int max_mcs, ridx; - max_mcs = RTWN_RIDX_MCS(sc->ntxchains * 8 - 1); + max_mcs = RTWN_RIDX_HT_MCS(sc->ntxchains * 8 - 1); /* Dump per-rate Tx power values. */ printf("Tx power for chain %d:\n", i); for (ridx = RTWN_RIDX_CCK1; ridx <= max_mcs; ridx++) printf("Rate %d = %u\n", ridx, power[ridx]); } #endif /* Write per-rate Tx power values to hardware. */ r92c_write_txpower(sc, i, power); } } static void r92c_set_bw40(struct rtwn_softc *sc, uint8_t chan, int prichlo) { struct r92c_softc *rs = sc->sc_priv; rtwn_setbits_1(sc, R92C_BWOPMODE, R92C_BWOPMODE_20MHZ, 0); rtwn_setbits_1(sc, R92C_RRSR + 2, 0x6f, (prichlo ? 1 : 2) << 5); rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, 0, R92C_RFMOD_40MHZ); rtwn_bb_setbits(sc, R92C_FPGA1_RFMOD, 0, R92C_RFMOD_40MHZ); /* Set CCK side band. */ rtwn_bb_setbits(sc, R92C_CCK0_SYSTEM, 0x10, (prichlo ? 0 : 1) << 4); rtwn_bb_setbits(sc, R92C_OFDM1_LSTF, 0x0c00, (prichlo ? 1 : 2) << 10); rtwn_bb_setbits(sc, R92C_FPGA0_ANAPARAM2, R92C_FPGA0_ANAPARAM2_CBW20, 0); rtwn_bb_setbits(sc, 0x818, 0x0c000000, (prichlo ? 2 : 1) << 26); /* Select 40MHz bandwidth. */ rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, (rs->rf_chnlbw[0] & ~0xfff) | chan); } void r92c_set_bw20(struct rtwn_softc *sc, uint8_t chan) { struct r92c_softc *rs = sc->sc_priv; rtwn_setbits_1(sc, R92C_BWOPMODE, 0, R92C_BWOPMODE_20MHZ); rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, R92C_RFMOD_40MHZ, 0); rtwn_bb_setbits(sc, R92C_FPGA1_RFMOD, R92C_RFMOD_40MHZ, 0); rtwn_bb_setbits(sc, R92C_FPGA0_ANAPARAM2, 0, R92C_FPGA0_ANAPARAM2_CBW20); /* Select 20MHz bandwidth. */ rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, (rs->rf_chnlbw[0] & ~0xfff) | chan | R92C_RF_CHNLBW_BW20); } void r92c_set_chan(struct rtwn_softc *sc, struct ieee80211_channel *c) { struct r92c_softc *rs = sc->sc_priv; u_int chan; int i; chan = rtwn_chan2centieee(c); /* Set Tx power for this new channel. */ r92c_set_txpower(sc, c); for (i = 0; i < sc->nrxchains; i++) { rtwn_rf_write(sc, i, R92C_RF_CHNLBW, RW(rs->rf_chnlbw[i], R92C_RF_CHNLBW_CHNL, chan)); } if (IEEE80211_IS_CHAN_HT40(c)) r92c_set_bw40(sc, chan, IEEE80211_IS_CHAN_HT40U(c)); else rtwn_r92c_set_bw20(sc, chan); } void r92c_set_gain(struct rtwn_softc *sc, uint8_t gain) { rtwn_bb_setbits(sc, R92C_OFDM0_AGCCORE1(0), R92C_OFDM0_AGCCORE1_GAIN_M, gain); rtwn_bb_setbits(sc, R92C_OFDM0_AGCCORE1(1), R92C_OFDM0_AGCCORE1_GAIN_M, gain); } void r92c_scan_start(struct ieee80211com *ic) { struct rtwn_softc *sc = ic->ic_softc; struct r92c_softc *rs = sc->sc_priv; RTWN_LOCK(sc); /* Set gain for scanning. */ rtwn_r92c_set_gain(sc, 0x20); RTWN_UNLOCK(sc); rs->rs_scan_start(ic); } void r92c_scan_end(struct ieee80211com *ic) { struct rtwn_softc *sc = ic->ic_softc; struct r92c_softc *rs = sc->sc_priv; RTWN_LOCK(sc); /* Set gain under link. */ rtwn_r92c_set_gain(sc, 0x32); RTWN_UNLOCK(sc); rs->rs_scan_end(ic); } Index: head/sys/dev/rtwn/rtl8192c/r92c_fw.c =================================================================== --- head/sys/dev/rtwn/rtl8192c/r92c_fw.c (revision 322987) +++ head/sys/dev/rtwn/rtl8192c/r92c_fw.c (revision 322988) @@ -1,520 +1,520 @@ /* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini * Copyright (c) 2014 Kevin Lo * Copyright (c) 2015-2016 Andriy Voskoboinyk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef RTWN_WITHOUT_UCODE static int r92c_fw_cmd(struct rtwn_softc *sc, uint8_t id, const void *buf, int len) { struct r92c_fw_cmd cmd; int ntries, error; KASSERT(len <= sizeof(cmd.msg), ("%s: firmware command too long (%d > %zu)\n", __func__, len, sizeof(cmd.msg))); if (!(sc->sc_flags & RTWN_FW_LOADED)) { RTWN_DPRINTF(sc, RTWN_DEBUG_FIRMWARE, "%s: firmware " "was not loaded; command (id %u) will be discarded\n", __func__, id); return (0); } /* Wait for current FW box to be empty. */ for (ntries = 0; ntries < 100; ntries++) { if (!(rtwn_read_1(sc, R92C_HMETFR) & (1 << sc->fwcur))) break; rtwn_delay(sc, 2000); } if (ntries == 100) { device_printf(sc->sc_dev, "could not send firmware command\n"); return (ETIMEDOUT); } memset(&cmd, 0, sizeof(cmd)); cmd.id = id; if (len > 3) { /* Ext command: [id : byte2 : byte3 : byte4 : byte0 : byte1] */ cmd.id |= R92C_CMD_FLAG_EXT; memcpy(cmd.msg, (const uint8_t *)buf + 2, len - 2); memcpy(cmd.msg + 3, buf, 2); } else memcpy(cmd.msg, buf, len); /* Write the first word last since that will trigger the FW. */ if (len > 3) { error = rtwn_write_2(sc, R92C_HMEBOX_EXT(sc->fwcur), *(uint16_t *)((uint8_t *)&cmd + 4)); if (error != 0) return (error); } error = rtwn_write_4(sc, R92C_HMEBOX(sc->fwcur), *(uint32_t *)&cmd); if (error != 0) return (error); sc->fwcur = (sc->fwcur + 1) % R92C_H2C_NBOX; return (0); } void r92c_fw_reset(struct rtwn_softc *sc, int reason) { int ntries; if (reason == RTWN_FW_RESET_CHECKSUM) return; /* Tell 8051 to reset itself. */ rtwn_write_1(sc, R92C_HMETFR + 3, 0x20); /* Wait until 8051 resets by itself. */ for (ntries = 0; ntries < 100; ntries++) { if ((rtwn_read_2(sc, R92C_SYS_FUNC_EN) & R92C_SYS_FUNC_EN_CPUEN) == 0) return; rtwn_delay(sc, 50); } /* Force 8051 reset. */ rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_CPUEN, 0, 1); } void r92c_fw_download_enable(struct rtwn_softc *sc, int enable) { if (enable) { /* 8051 enable. */ rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, 0, R92C_SYS_FUNC_EN_CPUEN, 1); /* MCU firmware download enable. */ rtwn_setbits_1(sc, R92C_MCUFWDL, 0, R92C_MCUFWDL_EN); /* 8051 reset. */ rtwn_setbits_1_shift(sc, R92C_MCUFWDL, R92C_MCUFWDL_ROM_DLEN, 0, 2); } else { /* MCU download disable. */ rtwn_setbits_1(sc, R92C_MCUFWDL, R92C_MCUFWDL_EN, 0); /* Reserved for f/w extension. */ rtwn_write_1(sc, R92C_MCUFWDL + 1, 0); } } #endif /* * Initialize firmware rate adaptation. */ #ifndef RTWN_WITHOUT_UCODE static int r92c_send_ra_cmd(struct rtwn_softc *sc, int macid, uint32_t rates, int maxrate) { struct r92c_fw_cmd_macid_cfg cmd; uint8_t mode; int error = 0; /* XXX should be called directly from iv_newstate() for MACID_BC */ /* XXX joinbss, not send_ra_cmd() */ #ifdef RTWN_TODO /* NB: group addressed frames are done at 11bg rates for now */ if (ic->ic_curmode == IEEE80211_MODE_11B) mode = R92C_RAID_11B; else mode = R92C_RAID_11BG; /* XXX misleading 'mode' value here for unicast frames */ RTWN_DPRINTF(sc, RTWN_DEBUG_RA, "%s: mode 0x%x, rates 0x%08x, basicrates 0x%08x\n", __func__, mode, rates, basicrates); /* Set rates mask for group addressed frames. */ cmd.macid = RTWN_MACID_BC | R92C_CMD_MACID_VALID; cmd.mask = htole32(mode << 28 | basicrates); error = rtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd)); if (error != 0) { device_printf(sc->sc_dev, "could not set RA mask for broadcast station\n"); return (error); } #endif /* Set rates mask for unicast frames. */ - if (maxrate >= RTWN_RIDX_MCS(0)) + if (maxrate >= RTWN_RIDX_HT_MCS(0)) mode = R92C_RAID_11GN; else if (maxrate >= RTWN_RIDX_OFDM6) mode = R92C_RAID_11BG; else mode = R92C_RAID_11B; cmd.macid = macid | R92C_CMD_MACID_VALID; cmd.mask = htole32(mode << 28 | rates); error = r92c_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd)); if (error != 0) { device_printf(sc->sc_dev, "%s: could not set RA mask for %d station\n", __func__, macid); return (error); } return (0); } #endif static void r92c_init_ra(struct rtwn_softc *sc, int macid) { struct ieee80211_htrateset *rs_ht; struct ieee80211_node *ni; uint32_t rates; int maxrate; RTWN_NT_LOCK(sc); if (sc->node_list[macid] == NULL) { RTWN_DPRINTF(sc, RTWN_DEBUG_RA, "%s: macid %d, ni is NULL\n", __func__, macid); RTWN_NT_UNLOCK(sc); return; } ni = ieee80211_ref_node(sc->node_list[macid]); if (ni->ni_flags & IEEE80211_NODE_HT) rs_ht = &ni->ni_htrates; else rs_ht = NULL; /* XXX MACID_BC */ rtwn_get_rates(sc, &ni->ni_rates, rs_ht, &rates, &maxrate, 0); RTWN_NT_UNLOCK(sc); #ifndef RTWN_WITHOUT_UCODE if (sc->sc_ratectl == RTWN_RATECTL_FW) { r92c_send_ra_cmd(sc, macid, rates, maxrate); } #endif rtwn_write_1(sc, R92C_INIDATA_RATE_SEL(macid), maxrate); ieee80211_free_node(ni); } void r92c_joinbss_rpt(struct rtwn_softc *sc, int macid) { #ifndef RTWN_WITHOUT_UCODE struct r92c_softc *rs = sc->sc_priv; struct ieee80211vap *vap; struct r92c_fw_cmd_joinbss_rpt cmd; if (sc->vaps[0] == NULL) /* XXX fix */ goto end; vap = &sc->vaps[0]->vap; if ((vap->iv_state == IEEE80211_S_RUN) ^ !(rs->rs_flags & R92C_FLAG_ASSOCIATED)) goto end; if (rs->rs_flags & R92C_FLAG_ASSOCIATED) { cmd.mstatus = R92C_MSTATUS_DISASSOC; rs->rs_flags &= ~R92C_FLAG_ASSOCIATED; } else { cmd.mstatus = R92C_MSTATUS_ASSOC; rs->rs_flags |= R92C_FLAG_ASSOCIATED; } if (r92c_fw_cmd(sc, R92C_CMD_JOINBSS_RPT, &cmd, sizeof(cmd)) != 0) { device_printf(sc->sc_dev, "%s: cannot change media status!\n", __func__); } end: #endif /* TODO: init rates for RTWN_MACID_BC. */ if (macid & RTWN_MACID_VALID) r92c_init_ra(sc, macid & ~RTWN_MACID_VALID); } #ifndef RTWN_WITHOUT_UCODE int r92c_set_rsvd_page(struct rtwn_softc *sc, int probe_resp, int null, int qos_null) { struct r92c_fw_cmd_rsvdpage rsvd; rsvd.probe_resp = probe_resp; rsvd.ps_poll = 0; rsvd.null_data = null; return (r92c_fw_cmd(sc, R92C_CMD_RSVD_PAGE, &rsvd, sizeof(rsvd))); } int r92c_set_pwrmode(struct rtwn_softc *sc, struct ieee80211vap *vap, int off) { struct r92c_fw_cmd_pwrmode mode; int error; /* XXX dm_RF_saving */ if (off && vap->iv_state == IEEE80211_S_RUN && (vap->iv_flags & IEEE80211_F_PMGTON)) mode.mode = R92C_PWRMODE_MIN; else mode.mode = R92C_PWRMODE_CAM; mode.smart_ps = R92C_PWRMODE_SMARTPS_NULLDATA; mode.bcn_pass = 1; /* XXX */ error = r92c_fw_cmd(sc, R92C_CMD_SET_PWRMODE, &mode, sizeof(mode)); if (error != 0) { device_printf(sc->sc_dev, "%s: CMD_SET_PWRMODE was not sent, error %d\n", __func__, error); } return (error); } void r92c_set_rssi(struct rtwn_softc *sc) { struct ieee80211_node *ni; struct rtwn_node *rn; struct r92c_fw_cmd_rssi cmd; int i; cmd.reserved = 0; RTWN_NT_LOCK(sc); for (i = 0; i < sc->macid_limit; i++) { /* XXX optimize? */ ni = sc->node_list[i]; if (ni == NULL) continue; rn = RTWN_NODE(ni); cmd.macid = i; cmd.pwdb = rn->avg_pwdb; RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI, "%s: sending RSSI command (macid %d, rssi %d)\n", __func__, i, rn->avg_pwdb); RTWN_NT_UNLOCK(sc); r92c_fw_cmd(sc, R92C_CMD_RSSI_SETTING, &cmd, sizeof(cmd)); RTWN_NT_LOCK(sc); } RTWN_NT_UNLOCK(sc); } static void r92c_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len) { #if __FreeBSD_version >= 1200012 struct ieee80211_ratectl_tx_status txs; #endif struct r92c_c2h_tx_rpt *rpt; struct ieee80211_node *ni; uint8_t macid; int ntries; if (sc->sc_ratectl != RTWN_RATECTL_NET80211) { /* shouldn't happen */ device_printf(sc->sc_dev, "%s called while ratectl = %d!\n", __func__, sc->sc_ratectl); return; } rpt = (struct r92c_c2h_tx_rpt *)buf; if (len != sizeof(*rpt)) { device_printf(sc->sc_dev, "%s: wrong report size (%d, must be %zu)\n", __func__, len, sizeof(*rpt)); return; } RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: ccx report dump: 0: %02X, 1: %02X, queue time: " "low %02X, high %02X, 4: %02X, 5: %02X, 6: %02X, 7: %02X\n", __func__, rpt->rptb0, rpt->rptb1, rpt->queue_time_low, rpt->queue_time_high, rpt->rptb4, rpt->rptb5, rpt->rptb6, rpt->rptb7); macid = MS(rpt->rptb5, R92C_RPTB5_MACID); if (macid > sc->macid_limit) { device_printf(sc->sc_dev, "macid %u is too big; increase MACID_MAX limit\n", macid); return; } ntries = MS(rpt->rptb0, R92C_RPTB0_RETRY_CNT); RTWN_NT_LOCK(sc); ni = sc->node_list[macid]; if (ni != NULL) { RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: frame for macid %u was" "%s sent (%d retries)\n", __func__, macid, (rpt->rptb7 & R92C_RPTB7_PKT_OK) ? "" : " not", ntries); #if __FreeBSD_version >= 1200012 txs.flags = IEEE80211_RATECTL_STATUS_LONG_RETRY; txs.long_retries = ntries; if (rpt->rptb7 & R92C_RPTB7_PKT_OK) txs.status = IEEE80211_RATECTL_TX_SUCCESS; else if (rpt->rptb6 & R92C_RPTB6_RETRY_OVER) txs.status = IEEE80211_RATECTL_TX_FAIL_LONG; /* XXX */ else if (rpt->rptb6 & R92C_RPTB6_LIFE_EXPIRE) txs.status = IEEE80211_RATECTL_TX_FAIL_EXPIRED; else txs.status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED; ieee80211_ratectl_tx_complete(ni, &txs); #else struct ieee80211vap *vap = ni->ni_vap; if (rpt->rptb7 & R92C_RPTB7_PKT_OK) { ieee80211_ratectl_tx_complete(vap, ni, IEEE80211_RATECTL_TX_SUCCESS, &ntries, NULL); } else { ieee80211_ratectl_tx_complete(vap, ni, IEEE80211_RATECTL_TX_FAILURE, &ntries, NULL); } #endif } else { RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: macid %u, ni is NULL\n", __func__, macid); } RTWN_NT_UNLOCK(sc); #ifdef IEEE80211_SUPPORT_SUPERG if (sc->sc_tx_n_active > 0 && --sc->sc_tx_n_active <= 1) rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all); #endif } static void r92c_handle_c2h_task(struct rtwn_softc *sc, union sec_param *data) { const uint16_t off = R92C_C2H_EVT_MSG + sizeof(struct r92c_c2h_evt); struct r92c_softc *rs = sc->sc_priv; uint16_t buf[R92C_C2H_MSG_MAX_LEN / 2 + 1]; uint8_t id, len, status; int i; /* Do not reschedule the task if device is not running. */ if (!(sc->sc_flags & RTWN_RUNNING)) return; /* Read current status. */ status = rtwn_read_1(sc, R92C_C2H_EVT_CLEAR); if (status == R92C_C2H_EVT_HOST_CLOSE) goto end; /* nothing to do */ else if (status == R92C_C2H_EVT_FW_CLOSE) { len = rtwn_read_1(sc, R92C_C2H_EVT_MSG); id = MS(len, R92C_C2H_EVTB0_ID); len = MS(len, R92C_C2H_EVTB0_LEN); memset(buf, 0, sizeof(buf)); /* Try to optimize event reads. */ for (i = 0; i < len; i += 2) buf[i / 2] = rtwn_read_2(sc, off + i); KASSERT(i < sizeof(buf), ("%s: buffer overrun (%d >= %zu)!", __func__, i, sizeof(buf))); switch (id) { case R92C_C2H_EVT_TX_REPORT: r92c_ratectl_tx_complete(sc, (uint8_t *)buf, len); break; default: device_printf(sc->sc_dev, "%s: C2H report %u (len %u) was not handled\n", __func__, id, len); break; } } /* Prepare for next event. */ rtwn_write_1(sc, R92C_C2H_EVT_CLEAR, R92C_C2H_EVT_HOST_CLOSE); end: /* Adjust timeout for next call. */ if (rs->rs_c2h_pending != 0) { rs->rs_c2h_pending = 0; rs->rs_c2h_paused = 0; } else rs->rs_c2h_paused++; if (rs->rs_c2h_paused > R92C_TX_PAUSED_THRESHOLD) rs->rs_c2h_timeout = hz; else rs->rs_c2h_timeout = MAX(hz / 100, 1); /* Reschedule the task. */ callout_reset(&rs->rs_c2h_report, rs->rs_c2h_timeout, r92c_handle_c2h_report, sc); } void r92c_handle_c2h_report(void *arg) { struct rtwn_softc *sc = arg; rtwn_cmd_sleepable(sc, NULL, 0, r92c_handle_c2h_task); } #endif /* RTWN_WITHOUT_UCODE */ Index: head/sys/dev/rtwn/rtl8192c/r92c_priv.h =================================================================== --- head/sys/dev/rtwn/rtl8192c/r92c_priv.h (revision 322987) +++ head/sys/dev/rtwn/rtl8192c/r92c_priv.h (revision 322988) @@ -1,408 +1,408 @@ /*- * Copyright (c) 2010 Damien Bergamini * Copyright (c) 2016 Andriy Voskoboinyk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ * $FreeBSD$ */ #ifndef R92C_PRIV_H #define R92C_PRIV_H #include /* * Parsed Tx power (diff) values. */ struct rtwn_r92c_txpwr { uint8_t cck_tx_pwr[R92C_MAX_CHAINS][R92C_GROUP_2G]; uint8_t ht40_1s_tx_pwr[R92C_MAX_CHAINS][R92C_GROUP_2G]; int8_t ht40_2s_tx_pwr_diff[R92C_MAX_CHAINS][R92C_GROUP_2G]; int8_t ht20_tx_pwr_diff[R92C_MAX_CHAINS][R92C_GROUP_2G]; int8_t ofdm_tx_pwr_diff[R92C_MAX_CHAINS][R92C_GROUP_2G]; int8_t ht40_max_pwr[R92C_MAX_CHAINS][R92C_GROUP_2G]; int8_t ht20_max_pwr[R92C_MAX_CHAINS][R92C_GROUP_2G]; }; /* * Baseband initialization values (shared parts). */ #define R92C_COND_RTL8188CE 0x01 #define R92C_COND_RTL8188CU 0x02 #define R92C_COND_RTL8188RU 0x04 #define R92C_COND_RTL8192CE 0x08 #define R92C_COND_RTL8192CU 0x10 /* Shortcut. */ #define R92C_COND_RTL8192C (R92C_COND_RTL8192CE | R92C_COND_RTL8192CU) static const uint16_t rtl8192c_bb_regs3[] = { 0xd04 }, rtl8192c_bb_regs4[] = { 0xd08, 0xd0c, 0xd10, 0xd14, 0xd18, 0xd2c, 0xd30, 0xd34, 0xd38, 0xd3c, 0xd40, 0xd44, 0xd48, 0xd4c, 0xd50, 0xd54, 0xd58, 0xd5c, 0xd60, 0xd64, 0xd68, 0xd6c, 0xd70, 0xd74, 0xd78, 0xe00, 0xe04, 0xe08, 0xe10, 0xe14, 0xe18, 0xe1c, 0xe28, 0xe30, 0xe34, 0xe38, 0xe3c, 0xe40, 0xe44, 0xe48, 0xe4c, 0xe50, 0xe54, 0xe58, 0xe5c }, rtl8192c_bb_regs5[] = { 0xe60, 0xe68, 0xe6c, 0xe70, 0xe74, 0xe78, 0xe7c, 0xe80, 0xe84, 0xe88, 0xe8c, 0xed0, 0xed4, 0xed8, 0xedc, 0xee0, 0xeec, 0xf14, 0xf4c, 0xf00 }; static const uint32_t rtl8192c_bb_vals3_88cu_88ru[] = { 0x00020401 }, rtl8192c_bb_vals3_92ce_92cu[] = { 0x00020403 }, rtl8192c_bb_vals4[] = { 0x0000907f, 0x20010201, 0xa0633333, 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000, 0x80608000, 0x00000000, 0x00027293, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6437140a, 0x00000000, 0x00000000, 0x30032064, 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e, 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a, 0x03902a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x00000000, 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00, 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f, 0x02140102, 0x28160d05 },rtl8192c_bb_vals5_92ce_92cu[] = { 0x00000010, 0x001b25a4, 0x63db25a4, 0x63db25a4, 0x0c1b25a4, 0x0c1b25a4, 0x0c1b25a4, 0x0c1b25a4, 0x63db25a4, 0x0c1b25a4, 0x63db25a4, 0x63db25a4, 0x63db25a4, 0x63db25a4, 0x001b25a4, 0x001b25a4, 0x6fdb25a4, 0x00000003, 0x00000000, 0x00000300 }; /* * RTL8192CU and RTL8192CE-VAU. */ static const uint32_t rtl8192ce_agc_vals[] = { 0x7b000001, 0x7b010001, 0x7b020001, 0x7b030001, 0x7b040001, 0x7b050001, 0x7a060001, 0x79070001, 0x78080001, 0x77090001, 0x760a0001, 0x750b0001, 0x740c0001, 0x730d0001, 0x720e0001, 0x710f0001, 0x70100001, 0x6f110001, 0x6e120001, 0x6d130001, 0x6c140001, 0x6b150001, 0x6a160001, 0x69170001, 0x68180001, 0x67190001, 0x661a0001, 0x651b0001, 0x641c0001, 0x631d0001, 0x621e0001, 0x611f0001, 0x60200001, 0x49210001, 0x48220001, 0x47230001, 0x46240001, 0x45250001, 0x44260001, 0x43270001, 0x42280001, 0x41290001, 0x402a0001, 0x262b0001, 0x252c0001, 0x242d0001, 0x232e0001, 0x222f0001, 0x21300001, 0x20310001, 0x06320001, 0x05330001, 0x04340001, 0x03350001, 0x02360001, 0x01370001, 0x00380001, 0x00390001, 0x003a0001, 0x003b0001, 0x003c0001, 0x003d0001, 0x003e0001, 0x003f0001, 0x7b400001, 0x7b410001, 0x7b420001, 0x7b430001, 0x7b440001, 0x7b450001, 0x7a460001, 0x79470001, 0x78480001, 0x77490001, 0x764a0001, 0x754b0001, 0x744c0001, 0x734d0001, 0x724e0001, 0x714f0001, 0x70500001, 0x6f510001, 0x6e520001, 0x6d530001, 0x6c540001, 0x6b550001, 0x6a560001, 0x69570001, 0x68580001, 0x67590001, 0x665a0001, 0x655b0001, 0x645c0001, 0x635d0001, 0x625e0001, 0x615f0001, 0x60600001, 0x49610001, 0x48620001, 0x47630001, 0x46640001, 0x45650001, 0x44660001, 0x43670001, 0x42680001, 0x41690001, 0x406a0001, 0x266b0001, 0x256c0001, 0x246d0001, 0x236e0001, 0x226f0001, 0x21700001, 0x20710001, 0x06720001, 0x05730001, 0x04740001, 0x03750001, 0x02760001, 0x01770001, 0x00780001, 0x00790001, 0x007a0001, 0x007b0001, 0x007c0001, 0x007d0001, 0x007e0001, 0x007f0001, 0x3800001e, 0x3801001e, 0x3802001e, 0x3803001e, 0x3804001e, 0x3805001e, 0x3806001e, 0x3807001e, 0x3808001e, 0x3c09001e, 0x3e0a001e, 0x400b001e, 0x440c001e, 0x480d001e, 0x4c0e001e, 0x500f001e, 0x5210001e, 0x5611001e, 0x5a12001e, 0x5e13001e, 0x6014001e, 0x6015001e, 0x6016001e, 0x6217001e, 0x6218001e, 0x6219001e, 0x621a001e, 0x621b001e, 0x621c001e, 0x621d001e, 0x621e001e, 0x621f001e }; static const struct rtwn_agc_prog rtl8192ce_agc[] = { { nitems(rtl8192ce_agc_vals), rtl8192ce_agc_vals, { 0 }, NULL } }; /* * RF initialization values. */ static const uint8_t rtl8192c_rf0_regs0[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21 }, rtl8192c_rf0_regs1[] = { 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28 }, rtl8192c_rf0_regs2[] = { 0x29, 0x2a, 0x2b, 0x2a, 0x2b, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11 }, rtl8192c_rf0_regs3[] = { 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13 }, rtl8192c_rf0_regs4[] = { 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15 }, rtl8192c_rf0_regs5[] = { 0x16, 0x16, 0x16, 0x16, 0x00, 0x18, 0xfe, 0xfe, 0x1f, 0xfe, 0xfe, 0x1e, 0x1f, 0x00 }; static const uint32_t rtl8192c_rf0_vals0_88ce_88cu_92ce[] = { 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb1, 0x54867, 0x8992e, 0x0e52c, 0x39ce7, 0x00451, 0x00000, 0x10255, 0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000 }, rtl8192c_rf0_vals0_88ru[] = { 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb0, 0x54867, 0x8992e, 0x0e529, 0x39ce7, 0x00451, 0x00000, 0x00255, 0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000 }, rtl8192c_rf0_vals1_88ru[] = { 0x0083c, 0x01558, 0x00060, 0x00483, 0x4f000, 0xec7d9, 0x977c0 }, rtl8192c_rf0_vals1_88ce[] = { 0x00000, 0x01558, 0x00060, 0x00483, 0x4f200, 0xec7d9, 0x577c0 }, rtl8192c_rf0_vals1_88cu_92ce[] = { 0x00000, 0x01558, 0x00060, 0x00483, 0x4f000, 0xec7d9, 0x577c0 }, rtl8192c_rf0_vals2[] = { 0x04783, 0x00001, 0x21334, 0x00000, 0x00054, 0x00001, 0x00808, 0x53333, 0x0000c, 0x00002, 0x00808, 0x5b333, 0x0000d, 0x00003, 0x00808, 0x63333, 0x0000d, 0x00004, 0x00808, 0x6b333, 0x0000d, 0x00005, 0x00808, 0x73333, 0x0000d, 0x00006, 0x00709, 0x5b333, 0x0000d, 0x00007, 0x00709, 0x63333, 0x0000d, 0x00008, 0x0060a, 0x4b333, 0x0000d, 0x00009, 0x0060a, 0x53333, 0x0000d, 0x0000a, 0x0060a, 0x5b333, 0x0000d, 0x0000b, 0x0060a, 0x63333, 0x0000d, 0x0000c, 0x0060a, 0x6b333, 0x0000d, 0x0000d, 0x0060a, 0x73333, 0x0000d, 0x0000e, 0x0050b, 0x66666, 0x0001a, 0xe0000, 0x4000f, 0xe31fc, 0x6000f, 0xff9f8, 0x2000f, 0x203f9, 0x3000f, 0xff500, 0x00000, 0x00000, 0x8000f, 0x3f100, 0x9000f, 0x23100 }, rtl8192c_rf0_vals3_88ru[] = { 0xd8000, 0x90000, 0x51000, 0x12000, 0x28fb4, 0x24fa8, 0x207a4, 0x1c798, 0x183a4, 0x14398, 0x101a4, 0x0c198, 0x080a4, 0x04098, 0x00014 }, rtl8192c_rf0_vals3_92ce[] = { 0x32000, 0x71000, 0xb0000, 0xfc000, 0x287af, 0x244b7, 0x204ab, 0x1c49f, 0x18493, 0x14297, 0x10295, 0x0c298, 0x0819c, 0x040a8, 0x0001c }, rtl8192c_rf0_vals3_88cu_88ce[] = { 0x32000, 0x71000, 0xb0000, 0xfc000, 0x287b3, 0x244b7, 0x204ab, 0x1c49f, 0x18493, 0x1429b, 0x10299, 0x0c29c, 0x081a0, 0x040ac, 0x00020 }, rtl8192c_rf0_vals4_92ce_88ce[] = { 0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f424, 0x4f424, 0x8f424, 0xcf424 }, rtl8192c_rf0_vals4_88cu_88ru[] = { 0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f405, 0x4f405, 0x8f405, 0xcf405 }, rtl8192c_rf0_vals5[] = { 0xe0330, 0xa0330, 0x60330, 0x20330, 0x10159, 0x0f401, 0x0c350, 0x0c350, 0x80003, 0x0c350, 0x0c350, 0x44457, 0x80000, 0x30159 }; static const struct rtwn_rf_prog rtl8192c_rf[] = { /* RF chain 0 */ /* RTL8188RU. */ { nitems(rtl8192c_rf0_regs0), rtl8192c_rf0_regs0, rtl8192c_rf0_vals0_88ru, { R92C_COND_RTL8188RU }, /* Others. */ &(const struct rtwn_rf_prog){ nitems(rtl8192c_rf0_regs0), rtl8192c_rf0_regs0, rtl8192c_rf0_vals0_88ce_88cu_92ce, { 0 }, NULL } }, /* RTL8188RU. */ { nitems(rtl8192c_rf0_regs1), rtl8192c_rf0_regs1, rtl8192c_rf0_vals1_88ru, { R92C_COND_RTL8188RU }, /* RTL8188CE. */ &(const struct rtwn_rf_prog){ nitems(rtl8192c_rf0_regs1), rtl8192c_rf0_regs1, rtl8192c_rf0_vals1_88ce, { R92C_COND_RTL8188CE }, /* Others. */ &(const struct rtwn_rf_prog){ nitems(rtl8192c_rf0_regs1), rtl8192c_rf0_regs1, rtl8192c_rf0_vals1_88cu_92ce, { 0 }, NULL } } }, { nitems(rtl8192c_rf0_regs2), rtl8192c_rf0_regs2, rtl8192c_rf0_vals2, { 0 }, NULL }, /* RTL8188RU. */ { nitems(rtl8192c_rf0_regs3), rtl8192c_rf0_regs3, rtl8192c_rf0_vals3_88ru, { R92C_COND_RTL8188RU }, /* RTL8192C. */ &(const struct rtwn_rf_prog){ nitems(rtl8192c_rf0_regs3), rtl8192c_rf0_regs3, rtl8192c_rf0_vals3_92ce, { R92C_COND_RTL8192C }, /* Others. */ &(struct rtwn_rf_prog){ nitems(rtl8192c_rf0_regs3), rtl8192c_rf0_regs3, rtl8192c_rf0_vals3_88cu_88ce, { 0 }, NULL } } }, /* RTL8188CE / RTL8192C. */ { nitems(rtl8192c_rf0_regs4), rtl8192c_rf0_regs4, rtl8192c_rf0_vals4_92ce_88ce, { R92C_COND_RTL8188CE | R92C_COND_RTL8192C }, /* Others. */ &(const struct rtwn_rf_prog){ nitems(rtl8192c_rf0_regs4), rtl8192c_rf0_regs4, rtl8192c_rf0_vals4_88cu_88ru, { 0 }, NULL } }, { nitems(rtl8192c_rf0_regs5), rtl8192c_rf0_regs5, rtl8192c_rf0_vals5, { 0 }, NULL }, { 0, NULL, NULL, { 0 }, NULL }, /* RF chain 1 (RTL8192C). */ { 12, /* 0x00 - 0x0f */ rtl8192c_rf0_regs0, rtl8192c_rf0_vals0_88ce_88cu_92ce, { 0 }, NULL }, { nitems(rtl8192c_rf0_regs3), /* 0x12 - 0x13 */ rtl8192c_rf0_regs3, rtl8192c_rf0_vals3_92ce, { 0 }, NULL }, { nitems(rtl8192c_rf0_regs4), /* 0x14 - 0x15 */ rtl8192c_rf0_regs4, rtl8192c_rf0_vals4_92ce_88ce, { 0 }, NULL }, { 4, /* 0x16 */ rtl8192c_rf0_regs5, rtl8192c_rf0_vals5, { 0 }, NULL }, { 0, NULL, NULL, { 0 }, NULL } }; struct rtwn_r92c_txagc { - uint8_t pwr[R92C_GROUP_2G][28]; /* RTWN_RIDX_MCS(15) + 1 */ + uint8_t pwr[R92C_GROUP_2G][28]; /* RTWN_RIDX_HT_MCS(15) + 1 */ }; /* * Per RF chain/group/rate Tx gain values. */ static const struct rtwn_r92c_txagc rtl8192cu_txagc[] = { { { /* Chain 0. */ { /* Group 0. */ 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ 0x0c, 0x0c, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02, /* OFDM6~54. */ 0x0e, 0x0d, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02, /* MCS0~7. */ 0x0e, 0x0d, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02 /* MCS8~15. */ }, { /* Group 1. */ 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ }, { /* Group 2. */ 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x00, /* OFDM6~54. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ } } }, { { /* Chain 1. */ { /* Group 0. */ 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ }, { /* Group 1. */ 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ }, { /* Group 2. */ 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x00, /* OFDM6~54. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ } } } }; static const struct rtwn_r92c_txagc rtl8188ru_txagc[] = { { { /* Chain 0. */ { /* Group 0. */ 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ 0x08, 0x08, 0x08, 0x06, 0x06, 0x04, 0x04, 0x00, /* OFDM6~54. */ 0x08, 0x06, 0x06, 0x04, 0x04, 0x02, 0x02, 0x00, /* MCS0~7. */ 0x08, 0x06, 0x06, 0x04, 0x04, 0x02, 0x02, 0x00 /* MCS8~15. */ }, { /* Group 1. */ 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ }, { /* Group 2. */ 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ } } } }; #endif /* R92C_PRIV_H */ Index: head/sys/dev/rtwn/rtl8192c/r92c_rx.c =================================================================== --- head/sys/dev/rtwn/rtl8192c/r92c_rx.c (revision 322987) +++ head/sys/dev/rtwn/rtl8192c/r92c_rx.c (revision 322988) @@ -1,146 +1,146 @@ /* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini * Copyright (c) 2014 Kevin Lo * Copyright (c) 2015-2016 Andriy Voskoboinyk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int8_t r92c_get_rssi_cck(struct rtwn_softc *sc, void *physt) { static const int8_t cckoff[] = { 16, -12, -26, -46 }; struct r92c_rx_cck *cck = (struct r92c_rx_cck *)physt; uint8_t rpt; int8_t rssi; if (sc->sc_flags & RTWN_FLAG_CCK_HIPWR) { rpt = (cck->agc_rpt >> 5) & 0x03; rssi = (cck->agc_rpt & 0x1f) << 1; } else { rpt = (cck->agc_rpt >> 6) & 0x03; rssi = cck->agc_rpt & 0x3e; } rssi = cckoff[rpt] - rssi; return (rssi); } int8_t r92c_get_rssi_ofdm(struct rtwn_softc *sc, void *physt) { struct r92c_rx_phystat *phy = (struct r92c_rx_phystat *)physt; int rssi; /* Get average RSSI. */ rssi = ((phy->pwdb_all >> 1) & 0x7f) - 110; return (rssi); } uint8_t r92c_rx_radiotap_flags(const void *buf) { const struct r92c_rx_stat *stat = buf; uint8_t flags, rate; if (!(stat->rxdw3 & htole32(R92C_RXDW3_SPLCP))) return (0); rate = MS(le32toh(stat->rxdw3), R92C_RXDW3_RATE); if (RTWN_RATE_IS_CCK(rate)) flags = IEEE80211_RADIOTAP_F_SHORTPRE; else 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)) + if ((rxdw3 & R92C_RXDW3_SPLCP) && rate >= RTWN_RIDX_HT_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)) + else if (rate < RTWN_RIDX_HT_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)) { + if (rate < RTWN_RIDX_HT_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_tx.c =================================================================== --- head/sys/dev/rtwn/rtl8192c/r92c_tx.c (revision 322987) +++ head/sys/dev/rtwn/rtl8192c/r92c_tx.c (revision 322988) @@ -1,434 +1,434 @@ /* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini * Copyright (c) 2014 Kevin Lo * Copyright (c) 2015-2016 Andriy Voskoboinyk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int r92c_tx_get_sco(struct rtwn_softc *sc, struct ieee80211_channel *c) { if (IEEE80211_IS_CHAN_HT40U(c)) return (R92C_TXDW4_SCO_SCA); else return (R92C_TXDW4_SCO_SCB); } static void r92c_tx_set_ht40(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) { struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; if (ni->ni_chan != IEEE80211_CHAN_ANYC && IEEE80211_IS_CHAN_HT40(ni->ni_chan)) { int extc_offset; extc_offset = r92c_tx_get_sco(sc, ni->ni_chan); txd->txdw4 |= htole32(R92C_TXDW4_DATA_BW40); txd->txdw4 |= htole32(SM(R92C_TXDW4_DATA_SCO, extc_offset)); } } static void r92c_tx_protection(struct rtwn_softc *sc, struct r92c_tx_desc *txd, enum ieee80211_protmode mode, uint8_t ridx) { struct ieee80211com *ic = &sc->sc_ic; uint8_t rate; switch (mode) { case IEEE80211_PROT_CTSONLY: txd->txdw4 |= htole32(R92C_TXDW4_CTS2SELF); break; case IEEE80211_PROT_RTSCTS: txd->txdw4 |= htole32(R92C_TXDW4_RTSEN); break; default: break; } if (mode == IEEE80211_PROT_CTSONLY || mode == IEEE80211_PROT_RTSCTS) { - if (ridx >= RTWN_RIDX_MCS(0)) + if (ridx >= RTWN_RIDX_HT_MCS(0)) rate = rtwn_ctl_mcsrate(ic->ic_rt, ridx); else rate = ieee80211_ctl_rate(ic->ic_rt, ridx2rate[ridx]); ridx = rate2ridx(rate); txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, ridx)); /* RTS rate fallback limit (max). */ txd->txdw5 |= htole32(SM(R92C_TXDW5_RTSRATE_FB_LMT, 0xf)); if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) txd->txdw4 |= htole32(R92C_TXDW4_RTS_SHORT); } } static void r92c_tx_raid(struct rtwn_softc *sc, struct r92c_tx_desc *txd, struct ieee80211_node *ni, int ismcast) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_channel *chan; enum ieee80211_phymode mode; uint8_t raid; chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ? ni->ni_chan : ic->ic_curchan; mode = ieee80211_chan2mode(chan); /* NB: group addressed frames are done at 11bg rates for now */ if (ismcast || !(ni->ni_flags & IEEE80211_NODE_HT)) { switch (mode) { case IEEE80211_MODE_11B: case IEEE80211_MODE_11G: break; case IEEE80211_MODE_11NG: mode = IEEE80211_MODE_11G; break; default: device_printf(sc->sc_dev, "unknown mode(1) %d!\n", ic->ic_curmode); return; } } switch (mode) { case IEEE80211_MODE_11B: raid = R92C_RAID_11B; break; case IEEE80211_MODE_11G: if (vap->iv_flags & IEEE80211_F_PUREG) raid = R92C_RAID_11G; else raid = R92C_RAID_11BG; break; case IEEE80211_MODE_11NG: if (vap->iv_flags_ht & IEEE80211_FHT_PUREN) raid = R92C_RAID_11N; else raid = R92C_RAID_11BGN; break; default: device_printf(sc->sc_dev, "unknown mode(2) %d!\n", mode); return; } txd->txdw1 |= htole32(SM(R92C_TXDW1_RAID, raid)); } /* XXX move to device-independent layer */ static void r92c_tx_set_sgi(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) { struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; struct ieee80211vap *vap = ni->ni_vap; if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) && /* HT20 */ (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20)) txd->txdw5 |= htole32(R92C_TXDW5_SGI); else if (ni->ni_chan != IEEE80211_CHAN_ANYC && /* HT40 */ IEEE80211_IS_CHAN_HT40(ni->ni_chan) && (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) && (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40)) txd->txdw5 |= htole32(R92C_TXDW5_SGI); } void r92c_tx_enable_ampdu(void *buf, int enable) { struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; if (enable) txd->txdw1 |= htole32(R92C_TXDW1_AGGEN); else txd->txdw1 |= htole32(R92C_TXDW1_AGGBK); } void r92c_tx_setup_hwseq(void *buf) { struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ_EN); } void r92c_tx_setup_macid(void *buf, int id) { struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, id)); } void r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m, void *buf, uint8_t ridx, int maxretry) { #ifndef RTWN_WITHOUT_UCODE struct r92c_softc *rs = sc->sc_priv; #endif struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = ni->ni_vap; struct rtwn_vap *uvp = RTWN_VAP(vap); struct ieee80211_frame *wh; struct r92c_tx_desc *txd; enum ieee80211_protmode prot; uint8_t type, tid, qos, qsel; int hasqos, ismcast, macid; wh = mtod(m, struct ieee80211_frame *); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; hasqos = IEEE80211_QOS_HAS_SEQ(wh); ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); /* Select TX ring for this frame. */ if (hasqos) { qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; tid = qos & IEEE80211_QOS_TID; } else { qos = 0; tid = 0; } /* Fill Tx descriptor. */ txd = (struct r92c_tx_desc *)buf; txd->flags0 |= R92C_FLAGS0_LSG | R92C_FLAGS0_FSG; if (ismcast) txd->flags0 |= R92C_FLAGS0_BMCAST; if (!ismcast) { /* Unicast frame, check if an ACK is expected. */ if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) != IEEE80211_QOS_ACKPOLICY_NOACK) { txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA); txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT, maxretry)); } struct rtwn_node *un = RTWN_NODE(ni); macid = un->id; if (type == IEEE80211_FC0_TYPE_DATA) { qsel = tid % RTWN_MAX_TID; rtwn_r92c_tx_enable_ampdu(sc, buf, (m->m_flags & M_AMPDU_MPDU) != 0); if (m->m_flags & M_AMPDU_MPDU) { txd->txdw2 |= htole32(SM(R92C_TXDW2_AMPDU_DEN, vap->iv_ampdu_density)); txd->txdw6 |= htole32(SM(R92C_TXDW6_MAX_AGG, 0x1f)); /* XXX */ } if (sc->sc_ratectl == RTWN_RATECTL_NET80211) { txd->txdw2 |= htole32(R92C_TXDW2_CCX_RPT); sc->sc_tx_n_active++; #ifndef RTWN_WITHOUT_UCODE rs->rs_c2h_pending++; #endif } if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) txd->txdw4 |= htole32(R92C_TXDW4_DATA_SHPRE); prot = IEEE80211_PROT_NONE; - if (ridx >= RTWN_RIDX_MCS(0)) { + if (ridx >= RTWN_RIDX_HT_MCS(0)) { r92c_tx_set_ht40(sc, txd, ni); r92c_tx_set_sgi(sc, txd, ni); prot = ic->ic_htprotmode; } else if (ic->ic_flags & IEEE80211_F_USEPROT) prot = ic->ic_protmode; /* XXX fix last comparison for A-MSDU (in net80211) */ /* XXX A-MPDU? */ if (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold && vap->iv_rtsthreshold != IEEE80211_RTS_MAX) prot = IEEE80211_PROT_RTSCTS; /* NB: checks for ht40 / short bits (set above). */ if (prot != IEEE80211_PROT_NONE) r92c_tx_protection(sc, txd, prot, ridx); } else /* IEEE80211_FC0_TYPE_MGT */ qsel = R92C_TXDW1_QSEL_MGNT; } else { macid = RTWN_MACID_BC; qsel = R92C_TXDW1_QSEL_MGNT; } txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, qsel)); rtwn_r92c_tx_setup_macid(sc, txd, macid); txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx)); /* Data rate fallback limit (max). */ txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE_FB_LMT, 0x1f)); txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, uvp->id)); r92c_tx_raid(sc, txd, ni, ismcast); /* Force this rate if needed. */ if (sc->sc_ratectl != RTWN_RATECTL_FW) txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); if (!hasqos) { /* Use HW sequence numbering for non-QoS frames. */ rtwn_r92c_tx_setup_hwseq(sc, txd); txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, uvp->id)); } else { uint16_t seqno; if (m->m_flags & M_AMPDU_MPDU) { seqno = ni->ni_txseqs[tid]; ni->ni_txseqs[tid]++; } else seqno = M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE; /* Set sequence number. */ txd->txdseq = htole16(seqno); } } void r92c_fill_tx_desc_raw(struct rtwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m, void *buf, const struct ieee80211_bpf_params *params) { struct ieee80211vap *vap = ni->ni_vap; struct rtwn_vap *uvp = RTWN_VAP(vap); struct ieee80211_frame *wh; struct r92c_tx_desc *txd; uint8_t ridx; int ismcast; /* XXX TODO: 11n checks, matching r92c_fill_tx_desc() */ wh = mtod(m, struct ieee80211_frame *); ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); ridx = rate2ridx(params->ibp_rate0); /* Fill Tx descriptor. */ txd = (struct r92c_tx_desc *)buf; txd->flags0 |= R92C_FLAGS0_LSG | R92C_FLAGS0_FSG; if (ismcast) txd->flags0 |= R92C_FLAGS0_BMCAST; if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) { txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA); txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT, params->ibp_try0)); } if (params->ibp_flags & IEEE80211_BPF_RTS) r92c_tx_protection(sc, txd, IEEE80211_PROT_RTSCTS, ridx); if (params->ibp_flags & IEEE80211_BPF_CTS) r92c_tx_protection(sc, txd, IEEE80211_PROT_CTSONLY, ridx); rtwn_r92c_tx_setup_macid(sc, txd, RTWN_MACID_BC); txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT)); /* Set TX rate index. */ txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx)); txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE_FB_LMT, 0x1f)); txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, uvp->id)); txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); r92c_tx_raid(sc, txd, ni, ismcast); if (!IEEE80211_QOS_HAS_SEQ(wh)) { /* Use HW sequence numbering for non-QoS frames. */ rtwn_r92c_tx_setup_hwseq(sc, txd); txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, uvp->id)); } else { /* Set sequence number. */ txd->txdseq |= htole16(M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE); } } void r92c_fill_tx_desc_null(struct rtwn_softc *sc, void *buf, int is11b, int qos, int id) { struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; txd->flags0 = R92C_FLAGS0_FSG | R92C_FLAGS0_LSG | R92C_FLAGS0_OWN; txd->txdw1 = htole32( SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT)); txd->txdw4 = htole32(R92C_TXDW4_DRVRATE); txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, id)); if (is11b) { txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE, RTWN_RIDX_CCK1)); } else { txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE, RTWN_RIDX_OFDM6)); } if (!qos) { rtwn_r92c_tx_setup_hwseq(sc, txd); txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, id)); } } uint8_t r92c_tx_radiotap_flags(const void *buf) { const struct r92c_tx_desc *txd = buf; uint8_t flags; flags = 0; if (txd->txdw4 & htole32(R92C_TXDW4_DATA_SHPRE)) flags |= IEEE80211_RADIOTAP_F_SHORTPRE; if (txd->txdw5 & htole32(R92C_TXDW5_SGI)) flags |= IEEE80211_RADIOTAP_F_SHORTGI; return (flags); } Index: head/sys/dev/rtwn/rtl8192e/r92e_chan.c =================================================================== --- head/sys/dev/rtwn/rtl8192e/r92e_chan.c (revision 322987) +++ head/sys/dev/rtwn/rtl8192e/r92e_chan.c (revision 322988) @@ -1,233 +1,233 @@ /*- * Copyright (c) 2017 Kevin Lo * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int r92e_get_power_group(struct rtwn_softc *sc, struct ieee80211_channel *c) { uint8_t chan; int group; chan = rtwn_chan2centieee(c); if (IEEE80211_IS_CHAN_2GHZ(c)) { if (chan <= 2) group = 0; else if (chan <= 5) group = 1; else if (chan <= 8) group = 2; else if (chan <= 11) group = 3; else if (chan <= 14) group = 4; else { KASSERT(0, ("wrong 2GHz channel %d!\n", chan)); return (-1); } } else { KASSERT(0, ("wrong channel band (flags %08X)\n", c->ic_flags)); return (-1); } return (group); } static void r92e_get_txpower(struct rtwn_softc *sc, int chain, struct ieee80211_channel *c, uint8_t power[RTWN_RIDX_COUNT]) { struct r92e_softc *rs = sc->sc_priv; int i, ridx, group, max_mcs; /* Determine channel group. */ group = r92e_get_power_group(sc, c); if (group == -1) { /* shouldn't happen */ device_printf(sc->sc_dev, "%s: incorrect channel\n", __func__); return; } - max_mcs = RTWN_RIDX_MCS(sc->ntxchains * 8 - 1); + max_mcs = RTWN_RIDX_HT_MCS(sc->ntxchains * 8 - 1); /* XXX regulatory */ /* XXX net80211 regulatory */ for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++) power[ridx] = rs->cck_tx_pwr[chain][group]; for (ridx = RTWN_RIDX_OFDM6; ridx <= max_mcs; ridx++) power[ridx] = rs->ht40_tx_pwr_2g[chain][group]; for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++) power[ridx] += rs->ofdm_tx_pwr_diff_2g[chain][0]; for (i = 0; i < sc->ntxchains; i++) { uint8_t min_mcs; uint8_t pwr_diff; if (IEEE80211_IS_CHAN_HT40(c)) pwr_diff = rs->bw40_tx_pwr_diff_2g[chain][i]; else pwr_diff = rs->bw20_tx_pwr_diff_2g[chain][i]; - min_mcs = RTWN_RIDX_MCS(i * 8); + min_mcs = RTWN_RIDX_HT_MCS(i * 8); for (ridx = min_mcs; ridx <= max_mcs; ridx++) power[ridx] += pwr_diff; } /* Apply max limit. */ for (ridx = RTWN_RIDX_CCK1; ridx <= max_mcs; ridx++) { if (power[ridx] > R92C_MAX_TX_PWR) power[ridx] = R92C_MAX_TX_PWR; } #ifdef RTWN_DEBUG if (sc->sc_debug & RTWN_DEBUG_TXPWR) { /* Dump per-rate Tx power values. */ printf("Tx power for chain %d:\n", chain); for (ridx = RTWN_RIDX_CCK1; ridx < RTWN_RIDX_COUNT; ridx++) printf("Rate %d = %u\n", ridx, power[ridx]); } #endif } static void r92e_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c) { uint8_t power[RTWN_RIDX_COUNT]; int i; for (i = 0; i < sc->ntxchains; i++) { memset(power, 0, sizeof(power)); /* Compute per-rate Tx power values. */ r92e_get_txpower(sc, i, c, power); /* Write per-rate Tx power values to hardware. */ r92c_write_txpower(sc, i, power); } } static void r92e_set_bw40(struct rtwn_softc *sc, uint8_t chan, int prichlo) { int i; rtwn_setbits_2(sc, R92C_WMAC_TRXPTCL_CTL, 0x100, 0x80); rtwn_write_1(sc, R12A_DATA_SEC, prichlo ? R12A_DATA_SEC_PRIM_DOWN_20 : R12A_DATA_SEC_PRIM_UP_20); rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, 0, R92C_RFMOD_40MHZ); rtwn_bb_setbits(sc, R92C_FPGA1_RFMOD, 0, R92C_RFMOD_40MHZ); /* Select 40MHz bandwidth. */ for (i = 0; i < sc->nrxchains; i++) rtwn_rf_setbits(sc, i, R92C_RF_CHNLBW, R88E_RF_CHNLBW_BW20, 0x400); /* Set CCK side band. */ rtwn_bb_setbits(sc, R92C_CCK0_SYSTEM, R92C_CCK0_SYSTEM_CCK_SIDEBAND, (prichlo ? 0 : 1) << 4); rtwn_bb_setbits(sc, R92C_OFDM1_LSTF, 0x0c00, (prichlo ? 1 : 2) << 10); rtwn_bb_setbits(sc, R92C_FPGA0_ANAPARAM2, R92C_FPGA0_ANAPARAM2_CBW20, 0); rtwn_bb_setbits(sc, 0x818, 0x0c000000, (prichlo ? 2 : 1) << 26); } static void r92e_set_bw20(struct rtwn_softc *sc, uint8_t chan) { int i; rtwn_setbits_2(sc, R92C_WMAC_TRXPTCL_CTL, 0x180, 0); rtwn_write_1(sc, R12A_DATA_SEC, R12A_DATA_SEC_NO_EXT); rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, R92C_RFMOD_40MHZ, 0); rtwn_bb_setbits(sc, R92C_FPGA1_RFMOD, R92C_RFMOD_40MHZ, 0); /* Select 20MHz bandwidth. */ for (i = 0; i < sc->nrxchains; i++) rtwn_rf_setbits(sc, i, R92C_RF_CHNLBW, R88E_RF_CHNLBW_BW20, 0xc00); rtwn_bb_setbits(sc, R92C_OFDM0_TXPSEUDONOISEWGT, 0xc0000000, 0); } void r92e_set_chan(struct rtwn_softc *sc, struct ieee80211_channel *c) { struct r92e_softc *rs = sc->sc_priv; u_int chan; int i; chan = rtwn_chan2centieee(c); for (i = 0; i < sc->nrxchains; i++) { rtwn_rf_write(sc, i, R92C_RF_CHNLBW, RW(rs->rf_chnlbw[0], R92C_RF_CHNLBW_CHNL, chan)); } if (IEEE80211_IS_CHAN_HT40(c)) r92e_set_bw40(sc, chan, IEEE80211_IS_CHAN_HT40U(c)); else r92e_set_bw20(sc, chan); /* Set Tx power for this new channel. */ r92e_set_txpower(sc, c); } Index: head/sys/dev/rtwn/rtl8812a/r12a_chan.c =================================================================== --- head/sys/dev/rtwn/rtl8812a/r12a_chan.c (revision 322987) +++ head/sys/dev/rtwn/rtl8812a/r12a_chan.c (revision 322988) @@ -1,601 +1,601 @@ /*- * Copyright (c) 2016 Andriy Voskoboinyk * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void r12a_write_txpower(struct rtwn_softc *sc, int chain, struct ieee80211_channel *c, uint8_t power[RTWN_RIDX_COUNT]) { if (IEEE80211_IS_CHAN_2GHZ(c)) { /* Write per-CCK rate Tx power. */ rtwn_bb_write(sc, R12A_TXAGC_CCK11_1(chain), SM(R12A_TXAGC_CCK1, power[RTWN_RIDX_CCK1]) | SM(R12A_TXAGC_CCK2, power[RTWN_RIDX_CCK2]) | SM(R12A_TXAGC_CCK55, power[RTWN_RIDX_CCK55]) | SM(R12A_TXAGC_CCK11, power[RTWN_RIDX_CCK11])); } /* Write per-OFDM rate Tx power. */ rtwn_bb_write(sc, R12A_TXAGC_OFDM18_6(chain), SM(R12A_TXAGC_OFDM06, power[RTWN_RIDX_OFDM6]) | SM(R12A_TXAGC_OFDM09, power[RTWN_RIDX_OFDM9]) | SM(R12A_TXAGC_OFDM12, power[RTWN_RIDX_OFDM12]) | SM(R12A_TXAGC_OFDM18, power[RTWN_RIDX_OFDM18])); rtwn_bb_write(sc, R12A_TXAGC_OFDM54_24(chain), SM(R12A_TXAGC_OFDM24, power[RTWN_RIDX_OFDM24]) | SM(R12A_TXAGC_OFDM36, power[RTWN_RIDX_OFDM36]) | SM(R12A_TXAGC_OFDM48, power[RTWN_RIDX_OFDM48]) | SM(R12A_TXAGC_OFDM54, power[RTWN_RIDX_OFDM54])); /* Write per-MCS Tx power. */ rtwn_bb_write(sc, R12A_TXAGC_MCS3_0(chain), - SM(R12A_TXAGC_MCS0, power[RTWN_RIDX_MCS(0)]) | - SM(R12A_TXAGC_MCS1, power[RTWN_RIDX_MCS(1)]) | - SM(R12A_TXAGC_MCS2, power[RTWN_RIDX_MCS(2)]) | - SM(R12A_TXAGC_MCS3, power[RTWN_RIDX_MCS(3)])); + SM(R12A_TXAGC_MCS0, power[RTWN_RIDX_HT_MCS(0)]) | + SM(R12A_TXAGC_MCS1, power[RTWN_RIDX_HT_MCS(1)]) | + SM(R12A_TXAGC_MCS2, power[RTWN_RIDX_HT_MCS(2)]) | + SM(R12A_TXAGC_MCS3, power[RTWN_RIDX_HT_MCS(3)])); rtwn_bb_write(sc, R12A_TXAGC_MCS7_4(chain), - SM(R12A_TXAGC_MCS4, power[RTWN_RIDX_MCS(4)]) | - SM(R12A_TXAGC_MCS5, power[RTWN_RIDX_MCS(5)]) | - SM(R12A_TXAGC_MCS6, power[RTWN_RIDX_MCS(6)]) | - SM(R12A_TXAGC_MCS7, power[RTWN_RIDX_MCS(7)])); + SM(R12A_TXAGC_MCS4, power[RTWN_RIDX_HT_MCS(4)]) | + SM(R12A_TXAGC_MCS5, power[RTWN_RIDX_HT_MCS(5)]) | + SM(R12A_TXAGC_MCS6, power[RTWN_RIDX_HT_MCS(6)]) | + SM(R12A_TXAGC_MCS7, power[RTWN_RIDX_HT_MCS(7)])); if (sc->ntxchains >= 2) { rtwn_bb_write(sc, R12A_TXAGC_MCS11_8(chain), - SM(R12A_TXAGC_MCS8, power[RTWN_RIDX_MCS(8)]) | - SM(R12A_TXAGC_MCS9, power[RTWN_RIDX_MCS(9)]) | - SM(R12A_TXAGC_MCS10, power[RTWN_RIDX_MCS(10)]) | - SM(R12A_TXAGC_MCS11, power[RTWN_RIDX_MCS(11)])); + SM(R12A_TXAGC_MCS8, power[RTWN_RIDX_HT_MCS(8)]) | + SM(R12A_TXAGC_MCS9, power[RTWN_RIDX_HT_MCS(9)]) | + SM(R12A_TXAGC_MCS10, power[RTWN_RIDX_HT_MCS(10)]) | + SM(R12A_TXAGC_MCS11, power[RTWN_RIDX_HT_MCS(11)])); rtwn_bb_write(sc, R12A_TXAGC_MCS15_12(chain), - SM(R12A_TXAGC_MCS12, power[RTWN_RIDX_MCS(12)]) | - SM(R12A_TXAGC_MCS13, power[RTWN_RIDX_MCS(13)]) | - SM(R12A_TXAGC_MCS14, power[RTWN_RIDX_MCS(14)]) | - SM(R12A_TXAGC_MCS15, power[RTWN_RIDX_MCS(15)])); + SM(R12A_TXAGC_MCS12, power[RTWN_RIDX_HT_MCS(12)]) | + SM(R12A_TXAGC_MCS13, power[RTWN_RIDX_HT_MCS(13)]) | + SM(R12A_TXAGC_MCS14, power[RTWN_RIDX_HT_MCS(14)]) | + SM(R12A_TXAGC_MCS15, power[RTWN_RIDX_HT_MCS(15)])); } /* TODO: VHT rates */ } static int r12a_get_power_group(struct rtwn_softc *sc, struct ieee80211_channel *c) { uint8_t chan; int group; chan = rtwn_chan2centieee(c); if (IEEE80211_IS_CHAN_2GHZ(c)) { if (chan <= 2) group = 0; else if (chan <= 5) group = 1; else if (chan <= 8) group = 2; else if (chan <= 11) group = 3; else if (chan <= 14) group = 4; else { KASSERT(0, ("wrong 2GHz channel %d!\n", chan)); return (-1); } } else if (IEEE80211_IS_CHAN_5GHZ(c)) { if (chan < 36) return (-1); if (chan <= 42) group = 0; else if (chan <= 48) group = 1; else if (chan <= 58) group = 2; else if (chan <= 64) group = 3; else if (chan <= 106) group = 4; else if (chan <= 114) group = 5; else if (chan <= 122) group = 6; else if (chan <= 130) group = 7; else if (chan <= 138) group = 8; else if (chan <= 144) group = 9; else if (chan <= 155) group = 10; else if (chan <= 161) group = 11; else if (chan <= 171) group = 12; else if (chan <= 177) group = 13; else { KASSERT(0, ("wrong 5GHz channel %d!\n", chan)); return (-1); } } else { KASSERT(0, ("wrong channel band (flags %08X)\n", c->ic_flags)); return (-1); } return (group); } static void r12a_get_txpower(struct rtwn_softc *sc, int chain, struct ieee80211_channel *c, uint8_t power[RTWN_RIDX_COUNT]) { struct r12a_softc *rs = sc->sc_priv; int i, ridx, group, max_mcs; /* Determine channel group. */ group = r12a_get_power_group(sc, c); if (group == -1) { /* shouldn't happen */ device_printf(sc->sc_dev, "%s: incorrect channel\n", __func__); return; } /* TODO: VHT rates. */ - max_mcs = RTWN_RIDX_MCS(sc->ntxchains * 8 - 1); + max_mcs = RTWN_RIDX_HT_MCS(sc->ntxchains * 8 - 1); /* XXX regulatory */ /* XXX net80211 regulatory */ if (IEEE80211_IS_CHAN_2GHZ(c)) { for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++) power[ridx] = rs->cck_tx_pwr[chain][group]; for (ridx = RTWN_RIDX_OFDM6; ridx <= max_mcs; ridx++) power[ridx] = rs->ht40_tx_pwr_2g[chain][group]; for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++) power[ridx] += rs->ofdm_tx_pwr_diff_2g[chain][0]; for (i = 0; i < sc->ntxchains; i++) { uint8_t min_mcs; uint8_t pwr_diff; #ifdef notyet if (IEEE80211_IS_CHAN_HT80(c)) { /* Vendor driver uses HT40 values here. */ pwr_diff = rs->bw40_tx_pwr_diff_2g[chain][i]; } else #endif if (IEEE80211_IS_CHAN_HT40(c)) pwr_diff = rs->bw40_tx_pwr_diff_2g[chain][i]; else pwr_diff = rs->bw20_tx_pwr_diff_2g[chain][i]; - min_mcs = RTWN_RIDX_MCS(i * 8); + min_mcs = RTWN_RIDX_HT_MCS(i * 8); for (ridx = min_mcs; ridx <= max_mcs; ridx++) power[ridx] += pwr_diff; } } else { /* 5GHz */ for (ridx = RTWN_RIDX_OFDM6; ridx <= max_mcs; ridx++) power[ridx] = rs->ht40_tx_pwr_5g[chain][group]; for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++) power[ridx] += rs->ofdm_tx_pwr_diff_5g[chain][0]; for (i = 0; i < sc->ntxchains; i++) { uint8_t min_mcs; uint8_t pwr_diff; #ifdef notyet if (IEEE80211_IS_CHAN_HT80(c)) { /* TODO: calculate base value. */ pwr_diff = rs->bw80_tx_pwr_diff_5g[chain][i]; } else #endif if (IEEE80211_IS_CHAN_HT40(c)) pwr_diff = rs->bw40_tx_pwr_diff_5g[chain][i]; else pwr_diff = rs->bw20_tx_pwr_diff_5g[chain][i]; - min_mcs = RTWN_RIDX_MCS(i * 8); + min_mcs = RTWN_RIDX_HT_MCS(i * 8); for (ridx = min_mcs; ridx <= max_mcs; ridx++) power[ridx] += pwr_diff; } } /* Apply max limit. */ for (ridx = RTWN_RIDX_CCK1; ridx <= max_mcs; ridx++) { if (power[ridx] > R92C_MAX_TX_PWR) power[ridx] = R92C_MAX_TX_PWR; } #ifdef RTWN_DEBUG if (sc->sc_debug & RTWN_DEBUG_TXPWR) { /* Dump per-rate Tx power values. */ printf("Tx power for chain %d:\n", chain); for (ridx = RTWN_RIDX_CCK1; ridx <= max_mcs; ridx++) printf("Rate %d = %u\n", ridx, power[ridx]); } #endif } static void r12a_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c) { uint8_t power[RTWN_RIDX_COUNT]; int i; for (i = 0; i < sc->ntxchains; i++) { memset(power, 0, sizeof(power)); /* Compute per-rate Tx power values. */ r12a_get_txpower(sc, i, c, power); /* Write per-rate Tx power values to hardware. */ r12a_write_txpower(sc, i, c, power); } } void r12a_fix_spur(struct rtwn_softc *sc, struct ieee80211_channel *c) { struct r12a_softc *rs = sc->sc_priv; uint16_t chan = rtwn_chan2centieee(c); if (rs->chip & R12A_CHIP_C_CUT) { if (IEEE80211_IS_CHAN_HT40(c) && chan == 11) { rtwn_bb_setbits(sc, R12A_RFMOD, 0, 0xc00); rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, 0, 0x40000000); } else { rtwn_bb_setbits(sc, R12A_RFMOD, 0x400, 0x800); if (!IEEE80211_IS_CHAN_HT40(c) && /* 20 MHz */ (chan == 13 || chan == 14)) { rtwn_bb_setbits(sc, R12A_RFMOD, 0, 0x300); rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, 0, 0x40000000); } else { /* !80 Mhz */ rtwn_bb_setbits(sc, R12A_RFMOD, 0x100, 0x200); rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, 0x40000000, 0); } } } else { /* Set ADC clock to 160M to resolve 2480 MHz spur. */ if (!IEEE80211_IS_CHAN_HT40(c) && /* 20 MHz */ (chan == 13 || chan == 14)) rtwn_bb_setbits(sc, R12A_RFMOD, 0, 0x300); else if (IEEE80211_IS_CHAN_2GHZ(c)) rtwn_bb_setbits(sc, R12A_RFMOD, 0x100, 0x200); } } static void r12a_set_band(struct rtwn_softc *sc, struct ieee80211_channel *c) { struct ieee80211com *ic = &sc->sc_ic; struct r12a_softc *rs = sc->sc_priv; uint32_t basicrates; uint8_t swing; int i; /* Check if band was changed. */ if ((sc->sc_flags & (RTWN_STARTED | RTWN_RUNNING)) != RTWN_STARTED && IEEE80211_IS_CHAN_5GHZ(c) ^ !(rtwn_read_1(sc, R12A_CCK_CHECK) & R12A_CCK_CHECK_5GHZ)) return; rtwn_get_rates(sc, ieee80211_get_suprates(ic, c), NULL, &basicrates, NULL, 1); if (IEEE80211_IS_CHAN_2GHZ(c)) { rtwn_r12a_set_band_2ghz(sc, basicrates); swing = rs->tx_bbswing_2g; } else if (IEEE80211_IS_CHAN_5GHZ(c)) { rtwn_r12a_set_band_5ghz(sc, basicrates); swing = rs->tx_bbswing_5g; } else { KASSERT(0, ("wrong channel flags %08X\n", c->ic_flags)); return; } /* XXX PATH_B is set by vendor driver. */ for (i = 0; i < 2; i++) { uint16_t val = 0; switch ((swing >> i * 2) & 0x3) { case 0: val = 0x200; /* 0 dB */ break; case 1: val = 0x16a; /* -3 dB */ break; case 2: val = 0x101; /* -6 dB */ break; case 3: val = 0xb6; /* -9 dB */ break; } rtwn_bb_setbits(sc, R12A_TX_SCALE(i), R12A_TX_SCALE_SWING_M, val << R12A_TX_SCALE_SWING_S); } } void r12a_set_chan(struct rtwn_softc *sc, struct ieee80211_channel *c) { uint32_t val; uint16_t chan; int i; r12a_set_band(sc, c); chan = rtwn_chan2centieee(c); if (36 <= chan && chan <= 48) val = 0x09280000; else if (50 <= chan && chan <= 64) val = 0x08a60000; else if (100 <= chan && chan <= 116) val = 0x08a40000; else if (118 <= chan) val = 0x08240000; else val = 0x12d40000; rtwn_bb_setbits(sc, R12A_FC_AREA, 0x1ffe0000, val); for (i = 0; i < sc->nrxchains; i++) { if (36 <= chan && chan <= 64) val = 0x10100; else if (100 <= chan && chan <= 140) val = 0x30100; else if (140 < chan) val = 0x50100; else val = 0x00000; rtwn_rf_setbits(sc, i, R92C_RF_CHNLBW, 0x70300, val); /* RTL8812AU-specific */ rtwn_r12a_fix_spur(sc, c); KASSERT(chan <= 0xff, ("%s: chan %d\n", __func__, chan)); rtwn_rf_setbits(sc, i, R92C_RF_CHNLBW, 0xff, chan); } #ifdef notyet if (IEEE80211_IS_CHAN_HT80(c)) { /* 80 MHz */ rtwn_setbits_2(sc, R92C_WMAC_TRXPTCL_CTL, 0x80, 0x100); /* TODO */ val = 0x0; } else #endif if (IEEE80211_IS_CHAN_HT40(c)) { /* 40 MHz */ uint8_t ext_chan; if (IEEE80211_IS_CHAN_HT40U(c)) ext_chan = R12A_DATA_SEC_PRIM_DOWN_20; else ext_chan = R12A_DATA_SEC_PRIM_UP_20; rtwn_setbits_2(sc, R92C_WMAC_TRXPTCL_CTL, 0x100, 0x80); rtwn_write_1(sc, R12A_DATA_SEC, ext_chan); rtwn_bb_setbits(sc, R12A_RFMOD, 0x003003c3, 0x00300201); rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, 0x40000000, 0); /* discard high 4 bits */ val = rtwn_bb_read(sc, R12A_RFMOD); val = RW(val, R12A_RFMOD_EXT_CHAN, ext_chan); rtwn_bb_write(sc, R12A_RFMOD, val); val = rtwn_bb_read(sc, R12A_CCA_ON_SEC); val = RW(val, R12A_CCA_ON_SEC_EXT_CHAN, ext_chan); rtwn_bb_write(sc, R12A_CCA_ON_SEC, val); if (rtwn_read_1(sc, 0x837) & 0x04) val = 0x01800000; else if (sc->nrxchains == 2 && sc->ntxchains == 2) val = 0x01c00000; else val = 0x02000000; rtwn_bb_setbits(sc, R12A_L1_PEAK_TH, 0x03c00000, val); if (IEEE80211_IS_CHAN_HT40U(c)) rtwn_bb_setbits(sc, R92C_CCK0_SYSTEM, 0x10, 0); else rtwn_bb_setbits(sc, R92C_CCK0_SYSTEM, 0, 0x10); val = 0x400; } else { /* 20 MHz */ rtwn_setbits_2(sc, R92C_WMAC_TRXPTCL_CTL, 0x180, 0); rtwn_write_1(sc, R12A_DATA_SEC, R12A_DATA_SEC_NO_EXT); rtwn_bb_setbits(sc, R12A_RFMOD, 0x003003c3, 0x00300200); rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, 0x40000000, 0); if (sc->nrxchains == 2 && sc->ntxchains == 2) val = 0x01c00000; else val = 0x02000000; rtwn_bb_setbits(sc, R12A_L1_PEAK_TH, 0x03c00000, val); val = 0xc00; } /* RTL8812AU-specific */ rtwn_r12a_fix_spur(sc, c); for (i = 0; i < sc->nrxchains; i++) rtwn_rf_setbits(sc, i, R92C_RF_CHNLBW, 0xc00, val); /* Set Tx power for this new channel. */ r12a_set_txpower(sc, c); } void r12a_set_band_2ghz(struct rtwn_softc *sc, uint32_t basicrates) { struct r12a_softc *rs = sc->sc_priv; /* Enable CCK / OFDM. */ rtwn_bb_setbits(sc, R12A_OFDMCCK_EN, 0, R12A_OFDMCCK_EN_CCK | R12A_OFDMCCK_EN_OFDM); rtwn_bb_setbits(sc, R12A_BW_INDICATION, 0x02, 0x01); rtwn_bb_setbits(sc, R12A_PWED_TH, 0x3e000, 0x2e000); /* Select AGC table. */ rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x03, 0); switch (rs->rfe_type) { case 0: case 1: case 2: rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77777777); rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77777777); rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0); rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0); break; case 3: rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x54337770); rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x54337770); rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x01000000); rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000); rtwn_bb_setbits(sc, R12A_ANTSEL_SW, 0x0303, 0x01); break; case 4: rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77777777); rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77777777); rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x00100000); rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x00100000); break; case 5: rtwn_write_1(sc, R12A_RFE_PINMUX(0) + 2, 0x77); rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77777777); rtwn_setbits_1(sc, R12A_RFE_INV(0) + 3, 0x01, 0); rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0); break; default: break; } rtwn_bb_setbits(sc, R12A_TX_PATH, 0xf0, 0x10); rtwn_bb_setbits(sc, R12A_CCK_RX_PATH, 0x0f000000, 0x01000000); /* Write basic rates. */ rtwn_set_basicrates(sc, basicrates); rtwn_write_1(sc, R12A_CCK_CHECK, 0); } void r12a_set_band_5ghz(struct rtwn_softc *sc, uint32_t basicrates) { struct r12a_softc *rs = sc->sc_priv; int ntries; rtwn_write_1(sc, R12A_CCK_CHECK, R12A_CCK_CHECK_5GHZ); for (ntries = 0; ntries < 100; ntries++) { if ((rtwn_read_2(sc, R12A_TXPKT_EMPTY) & 0x30) == 0x30) break; rtwn_delay(sc, 25); } if (ntries == 100) { device_printf(sc->sc_dev, "%s: TXPKT_EMPTY check failed (%04X)\n", __func__, rtwn_read_2(sc, R12A_TXPKT_EMPTY)); } /* Enable OFDM. */ rtwn_bb_setbits(sc, R12A_OFDMCCK_EN, R12A_OFDMCCK_EN_CCK, R12A_OFDMCCK_EN_OFDM); rtwn_bb_setbits(sc, R12A_BW_INDICATION, 0x01, 0x02); rtwn_bb_setbits(sc, R12A_PWED_TH, 0x3e000, 0x2a000); /* Select AGC table. */ rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x03, 0x01); switch (rs->rfe_type) { case 0: rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77337717); rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77337717); rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x01000000); rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000); break; case 1: rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77337717); rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77337717); rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0); rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0); break; case 2: case 4: rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77337777); rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77337777); rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x01000000); rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000); break; case 3: rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x54337717); rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x54337717); rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x01000000); rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000); rtwn_bb_setbits(sc, R12A_ANTSEL_SW, 0x0303, 0x01); break; case 5: rtwn_write_1(sc, R12A_RFE_PINMUX(0) + 2, 0x33); rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77337777); rtwn_setbits_1(sc, R12A_RFE_INV(0) + 3, 0, 0x01); rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000); break; default: break; } rtwn_bb_setbits(sc, R12A_TX_PATH, 0xf0, 0); rtwn_bb_setbits(sc, R12A_CCK_RX_PATH, 0, 0x0f000000); /* Write basic rates. */ rtwn_set_basicrates(sc, basicrates); } Index: head/sys/dev/rtwn/rtl8812a/r12a_rx.c =================================================================== --- head/sys/dev/rtwn/rtl8812a/r12a_rx.c (revision 322987) +++ head/sys/dev/rtwn/rtl8812a/r12a_rx.c (revision 322988) @@ -1,327 +1,327 @@ /*- * Copyright (c) 2016 Andriy Voskoboinyk * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef RTWN_WITHOUT_UCODE void r12a_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len) { #if __FreeBSD_version >= 1200012 struct ieee80211_ratectl_tx_status txs; #endif struct r12a_c2h_tx_rpt *rpt; struct ieee80211_node *ni; int ntries; /* Skip Rx descriptor / report id / sequence fields. */ buf += sizeof(struct r92c_rx_stat) + 2; len -= sizeof(struct r92c_rx_stat) + 2; rpt = (struct r12a_c2h_tx_rpt *)buf; if (len != sizeof(*rpt)) { device_printf(sc->sc_dev, "%s: wrong report size (%d, must be %zu)\n", __func__, len, sizeof(*rpt)); return; } RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: ccx report dump: 0: %02X, id: %02X, 2: %02X, queue time: " "low %02X, high %02X, final ridx: %02X, rsvd: %04X\n", __func__, rpt->txrptb0, rpt->macid, rpt->txrptb2, rpt->queue_time_low, rpt->queue_time_high, rpt->final_rate, rpt->reserved); if (rpt->macid > sc->macid_limit) { device_printf(sc->sc_dev, "macid %u is too big; increase MACID_MAX limit\n", rpt->macid); return; } ntries = MS(rpt->txrptb2, R12A_TXRPTB2_RETRY_CNT); ni = sc->node_list[rpt->macid]; if (ni != NULL) { RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: frame for macid %u was" "%s sent (%d retries)\n", __func__, rpt->macid, (rpt->txrptb0 & (R12A_TXRPTB0_RETRY_OVER | R12A_TXRPTB0_LIFE_EXPIRE)) ? " not" : "", ntries); #if __FreeBSD_version >= 1200012 txs.flags = IEEE80211_RATECTL_STATUS_LONG_RETRY | IEEE80211_RATECTL_STATUS_FINAL_RATE; txs.long_retries = ntries; if (rpt->final_rate > RTWN_RIDX_OFDM54) { /* MCS */ txs.final_rate = (rpt->final_rate - 12) | IEEE80211_RATE_MCS; } else txs.final_rate = ridx2rate[rpt->final_rate]; if (rpt->txrptb0 & R12A_TXRPTB0_RETRY_OVER) txs.status = IEEE80211_RATECTL_TX_FAIL_LONG; else if (rpt->txrptb0 & R12A_TXRPTB0_LIFE_EXPIRE) txs.status = IEEE80211_RATECTL_TX_FAIL_EXPIRED; else txs.status = IEEE80211_RATECTL_TX_SUCCESS; ieee80211_ratectl_tx_complete(ni, &txs); #else struct ieee80211vap *vap = ni->ni_vap; if (rpt->txrptb0 & R12A_TXRPTB0_RETRY_OVER) { ieee80211_ratectl_tx_complete(vap, ni, IEEE80211_RATECTL_TX_FAILURE, &ntries, NULL); } else { ieee80211_ratectl_tx_complete(vap, ni, IEEE80211_RATECTL_TX_SUCCESS, &ntries, NULL); } #endif } else { RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: macid %u, ni is NULL\n", __func__, rpt->macid); } } void r12a_handle_c2h_report(struct rtwn_softc *sc, uint8_t *buf, int len) { struct r12a_softc *rs = sc->sc_priv; /* Skip Rx descriptor. */ buf += sizeof(struct r92c_rx_stat); len -= sizeof(struct r92c_rx_stat); if (len < 2) { device_printf(sc->sc_dev, "C2H report too short (len %d)\n", len); return; } len -= 2; switch (buf[0]) { /* command id */ case R12A_C2H_TX_REPORT: /* NOTREACHED */ KASSERT(0, ("use handle_tx_report() instead of %s\n", __func__)); break; case R12A_C2H_IQK_FINISHED: RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, "FW IQ calibration finished\n"); rs->rs_flags &= ~R12A_IQK_RUNNING; break; default: device_printf(sc->sc_dev, "%s: C2H report %u was not handled\n", __func__, buf[0]); } } #else void r12a_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len) { /* Should not happen. */ device_printf(sc->sc_dev, "%s: called\n", __func__); } void r12a_handle_c2h_report(struct rtwn_softc *sc, uint8_t *buf, int len) { /* Should not happen. */ device_printf(sc->sc_dev, "%s: called\n", __func__); } #endif int r12a_check_frame_checksum(struct rtwn_softc *sc, struct mbuf *m) { struct r12a_softc *rs = sc->sc_priv; struct r92c_rx_stat *stat; uint32_t rxdw1; stat = mtod(m, struct r92c_rx_stat *); rxdw1 = le32toh(stat->rxdw1); if (rxdw1 & R12A_RXDW1_CKSUM) { RTWN_DPRINTF(sc, RTWN_DEBUG_RECV, "%s: %s/%s checksum is %s\n", __func__, (rxdw1 & R12A_RXDW1_UDP) ? "UDP" : "TCP", (rxdw1 & R12A_RXDW1_IPV6) ? "IPv6" : "IP", (rxdw1 & R12A_RXDW1_CKSUM_ERR) ? "invalid" : "valid"); if (rxdw1 & R12A_RXDW1_CKSUM_ERR) return (-1); if ((rxdw1 & R12A_RXDW1_IPV6) ? (rs->rs_flags & R12A_RXCKSUM6_EN) : (rs->rs_flags & R12A_RXCKSUM_EN)) { m->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID | CSUM_DATA_VALID | CSUM_PSEUDO_HDR; m->m_pkthdr.csum_data = 0xffff; } } return (0); } uint8_t r12a_rx_radiotap_flags(const void *buf) { const struct r92c_rx_stat *stat = buf; uint8_t flags, rate; if (!(stat->rxdw4 & htole32(R12A_RXDW4_SPLCP))) return (0); 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 */ if (rxdw4 & R12A_RXDW4_LDPC) rxs->c_pktflags |= IEEE80211_RX_F_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)) + if ((rxdw4 & R12A_RXDW4_SPLCP) && rate >= RTWN_RIDX_HT_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 (rate < RTWN_RIDX_HT_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)) { + if (rate < RTWN_RIDX_HT_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_tx.c =================================================================== --- head/sys/dev/rtwn/rtl8812a/r12a_tx.c (revision 322987) +++ head/sys/dev/rtwn/rtl8812a/r12a_tx.c (revision 322988) @@ -1,446 +1,446 @@ /*- * Copyright (c) 2016 Andriy Voskoboinyk * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int r12a_get_primary_channel(struct rtwn_softc *sc, struct ieee80211_channel *c) { /* XXX 80 MHz */ if (IEEE80211_IS_CHAN_HT40U(c)) return (R12A_TXDW5_PRIM_CHAN_20_80_2); else return (R12A_TXDW5_PRIM_CHAN_20_80_3); } static void r12a_tx_set_ht40(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) { struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf; /* XXX 80 Mhz */ if (ni->ni_chan != IEEE80211_CHAN_ANYC && IEEE80211_IS_CHAN_HT40(ni->ni_chan)) { int prim_chan; prim_chan = r12a_get_primary_channel(sc, ni->ni_chan); txd->txdw5 |= htole32(SM(R12A_TXDW5_DATA_BW, R12A_TXDW5_DATA_BW40)); txd->txdw5 |= htole32(SM(R12A_TXDW5_DATA_PRIM_CHAN, prim_chan)); } } static void r12a_tx_protection(struct rtwn_softc *sc, struct r12a_tx_desc *txd, enum ieee80211_protmode mode, uint8_t ridx) { struct ieee80211com *ic = &sc->sc_ic; uint8_t rate; switch (mode) { case IEEE80211_PROT_CTSONLY: txd->txdw3 |= htole32(R12A_TXDW3_CTS2SELF); break; case IEEE80211_PROT_RTSCTS: txd->txdw3 |= htole32(R12A_TXDW3_RTSEN); break; default: break; } if (mode == IEEE80211_PROT_CTSONLY || mode == IEEE80211_PROT_RTSCTS) { - if (ridx >= RTWN_RIDX_MCS(0)) + if (ridx >= RTWN_RIDX_HT_MCS(0)) rate = rtwn_ctl_mcsrate(ic->ic_rt, ridx); else rate = ieee80211_ctl_rate(ic->ic_rt, ridx2rate[ridx]); ridx = rate2ridx(rate); txd->txdw4 |= htole32(SM(R12A_TXDW4_RTSRATE, ridx)); /* RTS rate fallback limit (max). */ txd->txdw4 |= htole32(SM(R12A_TXDW4_RTSRATE_FB_LMT, 0xf)); if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) txd->txdw5 |= htole32(R12A_TXDW5_RTS_SHORT); } } static void r12a_tx_raid(struct rtwn_softc *sc, struct r12a_tx_desc *txd, struct ieee80211_node *ni, int ismcast) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_channel *chan; enum ieee80211_phymode mode; uint8_t raid; chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ? ni->ni_chan : ic->ic_curchan; mode = ieee80211_chan2mode(chan); /* NB: group addressed frames are done at 11bg rates for now */ if (ismcast || !(ni->ni_flags & IEEE80211_NODE_HT)) { switch (mode) { case IEEE80211_MODE_11A: case IEEE80211_MODE_11B: case IEEE80211_MODE_11G: break; case IEEE80211_MODE_11NA: mode = IEEE80211_MODE_11A; break; case IEEE80211_MODE_11NG: mode = IEEE80211_MODE_11G; break; default: device_printf(sc->sc_dev, "unknown mode(1) %d!\n", ic->ic_curmode); return; } } switch (mode) { case IEEE80211_MODE_11A: raid = R12A_RAID_11G; break; case IEEE80211_MODE_11B: raid = R12A_RAID_11B; break; case IEEE80211_MODE_11G: if (vap->iv_flags & IEEE80211_F_PUREG) raid = R12A_RAID_11G; else raid = R12A_RAID_11BG; break; case IEEE80211_MODE_11NA: if (sc->ntxchains == 1) raid = R12A_RAID_11GN_1; else raid = R12A_RAID_11GN_2; break; case IEEE80211_MODE_11NG: if (sc->ntxchains == 1) { if (IEEE80211_IS_CHAN_HT40(chan)) raid = R12A_RAID_11BGN_1_40; else raid = R12A_RAID_11BGN_1; } else { if (IEEE80211_IS_CHAN_HT40(chan)) raid = R12A_RAID_11BGN_2_40; else raid = R12A_RAID_11BGN_2; } break; default: /* TODO: 80 MHz / 11ac */ device_printf(sc->sc_dev, "unknown mode(2) %d!\n", mode); return; } txd->txdw1 |= htole32(SM(R12A_TXDW1_RAID, raid)); } static void r12a_tx_set_sgi(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) { struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf; struct ieee80211vap *vap = ni->ni_vap; if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) && /* HT20 */ (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20)) txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT); else if (ni->ni_chan != IEEE80211_CHAN_ANYC && /* HT40 */ IEEE80211_IS_CHAN_HT40(ni->ni_chan) && (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) && (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40)) txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT); } static void r12a_tx_set_ldpc(struct rtwn_softc *sc, struct r12a_tx_desc *txd, struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; if ((vap->iv_flags_ht & IEEE80211_FHT_LDPC_TX) && (ni->ni_htcap & IEEE80211_HTCAP_LDPC)) txd->txdw5 |= htole32(R12A_TXDW5_DATA_LDPC); } void r12a_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m, void *buf, uint8_t ridx, int maxretry) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = ni->ni_vap; struct rtwn_vap *uvp = RTWN_VAP(vap); struct ieee80211_frame *wh; struct r12a_tx_desc *txd; enum ieee80211_protmode prot; uint8_t type, tid, qos, qsel; int hasqos, ismcast, macid; wh = mtod(m, struct ieee80211_frame *); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; hasqos = IEEE80211_QOS_HAS_SEQ(wh); ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); /* Select TX ring for this frame. */ if (hasqos) { qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; tid = qos & IEEE80211_QOS_TID; } else { qos = 0; tid = 0; } /* Fill Tx descriptor. */ txd = (struct r12a_tx_desc *)buf; txd->flags0 |= R12A_FLAGS0_LSG | R12A_FLAGS0_FSG; if (ismcast) txd->flags0 |= R12A_FLAGS0_BMCAST; if (!ismcast) { /* Unicast frame, check if an ACK is expected. */ if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) != IEEE80211_QOS_ACKPOLICY_NOACK) { txd->txdw4 = htole32(R12A_TXDW4_RETRY_LMT_ENA); txd->txdw4 |= htole32(SM(R12A_TXDW4_RETRY_LMT, maxretry)); } struct rtwn_node *un = RTWN_NODE(ni); macid = un->id; if (type == IEEE80211_FC0_TYPE_DATA) { qsel = tid % RTWN_MAX_TID; if (m->m_flags & M_AMPDU_MPDU) { txd->txdw2 |= htole32(R12A_TXDW2_AGGEN); txd->txdw2 |= htole32(SM(R12A_TXDW2_AMPDU_DEN, vap->iv_ampdu_density)); txd->txdw3 |= htole32(SM(R12A_TXDW3_MAX_AGG, 0x1f)); /* XXX */ } else txd->txdw2 |= htole32(R12A_TXDW2_AGGBK); if (sc->sc_ratectl == RTWN_RATECTL_NET80211) { txd->txdw2 |= htole32(R12A_TXDW2_SPE_RPT); sc->sc_tx_n_active++; } if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT); prot = IEEE80211_PROT_NONE; - if (ridx >= RTWN_RIDX_MCS(0)) { + if (ridx >= RTWN_RIDX_HT_MCS(0)) { r12a_tx_set_ht40(sc, txd, ni); r12a_tx_set_sgi(sc, txd, ni); r12a_tx_set_ldpc(sc, txd, ni); prot = ic->ic_htprotmode; } else if (ic->ic_flags & IEEE80211_F_USEPROT) prot = ic->ic_protmode; /* XXX fix last comparison for A-MSDU (in net80211) */ /* XXX A-MPDU? */ if (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold && vap->iv_rtsthreshold != IEEE80211_RTS_MAX) prot = IEEE80211_PROT_RTSCTS; if (prot != IEEE80211_PROT_NONE) r12a_tx_protection(sc, txd, prot, ridx); } else /* IEEE80211_FC0_TYPE_MGT */ qsel = R12A_TXDW1_QSEL_MGNT; } else { macid = RTWN_MACID_BC; qsel = R12A_TXDW1_QSEL_MGNT; } txd->txdw1 |= htole32(SM(R12A_TXDW1_QSEL, qsel)); txd->txdw1 |= htole32(SM(R12A_TXDW1_MACID, macid)); txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE, ridx)); /* Data rate fallback limit (max). */ txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE_FB_LMT, 0x1f)); /* XXX recheck for non-21au */ txd->txdw6 |= htole32(SM(R21A_TXDW6_MBSSID, uvp->id)); r12a_tx_raid(sc, txd, ni, ismcast); /* Force this rate if needed. */ if (sc->sc_ratectl != RTWN_RATECTL_FW) txd->txdw3 |= htole32(R12A_TXDW3_DRVRATE); if (!hasqos) { /* Use HW sequence numbering for non-QoS frames. */ txd->txdw8 |= htole32(R12A_TXDW8_HWSEQ_EN); txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, uvp->id)); } else { uint16_t seqno; if (m->m_flags & M_AMPDU_MPDU) { seqno = ni->ni_txseqs[tid]; ni->ni_txseqs[tid]++; } else seqno = M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE; /* Set sequence number. */ txd->txdw9 |= htole32(SM(R12A_TXDW9_SEQ, seqno)); } } void r12a_fill_tx_desc_raw(struct rtwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m, void *buf, const struct ieee80211_bpf_params *params) { struct ieee80211vap *vap = ni->ni_vap; struct rtwn_vap *uvp = RTWN_VAP(vap); struct ieee80211_frame *wh; struct r12a_tx_desc *txd; uint8_t ridx; int ismcast; /* XXX TODO: 11n checks, matching rtwn_fill_tx_desc() */ wh = mtod(m, struct ieee80211_frame *); ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); ridx = rate2ridx(params->ibp_rate0); /* Fill Tx descriptor. */ txd = (struct r12a_tx_desc *)buf; txd->flags0 |= R12A_FLAGS0_LSG | R12A_FLAGS0_FSG; if (ismcast) txd->flags0 |= R12A_FLAGS0_BMCAST; if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) { txd->txdw4 = htole32(R12A_TXDW4_RETRY_LMT_ENA); txd->txdw4 |= htole32(SM(R12A_TXDW4_RETRY_LMT, params->ibp_try0)); } if (params->ibp_flags & IEEE80211_BPF_RTS) r12a_tx_protection(sc, txd, IEEE80211_PROT_RTSCTS, ridx); if (params->ibp_flags & IEEE80211_BPF_CTS) r12a_tx_protection(sc, txd, IEEE80211_PROT_CTSONLY, ridx); txd->txdw1 |= htole32(SM(R12A_TXDW1_MACID, RTWN_MACID_BC)); txd->txdw1 |= htole32(SM(R12A_TXDW1_QSEL, R12A_TXDW1_QSEL_MGNT)); /* Set TX rate index. */ txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE, ridx)); txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE_FB_LMT, 0x1f)); txd->txdw6 |= htole32(SM(R21A_TXDW6_MBSSID, uvp->id)); txd->txdw3 |= htole32(R12A_TXDW3_DRVRATE); r12a_tx_raid(sc, txd, ni, ismcast); if (!IEEE80211_QOS_HAS_SEQ(wh)) { /* Use HW sequence numbering for non-QoS frames. */ txd->txdw8 |= htole32(R12A_TXDW8_HWSEQ_EN); txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, uvp->id)); } else { /* Set sequence number. */ txd->txdw9 |= htole32(SM(R12A_TXDW9_SEQ, M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE)); } } void r12a_fill_tx_desc_null(struct rtwn_softc *sc, void *buf, int is11b, int qos, int id) { struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf; txd->flags0 = R12A_FLAGS0_FSG | R12A_FLAGS0_LSG | R12A_FLAGS0_OWN; txd->txdw1 = htole32( SM(R12A_TXDW1_QSEL, R12A_TXDW1_QSEL_MGNT)); txd->txdw3 = htole32(R12A_TXDW3_DRVRATE); txd->txdw6 = htole32(SM(R21A_TXDW6_MBSSID, id)); if (is11b) { txd->txdw4 = htole32(SM(R12A_TXDW4_DATARATE, RTWN_RIDX_CCK1)); } else { txd->txdw4 = htole32(SM(R12A_TXDW4_DATARATE, RTWN_RIDX_OFDM6)); } if (!qos) { txd->txdw8 = htole32(R12A_TXDW8_HWSEQ_EN); txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, id)); } } uint8_t r12a_tx_radiotap_flags(const void *buf) { const struct r12a_tx_desc *txd = buf; uint8_t flags, rate; if (!(txd->txdw5 & htole32(R12A_TXDW5_DATA_SHORT))) return (0); rate = MS(le32toh(txd->txdw4), R12A_TXDW4_DATARATE); if (RTWN_RATE_IS_CCK(rate)) flags = IEEE80211_RADIOTAP_F_SHORTPRE; else flags = IEEE80211_RADIOTAP_F_SHORTGI; return (flags); }