aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/rtwn/if_rtwn.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/rtwn/if_rtwn.c')
-rw-r--r--sys/dev/rtwn/if_rtwn.c140
1 files changed, 134 insertions, 6 deletions
diff --git a/sys/dev/rtwn/if_rtwn.c b/sys/dev/rtwn/if_rtwn.c
index 4334d5700e51..7a547e13cafa 100644
--- a/sys/dev/rtwn/if_rtwn.c
+++ b/sys/dev/rtwn/if_rtwn.c
@@ -232,6 +232,7 @@ rtwn_attach(struct rtwn_softc *sc)
| IEEE80211_C_WME /* 802.11e */
| IEEE80211_C_SWAMSDUTX /* Do software A-MSDU TX */
| IEEE80211_C_FF /* Atheros fast-frames */
+ | IEEE80211_C_TXPMGT /* TX power control */
;
if (sc->sc_hwcrypto != RTWN_CRYPTO_SW) {
@@ -247,6 +248,7 @@ rtwn_attach(struct rtwn_softc *sc)
| IEEE80211_HTCAP_SMPS_OFF /* SM PS mode disabled */
/* s/w capabilities */
| IEEE80211_HTC_HT /* HT operation */
+ | IEEE80211_HTC_RX_AMSDU_AMPDU /* A-MSDU in A-MPDU */
| IEEE80211_HTC_AMPDU /* A-MPDU tx */
| IEEE80211_HTC_AMSDU /* A-MSDU tx */
;
@@ -296,6 +298,11 @@ rtwn_attach(struct rtwn_softc *sc)
sc->sc_node_free = ic->ic_node_free;
ic->ic_node_free = rtwn_node_free;
+ /* Note: this has to happen AFTER ieee80211_ifattach() */
+ ieee80211_set_software_ciphers(ic, IEEE80211_CRYPTO_WEP |
+ IEEE80211_CRYPTO_TKIP | IEEE80211_CRYPTO_AES_CCM |
+ IEEE80211_CRYPTO_AES_GCM_128);
+
rtwn_postattach(sc);
rtwn_radiotap_attach(sc);
@@ -319,18 +326,55 @@ rtwn_radiotap_attach(struct rtwn_softc *sc)
&rxtap->wr_ihdr, sizeof(*rxtap), RTWN_RX_RADIOTAP_PRESENT);
}
+#ifdef RTWN_DEBUG
+static int
+rtwn_sysctl_reg_readwrite(SYSCTL_HANDLER_ARGS)
+{
+ struct rtwn_softc *sc = arg1;
+ int error;
+ uint32_t val;
+
+ if (sc->sc_reg_addr > 0xffff)
+ return (EINVAL);
+
+ RTWN_LOCK(sc);
+ val = rtwn_read_4(sc, sc->sc_reg_addr);
+ RTWN_UNLOCK(sc);
+ error = sysctl_handle_int(oidp, &val, 0, req);
+ if (error || !req->newptr)
+ return (error);
+ RTWN_LOCK(sc);
+ rtwn_write_4(sc, sc->sc_reg_addr, val);
+ RTWN_UNLOCK(sc);
+ return (0);
+}
+#endif /* RTWN_DEBUG */
+
void
rtwn_sysctlattach(struct rtwn_softc *sc)
{
struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
-#if 1
+ sc->sc_reg_addr = 0;
+#ifdef RTWN_DEBUG
+ SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "reg_addr", CTLFLAG_RW, &sc->sc_reg_addr,
+ sc->sc_reg_addr, "debug register address");
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "reg_val", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+ rtwn_sysctl_reg_readwrite, "I", "debug register read/write");
+#endif /* RTWN_DEBUG */
+
sc->sc_ht40 = 0;
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"ht40", CTLFLAG_RDTUN, &sc->sc_ht40,
sc->sc_ht40, "Enable 40 MHz mode support");
-#endif
+
+ sc->sc_ena_tsf64 = 0;
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "ena_tsf64", CTLFLAG_RWTUN, &sc->sc_ena_tsf64,
+ sc->sc_ena_tsf64, "Enable/disable per-packet TSF64 reporting");
#ifdef RTWN_DEBUG
SYSCTL_ADD_U32(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
@@ -397,6 +441,29 @@ rtwn_resume(struct rtwn_softc *sc)
ieee80211_resume_all(ic);
}
+void
+rtwn_attach_vht_cap_info_mcs(struct rtwn_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ uint32_t rx_mcs = 0, tx_mcs = 0;
+
+ for (int i = 0 ; i < 8; i++) {
+ if (i < sc->ntxchains)
+ tx_mcs |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i*2));
+ else
+ tx_mcs |= (IEEE80211_VHT_MCS_NOT_SUPPORTED << (i*2));
+
+ if (i < sc->nrxchains)
+ rx_mcs |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i*2));
+ else
+ rx_mcs |= (IEEE80211_VHT_MCS_NOT_SUPPORTED << (i*2));
+ }
+ ic->ic_vht_cap.supp_mcs.rx_mcs_map = rx_mcs;
+ ic->ic_vht_cap.supp_mcs.rx_highest = 0;
+ ic->ic_vht_cap.supp_mcs.tx_mcs_map = tx_mcs;
+ ic->ic_vht_cap.supp_mcs.tx_highest = 0;
+}
+
static void
rtwn_vap_decrement_counters(struct rtwn_softc *sc,
enum ieee80211_opmode opmode, int id)
@@ -570,6 +637,7 @@ rtwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
/* 802.11n parameters */
vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_16;
vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_64K;
+ vap->iv_ampdu_limit = IEEE80211_HTCAP_MAXRXAMPDU_64K;
TIMEOUT_TASK_INIT(taskqueue_thread, &uvp->tx_beacon_csa, 0,
rtwn_tx_beacon_csa, vap);
@@ -691,6 +759,14 @@ rtwn_ioctl_reset(struct ieee80211vap *vap, u_long cmd)
case IEEE80211_IOC_LDPC:
error = 0;
break;
+ case IEEE80211_IOC_TXPOWER:
+ {
+ struct rtwn_softc *sc = vap->iv_ic->ic_softc;
+ RTWN_LOCK(sc);
+ error = rtwn_set_tx_power(sc, vap);
+ RTWN_UNLOCK(sc);
+ }
+ break;
default:
error = ENETRESET;
break;
@@ -954,6 +1030,8 @@ rtwn_tsf_sync_enable(struct rtwn_softc *sc, struct ieee80211vap *vap)
/* Enable TSF synchronization. */
rtwn_setbits_1(sc, R92C_BCN_CTRL(uvp->id),
R92C_BCN_CTRL_DIS_TSF_UDT0, 0);
+ /* Enable TSF beacon handling, needed for RA */
+ rtwn_sta_beacon_enable(sc, uvp->id, true);
break;
case IEEE80211_M_IBSS:
ieee80211_runtask(ic, &uvp->tsf_sync_adhoc_task);
@@ -1095,6 +1173,7 @@ rtwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
/* Disable TSF synchronization / beaconing. */
rtwn_beacon_enable(sc, uvp->id, 0);
+ rtwn_sta_beacon_enable(sc, uvp->id, false);
rtwn_setbits_1(sc, R92C_BCN_CTRL(uvp->id),
0, R92C_BCN_CTRL_DIS_TSF_UDT0);
@@ -1124,6 +1203,9 @@ rtwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
/* Stop Rx of data frames. */
rtwn_write_2(sc, R92C_RXFLTMAP2, 0);
+ /* Stop Rx of control frames. */
+ rtwn_write_2(sc, R92C_RXFLTMAP1, 0);
+
/* Reset EDCA parameters. */
rtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002f3217);
rtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4317);
@@ -1188,7 +1270,8 @@ rtwn_calc_basicrates(struct rtwn_softc *sc)
struct rtwn_vap *rvp;
struct ieee80211vap *vap;
struct ieee80211_node *ni;
- uint32_t rates;
+ struct ieee80211_htrateset *rs_ht;
+ uint32_t rates = 0, htrates = 0;
rvp = sc->vaps[i];
if (rvp == NULL || rvp->curr_mode == R92C_MSR_NOLINK)
@@ -1199,16 +1282,48 @@ rtwn_calc_basicrates(struct rtwn_softc *sc)
continue;
ni = ieee80211_ref_node(vap->iv_bss);
- rtwn_get_rates(sc, &ni->ni_rates, NULL, &rates, NULL, 1);
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ rs_ht = &ni->ni_htrates;
+ else
+ rs_ht = NULL;
+ /*
+ * Only fetches basic rates; fetch 802.11abg and 11n basic
+ * rates
+ */
+ rtwn_get_rates(sc, &ni->ni_rates, rs_ht, &rates, &htrates,
+ NULL, 1);
+
+ /*
+ * We need at least /an/ OFDM and/or MCS rate for HT
+ * operation, or the MAC will generate MCS7 ACK/Block-ACK
+ * frames and thus performance will suffer.
+ */
+ if (ni->ni_flags & IEEE80211_NODE_HT) {
+ htrates |= 0x01; /* MCS0 */
+ rates |= (1 << RTWN_RIDX_OFDM6);
+ }
+
basicrates |= rates;
+ basicrates |= (htrates << RTWN_RIDX_HT_MCS_SHIFT);
+
+ /* Filter out undesired high rates */
+ if (ni->ni_chan != IEEE80211_CHAN_ANYC &&
+ IEEE80211_IS_CHAN_5GHZ(ni->ni_chan))
+ basicrates &= R92C_RRSR_RATE_MASK_5GHZ;
+ else
+ basicrates &= R92C_RRSR_RATE_MASK_2GHZ;
+
ieee80211_free_node(ni);
}
- if (basicrates == 0)
+ if (basicrates == 0) {
+ device_printf(sc->sc_dev,
+ "WARNING: no configured basic rates!\n");
return;
+ }
- /* XXX initial RTS rate? */
rtwn_set_basicrates(sc, basicrates);
+ rtwn_set_rts_rate(sc, basicrates);
}
static int
@@ -1262,6 +1377,11 @@ rtwn_run(struct rtwn_softc *sc, struct ieee80211vap *vap)
rtwn_write_2(sc, R92C_BCN_INTERVAL(uvp->id), ni->ni_intval);
if (sc->vaps_running == sc->monvaps_running) {
+ /* Enable Rx of BAR control frames. */
+ rtwn_write_2(sc, R92C_RXFLTMAP1,
+ 1 << (IEEE80211_FC0_SUBTYPE_BAR >>
+ IEEE80211_FC0_SUBTYPE_SHIFT));
+
/* Enable Rx of data frames. */
rtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff);
@@ -1539,6 +1659,14 @@ rtwn_getradiocaps(struct ieee80211com *ic,
/* XXX workaround add_channel_list() limitations */
setbit(bands, IEEE80211_MODE_11A);
setbit(bands, IEEE80211_MODE_11NA);
+
+ if (IEEE80211_CONF_VHT(ic)) {
+ setbit(bands, IEEE80211_MODE_VHT_5GHZ);
+ /* Only enable VHT80 if HT40/VHT40 is available */
+ if (sc->sc_ht40)
+ cbw_flags |= NET80211_CBW_FLAG_VHT80;
+ }
+
for (i = 0; i < nitems(sc->chan_num_5ghz); i++) {
if (sc->chan_num_5ghz[i] == 0)
continue;