This patch adds initial support for 40Mhz channels to the iwm driver.
There are a few changes in net80211 to support this feature in RA and
when parsing beacons. The work for net80211 is not yet complete but
more can be done incrementally later. What is missing in particular
is integration with ifconfig to display the use of a 40 MHz channel.
And there is no way to force 40 MHz off at the client side yet.
If the AP announces support for 40MHz we will always use it. Whether or
not we'll need an override to handle some edge case remains to be seen.
Please test this on any supported iwm(4) device. Thanks!
diff 4056ab6b22f0b2cb4f14b2b237355717bf154e4f refs/heads/40mhz
blob - fbf2059a1571c2c55b40fce5ffd7d145ab6b1f21
blob + 3bf02ee0969978149c20498a469c1a2dcf4d7177
--- sys/dev/ic/ar5008.c
+++ sys/dev/ic/ar5008.c
@@ -1150,7 +1150,7 @@ ar5008_tx_process(struct athn_softc *sc, int qid)
/* Update rate control statistics. */
if ((ni->ni_flags & IEEE80211_NODE_HT) && ic->ic_fixed_mcs == -1) {
const struct ieee80211_ht_rateset *rs =
- ieee80211_ra_get_ht_rateset(bf->bf_txmcs,
+ ieee80211_ra_get_ht_rateset(bf->bf_txmcs, 0 /* chan40 */,
ieee80211_node_supports_ht_sgi20(ni));
unsigned int retries = 0, i;
int mcs = bf->bf_txmcs;
blob - 6a145720d3070bd0c1eabae1bedddb5da8fb72a2
blob + 687cbf94f135f6586193b1724e52b80e7f16a529
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -335,9 +335,11 @@ void iwm_init_channel_map(struct iwm_softc *, const
ui
int iwm_mimo_enabled(struct iwm_softc *);
void iwm_setup_ht_rates(struct iwm_softc *);
void iwm_mac_ctxt_task(void *);
+void iwm_phy_ctxt_task(void *);
void iwm_updateprot(struct ieee80211com *);
void iwm_updateslot(struct ieee80211com *);
void iwm_updateedca(struct ieee80211com *);
+void iwm_updatechan(struct ieee80211com *);
void iwm_init_reorder_buffer(struct iwm_reorder_buffer *, uint16_t,
uint16_t);
void iwm_clear_reorder_buffer(struct iwm_softc *, struct iwm_rxba_data *);
@@ -408,13 +410,13 @@ void iwm_rx_bmiss(struct iwm_softc *, struct
iwm_rx_pa
struct iwm_rx_data *);
int iwm_binding_cmd(struct iwm_softc *, struct iwm_node *, uint32_t);
int iwm_phy_ctxt_cmd_uhb(struct iwm_softc *, struct iwm_phy_ctxt *, uint8_t,
- uint8_t, uint32_t, uint32_t);
+ uint8_t, uint32_t, uint32_t, uint8_t);
void iwm_phy_ctxt_cmd_hdr(struct iwm_softc *, struct iwm_phy_ctxt *,
struct iwm_phy_context_cmd *, uint32_t, uint32_t);
void iwm_phy_ctxt_cmd_data(struct iwm_softc *, struct iwm_phy_context_cmd *,
- struct ieee80211_channel *, uint8_t, uint8_t);
+ struct ieee80211_channel *, uint8_t, uint8_t, uint8_t);
int iwm_phy_ctxt_cmd(struct iwm_softc *, struct iwm_phy_ctxt *, uint8_t,
- uint8_t, uint32_t, uint32_t);
+ uint8_t, uint32_t, uint32_t, uint8_t);
int iwm_send_cmd(struct iwm_softc *, struct iwm_host_cmd *);
int iwm_send_cmd_pdu(struct iwm_softc *, uint32_t, uint32_t, uint16_t,
const void *);
@@ -479,7 +481,7 @@ int iwm_umac_scan_abort(struct iwm_softc *);
int iwm_lmac_scan_abort(struct iwm_softc *);
int iwm_scan_abort(struct iwm_softc *);
int iwm_phy_ctxt_update(struct iwm_softc *, struct iwm_phy_ctxt *,
- struct ieee80211_channel *, uint8_t, uint8_t, uint32_t);
+ struct ieee80211_channel *, uint8_t, uint8_t, uint32_t, uint8_t);
int iwm_auth(struct iwm_softc *);
int iwm_deauth(struct iwm_softc *);
int iwm_run(struct iwm_softc *);
@@ -3075,8 +3077,11 @@ iwm_init_channel_map(struct iwm_softc *sc, const uint1
if (!(ch_flags & IWM_NVM_CHANNEL_ACTIVE))
channel->ic_flags |= IEEE80211_CHAN_PASSIVE;
- if (data->sku_cap_11n_enable)
+ if (data->sku_cap_11n_enable) {
channel->ic_flags |= IEEE80211_CHAN_HT;
+ if (ch_flags & IWM_NVM_CHANNEL_40MHZ)
+ channel->ic_flags |= IEEE80211_CHAN_40MHZ;
+ }
}
}
@@ -3409,6 +3414,51 @@ iwm_updateedca(struct ieee80211com *ic)
iwm_add_task(sc, systq, &sc->mac_ctxt_task);
}
+void
+iwm_phy_ctxt_task(void *arg)
+{
+ struct iwm_softc *sc = arg;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct iwm_node *in = (void *)ic->ic_bss;
+ struct ieee80211_node *ni = &in->in_ni;
+ uint8_t chains, sco;
+ int err, s = splnet();
+
+ if ((sc->sc_flags & IWM_FLAG_SHUTDOWN) ||
+ ic->ic_state != IEEE80211_S_RUN ||
+ in->in_phyctxt == NULL) {
+ refcnt_rele_wake(&sc->task_refs);
+ splx(s);
+ return;
+ }
+
+ chains = iwm_mimo_enabled(sc) ? 2 : 1;
+ if (ieee80211_node_supports_ht_chan40(ni))
+ sco = (ni->ni_htop0 & IEEE80211_HTOP0_SCO_MASK);
+ else
+ sco = IEEE80211_HTOP0_SCO_SCN;
+ if (in->in_phyctxt->sco != sco) {
+ err = iwm_phy_ctxt_update(sc, in->in_phyctxt,
+ in->in_phyctxt->channel, chains, chains, 0, sco);
+ if (err)
+ printf("%s: failed to update PHY\n", DEVNAME(sc));
+ iwm_setrates(in, 0);
+ }
+
+ refcnt_rele_wake(&sc->task_refs);
+ splx(s);
+}
+
+void
+iwm_updatechan(struct ieee80211com *ic)
+{
+ struct iwm_softc *sc = ic->ic_softc;
+
+ if (ic->ic_state == IEEE80211_S_RUN &&
+ !task_pending(&sc->newstate_task))
+ iwm_add_task(sc, systq, &sc->phy_ctxt_task);
+}
+
int
iwm_sta_tx_agg(struct iwm_softc *sc, struct ieee80211_node *ni, uint8_t tid,
uint16_t ssn, uint16_t winsize, int start)
@@ -5390,7 +5440,8 @@ iwm_ht_single_rate_control(struct iwm_softc *sc, struc
int mcs = txmcs;
const struct ieee80211_ht_rateset *rs =
ieee80211_ra_get_ht_rateset(txmcs,
- ieee80211_node_supports_ht_sgi20(ni));
+ ieee80211_node_supports_ht_chan40(ni),
+ ieee80211_ra_use_ht_sgi(ni));
unsigned int retries = 0, i;
in->lq_rate_mismatch = 0;
@@ -5883,7 +5934,7 @@ iwm_phy_ctxt_cmd_hdr(struct iwm_softc *sc, struct iwm_
void
iwm_phy_ctxt_cmd_data(struct iwm_softc *sc, struct iwm_phy_context_cmd *cmd,
struct ieee80211_channel *chan, uint8_t chains_static,
- uint8_t chains_dynamic)
+ uint8_t chains_dynamic, uint8_t sco)
{
struct ieee80211com *ic = &sc->sc_ic;
uint8_t active_cnt, idle_cnt;
@@ -5891,8 +5942,23 @@ iwm_phy_ctxt_cmd_data(struct iwm_softc *sc, struct iwm
cmd->ci.band = IEEE80211_IS_CHAN_2GHZ(chan) ?
IWM_PHY_BAND_24 : IWM_PHY_BAND_5;
cmd->ci.channel = ieee80211_chan2ieee(ic, chan);
- cmd->ci.width = IWM_PHY_VHT_CHANNEL_MODE20;
- cmd->ci.ctrl_pos = IWM_PHY_VHT_CTRL_POS_1_BELOW;
+ if (chan->ic_flags & IEEE80211_CHAN_40MHZ) {
+ if (sco == IEEE80211_HTOP0_SCO_SCA) {
+ /* secondary chan above -> control chan below */
+ cmd->ci.ctrl_pos = IWM_PHY_VHT_CTRL_POS_1_BELOW;
+ cmd->ci.width = IWM_PHY_VHT_CHANNEL_MODE40;
+ } else if (sco == IEEE80211_HTOP0_SCO_SCB) {
+ /* secondary chan below -> control chan above */
+ cmd->ci.ctrl_pos = IWM_PHY_VHT_CTRL_POS_1_ABOVE;
+ cmd->ci.width = IWM_PHY_VHT_CHANNEL_MODE40;
+ } else {
+ cmd->ci.width = IWM_PHY_VHT_CHANNEL_MODE20;
+ cmd->ci.ctrl_pos = IWM_PHY_VHT_CTRL_POS_1_BELOW;
+ }
+ } else {
+ cmd->ci.width = IWM_PHY_VHT_CHANNEL_MODE20;
+ cmd->ci.ctrl_pos = IWM_PHY_VHT_CTRL_POS_1_BELOW;
+ }
/* Set rx the chains */
idle_cnt = chains_static;
@@ -5910,7 +5976,7 @@ iwm_phy_ctxt_cmd_data(struct iwm_softc *sc, struct iwm
int
iwm_phy_ctxt_cmd_uhb(struct iwm_softc *sc, struct iwm_phy_ctxt *ctxt,
uint8_t chains_static, uint8_t chains_dynamic, uint32_t action,
- uint32_t apply_time)
+ uint32_t apply_time, uint8_t sco)
{
struct ieee80211com *ic = &sc->sc_ic;
struct iwm_phy_context_cmd_uhb cmd;
@@ -5926,8 +5992,23 @@ iwm_phy_ctxt_cmd_uhb(struct iwm_softc *sc, struct iwm_
cmd.ci.band = IEEE80211_IS_CHAN_2GHZ(chan) ?
IWM_PHY_BAND_24 : IWM_PHY_BAND_5;
cmd.ci.channel = htole32(ieee80211_chan2ieee(ic, chan));
- cmd.ci.width = IWM_PHY_VHT_CHANNEL_MODE20;
- cmd.ci.ctrl_pos = IWM_PHY_VHT_CTRL_POS_1_BELOW;
+ if (chan->ic_flags & IEEE80211_CHAN_40MHZ) {
+ if (sco == IEEE80211_HTOP0_SCO_SCA) {
+ /* secondary chan above -> control chan below */
+ cmd.ci.ctrl_pos = IWM_PHY_VHT_CTRL_POS_1_BELOW;
+ cmd.ci.width = IWM_PHY_VHT_CHANNEL_MODE40;
+ } else if (sco == IEEE80211_HTOP0_SCO_SCB) {
+ /* secondary chan below -> control chan above */
+ cmd.ci.ctrl_pos = IWM_PHY_VHT_CTRL_POS_1_ABOVE;
+ cmd.ci.width = IWM_PHY_VHT_CHANNEL_MODE40;
+ } else {
+ cmd.ci.width = IWM_PHY_VHT_CHANNEL_MODE20;
+ cmd.ci.ctrl_pos = IWM_PHY_VHT_CTRL_POS_1_BELOW;
+ }
+ } else {
+ cmd.ci.width = IWM_PHY_VHT_CHANNEL_MODE20;
+ cmd.ci.ctrl_pos = IWM_PHY_VHT_CTRL_POS_1_BELOW;
+ }
idle_cnt = chains_static;
active_cnt = chains_dynamic;
@@ -5944,7 +6025,7 @@ iwm_phy_ctxt_cmd_uhb(struct iwm_softc *sc, struct iwm_
int
iwm_phy_ctxt_cmd(struct iwm_softc *sc, struct iwm_phy_ctxt *ctxt,
uint8_t chains_static, uint8_t chains_dynamic, uint32_t action,
- uint32_t apply_time)
+ uint32_t apply_time, uint8_t sco)
{
struct iwm_phy_context_cmd cmd;
@@ -5957,12 +6038,12 @@ iwm_phy_ctxt_cmd(struct iwm_softc *sc, struct iwm_phy_
*/
if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_ULTRA_HB_CHANNELS))
return iwm_phy_ctxt_cmd_uhb(sc, ctxt, chains_static,
- chains_dynamic, action, apply_time);
+ chains_dynamic, action, apply_time, sco);
iwm_phy_ctxt_cmd_hdr(sc, ctxt, &cmd, action, apply_time);
iwm_phy_ctxt_cmd_data(sc, &cmd, ctxt->channel,
- chains_static, chains_dynamic);
+ chains_static, chains_dynamic, sco);
return iwm_send_cmd_pdu(sc, IWM_PHY_CONTEXT_CMD, 0,
sizeof(struct iwm_phy_context_cmd), &cmd);
@@ -6353,8 +6434,19 @@ iwm_tx_fill_cmd(struct iwm_softc *sc, struct iwm_node
if ((ni->ni_flags & IEEE80211_NODE_HT) &&
type == IEEE80211_FC0_TYPE_DATA &&
rinfo->ht_plcp != IWM_RATE_HT_SISO_MCS_INV_PLCP) {
+ uint8_t sco;
+ if (ieee80211_node_supports_ht_chan40(ni))
+ sco = (ni->ni_htop0 & IEEE80211_HTOP0_SCO_MASK);
+ else
+ sco = IEEE80211_HTOP0_SCO_SCN;
rate_flags |= IWM_RATE_MCS_HT_MSK;
- if (ieee80211_node_supports_ht_sgi20(ni))
+ if ((sco == IEEE80211_HTOP0_SCO_SCA ||
+ sco == IEEE80211_HTOP0_SCO_SCB) &&
+ in->in_phyctxt != NULL && in->in_phyctxt->sco == sco) {
+ rate_flags |= IWM_RATE_MCS_CHAN_WIDTH_40;
+ if (ieee80211_node_supports_ht_sgi40(ni))
+ rate_flags |= IWM_RATE_MCS_SGI_MSK;
+ } else if (ieee80211_node_supports_ht_sgi20(ni))
rate_flags |= IWM_RATE_MCS_SGI_MSK;
tx->rate_n_flags = htole32(rate_flags | rinfo->ht_plcp);
} else
@@ -6944,6 +7036,11 @@ iwm_add_sta_cmd(struct iwm_softc *sc, struct iwm_node
}
}
+ if (ieee80211_node_supports_ht_chan40(&in->in_ni)) {
+ add_sta_cmd.station_flags |= htole32(
+ IWM_STA_FLG_FAT_EN_40MHZ);
+ }
+
add_sta_cmd.station_flags
|= htole32(IWM_STA_FLG_MAX_AGG_SIZE_64K);
switch (ic->ic_ampdu_params & IEEE80211_AMPDU_PARAM_SS) {
@@ -7934,8 +8031,9 @@ iwm_mac_ctxt_cmd_common(struct iwm_softc *sc, struct i
IWM_MAC_PROT_FLG_FAT_PROT);
break;
case IEEE80211_HTPROT_20MHZ:
- if (ic->ic_htcaps & IEEE80211_HTCAP_CBW20_40) {
- /* XXX ... and if our channel is 40 MHz ... */
+ if (in->in_phyctxt &&
+ (in->in_phyctxt->sco == IEEE80211_HTOP0_SCO_SCA ||
+ in->in_phyctxt->sco == IEEE80211_HTOP0_SCO_SCB)) {
cmd->protection_flags |=
htole32(IWM_MAC_PROT_FLG_HT_PROT |
IWM_MAC_PROT_FLG_FAT_PROT);
@@ -8238,7 +8336,7 @@ iwm_scan_abort(struct iwm_softc *sc)
int
iwm_phy_ctxt_update(struct iwm_softc *sc, struct iwm_phy_ctxt *phyctxt,
struct ieee80211_channel *chan, uint8_t chains_static,
- uint8_t chains_dynamic, uint32_t apply_time)
+ uint8_t chains_dynamic, uint32_t apply_time, uint8_t sco)
{
uint16_t band_flags = (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ);
int err;
@@ -8248,7 +8346,7 @@ iwm_phy_ctxt_update(struct iwm_softc *sc, struct iwm_p
(phyctxt->channel->ic_flags & band_flags) !=
(chan->ic_flags & band_flags)) {
err = iwm_phy_ctxt_cmd(sc, phyctxt, chains_static,
- chains_dynamic, IWM_FW_CTXT_ACTION_REMOVE, apply_time);
+ chains_dynamic, IWM_FW_CTXT_ACTION_REMOVE, apply_time, sco);
if (err) {
printf("%s: could not remove PHY context "
"(error %d)\n", DEVNAME(sc), err);
@@ -8256,7 +8354,7 @@ iwm_phy_ctxt_update(struct iwm_softc *sc, struct iwm_p
}
phyctxt->channel = chan;
err = iwm_phy_ctxt_cmd(sc, phyctxt, chains_static,
- chains_dynamic, IWM_FW_CTXT_ACTION_ADD, apply_time);
+ chains_dynamic, IWM_FW_CTXT_ACTION_ADD, apply_time, sco);
if (err) {
printf("%s: could not remove PHY context "
"(error %d)\n", DEVNAME(sc), err);
@@ -8265,7 +8363,7 @@ iwm_phy_ctxt_update(struct iwm_softc *sc, struct iwm_p
} else {
phyctxt->channel = chan;
err = iwm_phy_ctxt_cmd(sc, phyctxt, chains_static,
- chains_dynamic, IWM_FW_CTXT_ACTION_MODIFY, apply_time);
+ chains_dynamic, IWM_FW_CTXT_ACTION_MODIFY, apply_time, sco);
if (err) {
printf("%s: could not update PHY context (error %d)\n",
DEVNAME(sc), err);
@@ -8273,6 +8371,7 @@ iwm_phy_ctxt_update(struct iwm_softc *sc, struct iwm_p
}
}
+ phyctxt->sco = sco;
return 0;
}
@@ -8288,17 +8387,18 @@ iwm_auth(struct iwm_softc *sc)
if (ic->ic_opmode == IEEE80211_M_MONITOR) {
err = iwm_phy_ctxt_update(sc, &sc->sc_phyctxt[0],
- ic->ic_ibss_chan, 1, 1, 0);
+ ic->ic_ibss_chan, 1, 1, 0, IEEE80211_HTOP0_SCO_SCN);
if (err)
return err;
} else {
err = iwm_phy_ctxt_update(sc, &sc->sc_phyctxt[0],
- in->in_ni.ni_chan, 1, 1, 0);
+ in->in_ni.ni_chan, 1, 1, 0, IEEE80211_HTOP0_SCO_SCN);
if (err)
return err;
}
in->in_phyctxt = &sc->sc_phyctxt[0];
IEEE80211_ADDR_COPY(in->in_macaddr, in->in_ni.ni_macaddr);
+ iwm_setrates(in, 0);
err = iwm_mac_ctxt_cmd(sc, in, IWM_FW_CTXT_ACTION_ADD, 0);
if (err) {
@@ -8406,7 +8506,7 @@ iwm_deauth(struct iwm_softc *sc)
/* Move unused PHY context to a default channel. */
err = iwm_phy_ctxt_update(sc, &sc->sc_phyctxt[0],
- &ic->ic_channels[1], 1, 1, 0);
+ &ic->ic_channels[1], 1, 1, 0, IEEE80211_HTOP0_SCO_SCN);
if (err)
return err;
@@ -8418,6 +8518,7 @@ iwm_run(struct iwm_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
struct iwm_node *in = (void *)ic->ic_bss;
+ struct ieee80211_node *ni = &in->in_ni;
int err;
splassert(IPL_NET);
@@ -8429,16 +8530,30 @@ iwm_run(struct iwm_softc *sc)
return err;
}
- /* Configure Rx chains for MIMO. */
- if ((ic->ic_opmode == IEEE80211_M_MONITOR ||
- (in->in_ni.ni_flags & IEEE80211_NODE_HT)) &&
- iwm_mimo_enabled(sc)) {
- err = iwm_phy_ctxt_update(sc, &sc->sc_phyctxt[0],
- in->in_ni.ni_chan, 2, 2, 0);
+ /* Configure Rx chains for MIMO and configure 40 MHz channel. */
+ if (ic->ic_opmode == IEEE80211_M_MONITOR) {
+ uint8_t chains = iwm_mimo_enabled(sc) ? 2 : 1;
+ err = iwm_phy_ctxt_update(sc, in->in_phyctxt,
+ in->in_phyctxt->channel, chains, chains,
+ 0, IEEE80211_HTOP0_SCO_SCN);
if (err) {
printf("%s: failed to update PHY\n", DEVNAME(sc));
return err;
}
+ } else if (ni->ni_flags & IEEE80211_NODE_HT) {
+ uint8_t chains = iwm_mimo_enabled(sc) ? 2 : 1;
+ uint8_t sco;
+ if (ieee80211_node_supports_ht_chan40(ni))
+ sco = (ni->ni_htop0 & IEEE80211_HTOP0_SCO_MASK);
+ else
+ sco = IEEE80211_HTOP0_SCO_SCN;
+ err = iwm_phy_ctxt_update(sc, in->in_phyctxt,
+ in->in_phyctxt->channel, chains, chains,
+ 0, sco);
+ if (err) {
+ printf("%s: failed to update PHY\n", DEVNAME(sc));
+ return err;
+ }
}
/* Update STA again, for HT-related settings such as MIMO. */
@@ -8593,11 +8708,10 @@ iwm_run_stop(struct iwm_softc *sc)
return err;
}
- /* Reset Tx chains in case MIMO was enabled. */
- if ((in->in_ni.ni_flags & IEEE80211_NODE_HT) &&
- iwm_mimo_enabled(sc)) {
- err = iwm_phy_ctxt_update(sc, &sc->sc_phyctxt[0],
- in->in_ni.ni_chan, 1, 1, 0);
+ /* Reset Tx chains in case MIMO or 40 MHz channels were enabled. */
+ if (in->in_ni.ni_flags & IEEE80211_NODE_HT) {
+ err = iwm_phy_ctxt_update(sc, in->in_phyctxt,
+ in->in_phyctxt->channel, 1, 1, 0, IEEE80211_HTOP0_SCO_SCN);
if (err) {
printf("%s: failed to update PHY\n", DEVNAME(sc));
return err;
@@ -8760,7 +8874,7 @@ iwm_setrates(struct iwm_node *in, int async)
struct iwm_softc *sc = IC2IFP(ic)->if_softc;
struct iwm_lq_cmd lqcmd;
struct ieee80211_rateset *rs = &ni->ni_rates;
- int i, ridx, ridx_min, ridx_max, j, sgi_ok = 0, mimo, tab = 0;
+ int i, ridx, ridx_min, ridx_max, j, mimo, tab = 0;
struct iwm_host_cmd cmd = {
.id = IWM_LQ_CMD,
.len = { sizeof(lqcmd), },
@@ -8774,12 +8888,6 @@ iwm_setrates(struct iwm_node *in, int async)
if (ic->ic_flags & IEEE80211_F_USEPROT)
lqcmd.flags |= IWM_LQ_FLAG_USE_RTS_MSK;
- if ((ni->ni_flags & IEEE80211_NODE_HT) &&
- ieee80211_node_supports_ht_sgi20(ni)) {
- ni->ni_flags |= IEEE80211_NODE_HT_SGI20;
- sgi_ok = 1;
- }
-
/*
* Fill the LQ rate selection table with legacy and/or HT rates
* in descending order, i.e. with the node's current TX rate first.
@@ -8810,13 +8918,23 @@ iwm_setrates(struct iwm_node *in, int async)
for (i = ni->ni_txmcs; i >= 0; i--) {
if (isclr(ni->ni_rxmcs, i))
continue;
- if (ridx == iwm_mcs2ridx[i]) {
- tab = ht_plcp;
- tab |= IWM_RATE_MCS_HT_MSK;
- if (sgi_ok)
- tab |= IWM_RATE_MCS_SGI_MSK;
+ if (ridx != iwm_mcs2ridx[i])
+ continue;
+ tab = ht_plcp;
+ tab |= IWM_RATE_MCS_HT_MSK;
+ /* First two Tx attempts may use 40MHz/SGI. */
+ if (j > 1)
break;
+ if (in->in_phyctxt->sco ==
+ IEEE80211_HTOP0_SCO_SCA ||
+ in->in_phyctxt->sco ==
+ IEEE80211_HTOP0_SCO_SCB) {
+ tab |= IWM_RATE_MCS_CHAN_WIDTH_40;
+ tab |= IWM_RATE_MCS_RTS_REQUIRED_MSK;
}
+ if (ieee80211_ra_use_ht_sgi(ni))
+ tab |= IWM_RATE_MCS_SGI_MSK;
+ break;
}
} else if (plcp != IWM_RATE_INVM_PLCP) {
for (i = ni->ni_txrate; i >= 0; i--) {
@@ -9017,6 +9135,7 @@ iwm_newstate(struct ieee80211com *ic, enum ieee80211_s
timeout_del(&sc->sc_calib_to);
iwm_del_task(sc, systq, &sc->ba_task);
iwm_del_task(sc, systq, &sc->mac_ctxt_task);
+ iwm_del_task(sc, systq, &sc->phy_ctxt_task);
}
sc->ns_nstate = nstate;
@@ -9652,7 +9771,7 @@ iwm_init_hw(struct iwm_softc *sc)
sc->sc_phyctxt[i].id = i;
sc->sc_phyctxt[i].channel = &ic->ic_channels[1];
err = iwm_phy_ctxt_cmd(sc, &sc->sc_phyctxt[i], 1, 1,
- IWM_FW_CTXT_ACTION_ADD, 0);
+ IWM_FW_CTXT_ACTION_ADD, 0, IEEE80211_HTOP0_SCO_SCN);
if (err) {
printf("%s: could not add phy context %d (error %d)\n",
DEVNAME(sc), i, err);
@@ -9911,6 +10030,7 @@ iwm_stop(struct ifnet *ifp)
iwm_del_task(sc, sc->sc_nswq, &sc->newstate_task);
iwm_del_task(sc, systq, &sc->ba_task);
iwm_del_task(sc, systq, &sc->mac_ctxt_task);
+ iwm_del_task(sc, systq, &sc->phy_ctxt_task);
KASSERT(sc->task_refs.refs >= 1);
refcnt_finalize(&sc->task_refs, "iwmstop");
@@ -11321,7 +11441,8 @@ iwm_attach(struct device *parent, struct device *self,
IEEE80211_C_SHSLOT | /* short slot time supported */
IEEE80211_C_SHPREAMBLE; /* short preamble supported */
- ic->ic_htcaps = IEEE80211_HTCAP_SGI20;
+ ic->ic_htcaps = IEEE80211_HTCAP_SGI20 | IEEE80211_HTCAP_SGI40;
+ ic->ic_htcaps |= IEEE80211_HTCAP_CBW20_40;
ic->ic_htcaps |=
(IEEE80211_HTCAP_SMPS_DIS << IEEE80211_HTCAP_SMPS_SHIFT);
ic->ic_htxcaps = 0;
@@ -11335,6 +11456,7 @@ iwm_attach(struct device *parent, struct device *self,
for (i = 0; i < nitems(sc->sc_phyctxt); i++) {
sc->sc_phyctxt[i].id = i;
+ sc->sc_phyctxt[i].sco = IEEE80211_HTOP0_SCO_SCN;
}
sc->sc_amrr.amrr_min_success_threshold = 1;
@@ -11376,6 +11498,7 @@ iwm_attach(struct device *parent, struct device *self,
task_set(&sc->newstate_task, iwm_newstate_task, sc);
task_set(&sc->ba_task, iwm_ba_task, sc);
task_set(&sc->mac_ctxt_task, iwm_mac_ctxt_task, sc);
+ task_set(&sc->phy_ctxt_task, iwm_phy_ctxt_task, sc);
ic->ic_node_alloc = iwm_node_alloc;
ic->ic_bgscan_start = iwm_bgscan;
blob - ce7898fd501733b25a2c616805444c0bc4a1b05a
blob + fc08f24ee297062858ca21541e6af6259acb24cc
--- sys/dev/pci/if_iwmreg.h
+++ sys/dev/pci/if_iwmreg.h
@@ -4519,6 +4519,9 @@ enum {
#define IWM_RATE_MCS_VHT_POS 26
#define IWM_RATE_MCS_VHT_MSK (1 << IWM_RATE_MCS_VHT_POS)
+/* Bit 31: (1) RTS (2) CTS */
+#define IWM_RATE_MCS_RTS_REQUIRED_POS 30
+#define IWM_RATE_MCS_RTS_REQUIRED_MSK (1 << IWM_RATE_MCS_RTS_REQUIRED_POS)
/*
* High-throughput (HT) rate format for bits 7:0
blob - 1d94b1a708b15de1aa95d2d7dd1da738de53a15d
blob + 74a24e771de8bb26f0ae6243c503184a42b5cae6
--- sys/dev/pci/if_iwmvar.h
+++ sys/dev/pci/if_iwmvar.h
@@ -360,6 +360,7 @@ struct iwm_phy_ctxt {
uint16_t color;
uint32_t ref;
struct ieee80211_channel *channel;
+ uint8_t sco; /* 40 MHz secondary channel offset */
};
struct iwm_bf_data {
@@ -491,6 +492,9 @@ struct iwm_softc {
/* Task for ERP/HT prot/slot-time/EDCA updates. */
struct task mac_ctxt_task;
+ /* Task for HT 20/40 MHz channel width updates. */
+ struct task phy_ctxt_task;
+
bus_space_tag_t sc_st;
bus_space_handle_t sc_sh;
bus_size_t sc_sz;
blob - 2870256d8375776a759685d87786c8e14e31761f
blob + 4aa6f536d1cb679f0eb4eeb27488e6753774f95f
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -2283,8 +2283,8 @@ iwn_ht_single_rate_control(struct iwn_softc *sc, struc
struct iwn_node *wn = (void *)ni;
int mcs = rate;
const struct ieee80211_ht_rateset *rs =
- ieee80211_ra_get_ht_rateset(rate,
- ieee80211_node_supports_ht_sgi20(ni));
+ ieee80211_ra_get_ht_rateset(rate, 0 /* chan40 */,
+ ieee80211_ra_use_ht_sgi(ni));
unsigned int retries = 0, i;
/*
blob - e313d22d1a6ef3fd7eabd2ae546efa53618fb69b
blob + f3ea1d69c3ca9d796202dc4bfe97518acbeac9c6
--- sys/net80211/ieee80211.c
+++ sys/net80211/ieee80211.c
@@ -824,28 +824,68 @@ const struct ieee80211_rateset ieee80211_std_rateset_1
const struct ieee80211_ht_rateset ieee80211_std_ratesets_11n[] = {
/* MCS 0-7, 20MHz channel, no SGI */
- { 8, { 13, 26, 39, 52, 78, 104, 117, 130 }, 0x000000ff, 0, 7, 0},
+ { 8, { 13, 26, 39, 52, 78, 104, 117, 130 },
+ 0x000000ff, 0, 7, 0, 0},
/* MCS 0-7, 20MHz channel, SGI */
- { 8, { 14, 29, 43, 58, 87, 116, 130, 144 }, 0x000000ff, 0, 7, 1 },
+ { 8, { 14, 29, 43, 58, 87, 116, 130, 144 },
+ 0x000000ff, 0, 7, 0, 1 },
/* MCS 8-15, 20MHz channel, no SGI */
- { 8, { 26, 52, 78, 104, 156, 208, 234, 260 }, 0x0000ff00, 8, 15, 0 },
+ { 8, { 26, 52, 78, 104, 156, 208, 234, 260 },
+ 0x0000ff00, 8, 15, 0, 0 },
/* MCS 8-15, 20MHz channel, SGI */
- { 8, { 29, 58, 87, 116, 173, 231, 261, 289 }, 0x0000ff00, 8, 15, 1 },
+ { 8, { 29, 58, 87, 116, 173, 231, 261, 289 },
+ 0x0000ff00, 8, 15, 0, 1 },
/* MCS 16-23, 20MHz channel, no SGI */
- { 8, { 39, 78, 117, 156, 234, 312, 351, 390 }, 0x00ff0000, 16, 23, 0 },
+ { 8, { 39, 78, 117, 156, 234, 312, 351, 390 },
+ 0x00ff0000, 16, 23, 0, 0 },
/* MCS 16-23, 20MHz channel, SGI */
- { 8, { 43, 87, 130, 173, 260, 347, 390, 433 }, 0x00ff0000, 16, 23, 1 },
+ { 8, { 43, 87, 130, 173, 260, 347, 390, 433 },
+ 0x00ff0000, 16, 23, 0, 1 },
/* MCS 24-31, 20MHz channel, no SGI */
- { 8, { 52, 104, 156, 208, 312, 416, 468, 520 }, 0xff000000, 24, 31, 0 },
+ { 8, { 52, 104, 156, 208, 312, 416, 468, 520 },
+ 0xff000000, 24, 31, 0, 0 },
/* MCS 24-31, 20MHz channel, SGI */
- { 8, { 58, 116, 173, 231, 347, 462, 520, 578 }, 0xff000000, 24, 31, 1 },
+ { 8, { 58, 116, 173, 231, 347, 462, 520, 578 },
+ 0xff000000, 24, 31, 0, 1 },
+
+ /* MCS 0-7, 40MHz channel, no SGI */
+ { 8, { 27, 54, 81, 108, 162, 216, 243, 270 },
+ 0x000000ff, 0, 7, 1, 0 },
+
+ /* MCS 0-7, 40MHz channel, SGI */
+ { 8, { 30, 60, 90, 120, 180, 240, 270, 300 },
+ 0x000000ff, 0, 7, 1, 1 },
+
+ /* MCS 8-15, 40MHz channel, no SGI */
+ { 8, { 54, 108, 192, 216, 324, 432, 486, 540 },
+ 0x0000ff00, 8, 15, 1, 0 },
+
+ /* MCS 8-15, 40MHz channel, SGI */
+ { 8, { 60, 120, 180, 240, 360, 480, 540, 600 },
+ 0x0000ff00, 8, 15, 1, 1 },
+
+ /* MCS 16-23, 40MHz channel, no SGI */
+ { 8, { 81, 162, 243, 324, 486, 648, 729, 810 },
+ 0x00ff0000, 16, 23, 1, 0 },
+
+ /* MCS 16-23, 40MHz channel, SGI */
+ { 8, { 90, 180, 270, 360, 540, 720, 810, 900 },
+ 0x00ff0000, 16, 23, 1, 1 },
+
+ /* MCS 24-31, 40MHz channel, no SGI */
+ { 8, { 108, 216, 324, 432, 324, 864, 972, 1080 },
+ 0xff000000, 24, 31, 1, 0 },
+
+ /* MCS 24-31, 40MHz channel, SGI */
+ { 8, { 120, 240, 360, 480, 520, 960, 1080, 1200 },
+ 0xff000000, 24, 31, 1, 1 },
};
const struct ieee80211_vht_rateset ieee80211_std_ratesets_11ac[] = {
blob - 99699b933a0ed0e68c48abc417814fad04c05df9
blob + b5fbc95d2aaaca166bf0d33dde2a58403bf54862
--- sys/net80211/ieee80211_input.c
+++ sys/net80211/ieee80211_input.c
@@ -1858,6 +1858,27 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
ic->ic_updateprot(ic);
/*
+ * Check if 40MHz channel mode has changed since last beacon.
+ */
+ if (htop && (ic->ic_bss->ni_flags & IEEE80211_NODE_HT) &&
+ (ic->ic_htcaps & IEEE80211_HTCAP_CBW20_40)) {
+ uint8_t chw_last, chw, sco_last, sco;
+ chw_last = (ic->ic_bss->ni_htop0 & IEEE80211_HTOP0_CHW);
+ chw = (ni->ni_htop0 & IEEE80211_HTOP0_CHW);
+ sco_last =
+ ((ic->ic_bss->ni_htop0 & IEEE80211_HTOP0_SCO_MASK)
+ >> IEEE80211_HTOP0_SCO_SHIFT);
+ sco = ((ni->ni_htop0 & IEEE80211_HTOP0_SCO_MASK) >>
+ IEEE80211_HTOP0_SCO_SHIFT);
+ ic->ic_bss->ni_htop0 = ni->ni_htop0;
+ if (chw_last != chw || sco_last != sco) {
+ if (ic->ic_updatechan != NULL)
+ ic->ic_updatechan(ic);
+ }
+ } else if (htop)
+ ic->ic_bss->ni_htop0 = ni->ni_htop0;
+
+ /*
* Check if AP short slot time setting has changed
* since last beacon and give the driver a chance to
* update the hardware.
blob - 4d4b11d89a33b81aeb13ae25f6e53d36ef1833fd
blob + f49dfdb8b44f91304b5e4a48d11c89acd06aa230
--- sys/net80211/ieee80211_node.h
+++ sys/net80211/ieee80211_node.h
@@ -61,7 +61,15 @@ extern const struct ieee80211_rateset ieee80211_std_ra
#define IEEE80211_HT_RATESET_MIMO3_SGI 5
#define IEEE80211_HT_RATESET_MIMO4 6
#define IEEE80211_HT_RATESET_MIMO4_SGI 7
-#define IEEE80211_HT_NUM_RATESETS 8
+#define IEEE80211_HT_RATESET_SISO_40 8
+#define IEEE80211_HT_RATESET_SISO_SGI40 9
+#define IEEE80211_HT_RATESET_MIMO2_40 10
+#define IEEE80211_HT_RATESET_MIMO2_SGI40 11
+#define IEEE80211_HT_RATESET_MIMO3_40 12
+#define IEEE80211_HT_RATESET_MIMO3_SGI40 13
+#define IEEE80211_HT_RATESET_MIMO4_40 14
+#define IEEE80211_HT_RATESET_MIMO4_SGI40 15
+#define IEEE80211_HT_NUM_RATESETS 16
/* Maximum number of rates in a HT rateset. */
#define IEEE80211_HT_RATESET_MAX_NRATES 8
@@ -84,6 +92,7 @@ struct ieee80211_ht_rateset {
int min_mcs;
int max_mcs;
+ int chan40;
int sgi;
};
@@ -482,6 +491,15 @@ ieee80211_node_supports_ht_sgi40(struct ieee80211_node
(ni->ni_htcaps & IEEE80211_HTCAP_SGI40);
}
+/* Check if the peer can receive frames sent on a 40 MHz channel. */
+static inline int
+ieee80211_node_supports_ht_chan40(struct ieee80211_node *ni)
+{
+ return (ieee80211_node_supports_ht(ni) &&
+ (ni->ni_htcaps & IEEE80211_HTCAP_CBW20_40) &&
+ (ni->ni_htop0 & IEEE80211_HTOP0_CHW));
+}
+
struct ieee80211com;
typedef void ieee80211_iter_func(void *, struct ieee80211_node *);
blob - 7e53f9eb8e18e0851433adb16912434050b9cdb3
blob + b1c2719c7c64dc401514bfab518da7903f7ddf3d
--- sys/net80211/ieee80211_proto.c
+++ sys/net80211/ieee80211_proto.c
@@ -607,7 +607,12 @@ ieee80211_ht_negotiate(struct ieee80211com *ic, struct
ni->ni_flags |= IEEE80211_NODE_HT;
- /* Flags IEEE8021_NODE_HT_SGI20/40 are set by drivers if supported. */
+ if (ieee80211_node_supports_ht_sgi20(ni) &&
+ (ic->ic_htcaps & IEEE80211_HTCAP_SGI20))
+ ni->ni_flags |= IEEE80211_NODE_HT_SGI20;
+ if (ieee80211_node_supports_ht_sgi40(ni) &&
+ (ic->ic_htcaps & IEEE80211_HTCAP_SGI40))
+ ni->ni_flags |= IEEE80211_NODE_HT_SGI40;
}
void
blob - 8fa9a4f54c72480efb0c6060ced4c303ca00115f
blob + 2cd94451fde0ac9e74b52c6ece67eb715eaef945
--- sys/net80211/ieee80211_ra.c
+++ sys/net80211/ieee80211_ra.c
@@ -112,33 +112,45 @@ ra_fp_sprintf(uint64_t fp)
#endif /* RA_DEBUG */
const struct ieee80211_ht_rateset *
-ieee80211_ra_get_ht_rateset(int mcs, int sgi20)
+ieee80211_ra_get_ht_rateset(int mcs, int chan40, int sgi)
{
const struct ieee80211_ht_rateset *rs;
int i;
for (i = 0; i < IEEE80211_HT_NUM_RATESETS; i++) {
rs = &ieee80211_std_ratesets_11n[i];
- if (sgi20 != rs->sgi)
- continue;
- if (mcs >= rs->min_mcs && mcs <= rs->max_mcs)
+ if (chan40 == rs->chan40 && sgi == rs->sgi &&
+ mcs >= rs->min_mcs && mcs <= rs->max_mcs)
return rs;
}
panic("MCS %d is not part of any rateset", mcs);
}
+int
+ieee80211_ra_use_ht_sgi(struct ieee80211_node *ni)
+{
+ if ((ni->ni_chan->ic_flags & IEEE80211_CHAN_40MHZ) &&
+ ieee80211_node_supports_ht_chan40(ni)) {
+ if (ni->ni_flags & IEEE80211_NODE_HT_SGI40)
+ return 1;
+ } else if (ni->ni_flags & IEEE80211_NODE_HT_SGI20)
+ return 1;
+
+ return 0;
+}
+
/*
* Update goodput statistics.
*/
uint64_t
-ieee80211_ra_get_txrate(int mcs, int sgi20)
+ieee80211_ra_get_txrate(int mcs, int chan40, int sgi)
{
const struct ieee80211_ht_rateset *rs;
uint64_t txrate;
- rs = ieee80211_ra_get_ht_rateset(mcs, sgi20);
+ rs = ieee80211_ra_get_ht_rateset(mcs, chan40, sgi);
txrate = rs->rates[mcs - rs->min_mcs];
txrate <<= RA_FP_SHIFT; /* convert to fixed-point */
txrate *= 500; /* convert to kbit/s */
@@ -160,9 +172,9 @@ ieee80211_ra_next_lower_intra_rate(struct ieee80211_ra
{
const struct ieee80211_ht_rateset *rs;
int i, next;
- int sgi20 = (ni->ni_flags & IEEE80211_NODE_HT_SGI20) ? 1 : 0;
- rs = ieee80211_ra_get_ht_rateset(ni->ni_txmcs, sgi20);
+ rs = ieee80211_ra_get_ht_rateset(ni->ni_txmcs,
+ ieee80211_node_supports_ht_chan40(ni), ieee80211_ra_use_ht_sgi(ni));
if (ni->ni_txmcs == rs->min_mcs)
return rs->min_mcs;
@@ -185,9 +197,9 @@ ieee80211_ra_next_intra_rate(struct ieee80211_ra_node
{
const struct ieee80211_ht_rateset *rs;
int i, next;
- int sgi20 = (ni->ni_flags & IEEE80211_NODE_HT_SGI20) ? 1 : 0;
- rs = ieee80211_ra_get_ht_rateset(ni->ni_txmcs, sgi20);
+ rs = ieee80211_ra_get_ht_rateset(ni->ni_txmcs,
+ ieee80211_node_supports_ht_chan40(ni), ieee80211_ra_use_ht_sgi(ni));
if (ni->ni_txmcs == rs->max_mcs)
return rs->max_mcs;
@@ -210,33 +222,58 @@ ieee80211_ra_next_rateset(struct ieee80211_ra_node *rn
{
const struct ieee80211_ht_rateset *rs, *rsnext;
int next;
+ int chan40 = ieee80211_node_supports_ht_chan40(ni);
+ int sgi = ieee80211_ra_use_ht_sgi(ni);
int mcs = ni->ni_txmcs;
- int sgi20 = (ni->ni_flags & IEEE80211_NODE_HT_SGI20) ? 1 : 0;
- rs = ieee80211_ra_get_ht_rateset(mcs, sgi20);
+ rs = ieee80211_ra_get_ht_rateset(mcs, chan40, sgi);
if (rn->probing & IEEE80211_RA_PROBING_UP) {
- if (rs->max_mcs == 7) /* MCS 0-7 */
- next = sgi20 ? IEEE80211_HT_RATESET_MIMO2_SGI :
- IEEE80211_HT_RATESET_MIMO2;
- else if (rs->max_mcs == 15) /* MCS 8-15 */
- next = sgi20 ? IEEE80211_HT_RATESET_MIMO3_SGI :
- IEEE80211_HT_RATESET_MIMO3;
- else if (rs->max_mcs == 23) /* MCS 16-23 */
- next = sgi20 ? IEEE80211_HT_RATESET_MIMO4_SGI :
- IEEE80211_HT_RATESET_MIMO4;
- else /* MCS 24-31 */
+ if (rs->max_mcs == 7) { /* MCS 0-7 */
+ if (chan40)
+ next = sgi ? IEEE80211_HT_RATESET_MIMO2_SGI40 :
+ IEEE80211_HT_RATESET_MIMO2_40;
+ else
+ next = sgi ? IEEE80211_HT_RATESET_MIMO2_SGI :
+ IEEE80211_HT_RATESET_MIMO2;
+ } else if (rs->max_mcs == 15) { /* MCS 8-15 */
+ if (chan40)
+ next = sgi ? IEEE80211_HT_RATESET_MIMO3_SGI40 :
+ IEEE80211_HT_RATESET_MIMO3_40;
+ else
+ next = sgi ? IEEE80211_HT_RATESET_MIMO3_SGI :
+ IEEE80211_HT_RATESET_MIMO3;
+ } else if (rs->max_mcs == 23) { /* MCS 16-23 */
+ if (chan40)
+ next = sgi ? IEEE80211_HT_RATESET_MIMO4_SGI40 :
+ IEEE80211_HT_RATESET_MIMO4_40;
+ else
+ next = sgi ? IEEE80211_HT_RATESET_MIMO4_SGI :
+ IEEE80211_HT_RATESET_MIMO4;
+ } else /* MCS 24-31 */
return NULL;
} else if (rn->probing & IEEE80211_RA_PROBING_DOWN) {
- if (rs->min_mcs == 24) /* MCS 24-31 */
- next = sgi20 ? IEEE80211_HT_RATESET_MIMO3_SGI :
- IEEE80211_HT_RATESET_MIMO3;
- else if (rs->min_mcs == 16) /* MCS 16-23 */
- next = sgi20 ? IEEE80211_HT_RATESET_MIMO2_SGI :
- IEEE80211_HT_RATESET_MIMO2;
- else if (rs->min_mcs == 8) /* MCS 8-15 */
- next = sgi20 ? IEEE80211_HT_RATESET_SISO_SGI :
- IEEE80211_HT_RATESET_SISO;
- else /* MCS 0-7 */
+ if (rs->min_mcs == 24) { /* MCS 24-31 */
+ if (chan40)
+ next = sgi ? IEEE80211_HT_RATESET_MIMO3_SGI40 :
+ IEEE80211_HT_RATESET_MIMO3_40;
+ else
+ next = sgi ? IEEE80211_HT_RATESET_MIMO3_SGI :
+ IEEE80211_HT_RATESET_MIMO3;
+ } else if (rs->min_mcs == 16) { /* MCS 16-23 */
+ if (chan40)
+ next = sgi ? IEEE80211_HT_RATESET_MIMO2_SGI40 :
+ IEEE80211_HT_RATESET_MIMO2_40;
+ else
+ next = sgi ? IEEE80211_HT_RATESET_MIMO2_SGI :
+ IEEE80211_HT_RATESET_MIMO2;
+ } else if (rs->min_mcs == 8) { /* MCS 8-15 */
+ if (chan40)
+ next = sgi ? IEEE80211_HT_RATESET_SISO_SGI40 :
+ IEEE80211_HT_RATESET_SISO_40;
+ else
+ next = sgi ? IEEE80211_HT_RATESET_SISO_SGI :
+ IEEE80211_HT_RATESET_SISO;
+ } else /* MCS 0-7 */
return NULL;
} else
panic("%s: invalid probing mode %d", __func__, rn->probing);
@@ -276,10 +313,10 @@ ieee80211_ra_probe_next_rateset(struct ieee80211_ra_no
const struct ieee80211_ht_rateset *rs;
struct ieee80211_ra_goodput_stats *g;
int best_mcs, i;
- int sgi20 = (ni->ni_flags & IEEE80211_NODE_HT_SGI20) ? 1 : 0;
/* Find most recently measured best MCS from the current rateset. */
- rs = ieee80211_ra_get_ht_rateset(ni->ni_txmcs, sgi20);
+ rs = ieee80211_ra_get_ht_rateset(ni->ni_txmcs,
+ ieee80211_node_supports_ht_chan40(ni), ieee80211_ra_use_ht_sgi(ni));
best_mcs = ieee80211_ra_best_mcs_in_rateset(rn, rs);
/* Switch to the next rateset. */
@@ -365,12 +402,13 @@ ieee80211_ra_intra_mode_ra_finished(struct ieee80211_r
struct ieee80211_ra_goodput_stats *g = &rn->g[ni->ni_txmcs];
int next_mcs, best_mcs;
uint64_t next_rate;
- int sgi20 = (ni->ni_flags & IEEE80211_NODE_HT_SGI20) ? 1 : 0;
+ int chan40 = ieee80211_node_supports_ht_chan40(ni);
+ int sgi = ieee80211_ra_use_ht_sgi(ni);
rn->probed_rates = (rn->probed_rates | (1 << ni->ni_txmcs));
/* Check if the min/max MCS in this rateset has been probed. */
- rs = ieee80211_ra_get_ht_rateset(ni->ni_txmcs, sgi20);
+ rs = ieee80211_ra_get_ht_rateset(ni->ni_txmcs, chan40, sgi);
if (rn->probing & IEEE80211_RA_PROBING_DOWN) {
if (ni->ni_txmcs == rs->min_mcs ||
rn->probed_rates & (1 << rs->min_mcs)) {
@@ -394,7 +432,7 @@ ieee80211_ra_intra_mode_ra_finished(struct ieee80211_r
ieee80211_ra_trigger_next_rateset(rn, ni);
return 1;
}
- next_rate = ieee80211_ra_get_txrate(next_mcs, sgi20);
+ next_rate = ieee80211_ra_get_txrate(next_mcs, chan40, sgi);
if (g->loss == 0 &&
g->measured >= next_rate + IEEE80211_RA_RATE_THRESHOLD) {
ieee80211_ra_trigger_next_rateset(rn, ni);
@@ -544,7 +582,7 @@ ieee80211_ra_add_stats_ht(struct ieee80211_ra_node *rn
{
static const uint64_t alpha = RA_FP_1 / 8; /* 1/8 = 0.125 */
static const uint64_t beta = RA_FP_1 / 4; /* 1/4 = 0.25 */
- int s, sgi20;
+ int s;
struct ieee80211_ra_goodput_stats *g;
uint64_t sfer, rate, delta;
@@ -581,8 +619,9 @@ ieee80211_ra_add_stats_ht(struct ieee80211_ra_node *rn
g->nprobe_fail = 0;
g->nprobe_pkts = 0;
- sgi20 = (ni->ni_flags & IEEE80211_NODE_HT_SGI20) ? 1 : 0;
- rate = ieee80211_ra_get_txrate(mcs, sgi20);
+ rate = ieee80211_ra_get_txrate(mcs,
+ ieee80211_node_supports_ht_chan40(ni),
+ ieee80211_ra_use_ht_sgi(ni));
g->loss = sfer * 100;
g->measured = RA_FP_MUL(RA_FP_1 - sfer, rate);
@@ -605,7 +644,8 @@ ieee80211_ra_choose(struct ieee80211_ra_node *rn, stru
{
struct ieee80211_ra_goodput_stats *g = &rn->g[ni->ni_txmcs];
int s;
- int sgi20 = (ni->ni_flags & IEEE80211_NODE_HT_SGI20) ? 1 : 0;
+ int chan40 = ieee80211_node_supports_ht_chan40(ni);
+ int sgi = ieee80211_ra_use_ht_sgi(ni);
const struct ieee80211_ht_rateset *rs, *rsnext;
s = splnet();
@@ -635,7 +675,7 @@ ieee80211_ra_choose(struct ieee80211_ra_node *rn, stru
rn->valid_probes = 0;
}
- rs = ieee80211_ra_get_ht_rateset(ni->ni_txmcs, sgi20);
+ rs = ieee80211_ra_get_ht_rateset(ni->ni_txmcs, chan40, sgi);
if ((g->measured >> RA_FP_SHIFT) == 0LL ||
(g->average >= 3 * g->stddeviation &&
g->measured < g->average - 3 * g->stddeviation)) {
blob - 8c40b3045983639d4e386618bcead2e0f20c000b
blob + ab0990d21fe59c921324697e29c3bc3d1876bc24
--- sys/net80211/ieee80211_ra.h
+++ sys/net80211/ieee80211_ra.h
@@ -74,6 +74,9 @@ void ieee80211_ra_add_stats_ht(struct ieee80211_ra_nod
void ieee80211_ra_choose(struct ieee80211_ra_node *,
struct ieee80211com *, struct ieee80211_node *);
-/* Get the HT rateset for a particular HT MCS with SGI20 on/off. */
+/* Get the HT rateset for a particular HT MCS with 40MHz and/or SGI on/off. */
const struct ieee80211_ht_rateset * ieee80211_ra_get_ht_rateset(int mcs,
- int sgi20);
+ int chan40, int sgi);
+
+/* Check whether SGI should be used. */
+int ieee80211_ra_use_ht_sgi(struct ieee80211_node *);
blob - c4c25512cefdd4b8c19f612d9513e9ccf6a0e674
blob + fe8e8dfb20f59a5e48bc94f37731e49b0bd37301
--- sys/net80211/ieee80211_var.h
+++ sys/net80211/ieee80211_var.h
@@ -134,6 +134,7 @@ struct ieee80211_channel {
#define IEEE80211_CHAN_XR 0x1000 /* Extended range OFDM channel */
#define IEEE80211_CHAN_HT 0x2000 /* 11n/HT channel */
#define IEEE80211_CHAN_VHT 0x4000 /* 11ac/VHT channel */
+#define IEEE80211_CHAN_40MHZ 0x8000 /* use of 40 MHz is allowed */
/*
* Useful combinations of channel characteristics.
@@ -245,6 +246,7 @@ struct ieee80211com {
void (*ic_ampdu_rx_stop)(struct ieee80211com *,
struct ieee80211_node *, u_int8_t);
void (*ic_updateprot)(struct ieee80211com *);
+ void (*ic_updatechan)(struct ieee80211com *);
int (*ic_bgscan_start)(struct ieee80211com *);
struct timeout ic_bgscan_timeout;
uint32_t ic_bgscan_fail;