summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/pci/if_iwm.c222
-rw-r--r--sys/dev/pci/if_iwmreg.h5
-rw-r--r--sys/dev/pci/if_iwmvar.h6
3 files changed, 181 insertions, 52 deletions
diff --git a/sys/dev/pci/if_iwm.c b/sys/dev/pci/if_iwm.c
index 77d9c141cb9..ababbb0a4e9 100644
--- a/sys/dev/pci/if_iwm.c
+++ b/sys/dev/pci/if_iwm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwm.c,v 1.375 2021/10/11 09:01:05 stsp Exp $ */
+/* $OpenBSD: if_iwm.c,v 1.376 2021/10/11 09:03:22 stsp Exp $ */
/*
* Copyright (c) 2014, 2016 genua gmbh <info@genua.de>
@@ -335,9 +335,11 @@ void iwm_init_channel_map(struct iwm_softc *, const uint16_t * const,
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_packet *,
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 uint16_t * const nvm_ch_flags,
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)
@@ -5884,7 +5934,7 @@ iwm_phy_ctxt_cmd_hdr(struct iwm_softc *sc, struct iwm_phy_ctxt *ctxt,
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;
@@ -5892,8 +5942,23 @@ iwm_phy_ctxt_cmd_data(struct iwm_softc *sc, struct iwm_phy_context_cmd *cmd,
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;
@@ -5911,7 +5976,7 @@ iwm_phy_ctxt_cmd_data(struct iwm_softc *sc, struct iwm_phy_context_cmd *cmd,
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;
@@ -5927,8 +5992,23 @@ iwm_phy_ctxt_cmd_uhb(struct iwm_softc *sc, struct iwm_phy_ctxt *ctxt,
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;
@@ -5945,7 +6025,7 @@ iwm_phy_ctxt_cmd_uhb(struct iwm_softc *sc, struct iwm_phy_ctxt *ctxt,
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;
@@ -5958,12 +6038,12 @@ iwm_phy_ctxt_cmd(struct iwm_softc *sc, struct iwm_phy_ctxt *ctxt,
*/
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);
@@ -6354,8 +6434,19 @@ iwm_tx_fill_cmd(struct iwm_softc *sc, struct iwm_node *in,
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
@@ -6945,6 +7036,11 @@ iwm_add_sta_cmd(struct iwm_softc *sc, struct iwm_node *in, int update)
}
}
+ 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) {
@@ -7935,8 +8031,9 @@ iwm_mac_ctxt_cmd_common(struct iwm_softc *sc, struct iwm_node *in,
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);
@@ -8239,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;
@@ -8249,7 +8346,7 @@ iwm_phy_ctxt_update(struct iwm_softc *sc, struct iwm_phy_ctxt *phyctxt,
(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);
@@ -8257,7 +8354,7 @@ iwm_phy_ctxt_update(struct iwm_softc *sc, struct iwm_phy_ctxt *phyctxt,
}
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);
@@ -8266,7 +8363,7 @@ iwm_phy_ctxt_update(struct iwm_softc *sc, struct iwm_phy_ctxt *phyctxt,
} 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);
@@ -8274,6 +8371,7 @@ iwm_phy_ctxt_update(struct iwm_softc *sc, struct iwm_phy_ctxt *phyctxt,
}
}
+ phyctxt->sco = sco;
return 0;
}
@@ -8289,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) {
@@ -8407,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;
@@ -8419,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);
@@ -8430,12 +8530,26 @@ 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;
@@ -8594,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;
@@ -8761,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), },
@@ -8775,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.
@@ -8811,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--) {
@@ -9018,6 +9135,7 @@ iwm_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
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;
@@ -9653,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);
@@ -9912,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");
@@ -11322,7 +11441,8 @@ iwm_attach(struct device *parent, struct device *self, void *aux)
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;
@@ -11336,6 +11456,7 @@ iwm_attach(struct device *parent, struct device *self, void *aux)
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;
@@ -11377,6 +11498,7 @@ iwm_attach(struct device *parent, struct device *self, void *aux)
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;
diff --git a/sys/dev/pci/if_iwmreg.h b/sys/dev/pci/if_iwmreg.h
index ce7898fd501..59ae267a763 100644
--- a/sys/dev/pci/if_iwmreg.h
+++ b/sys/dev/pci/if_iwmreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwmreg.h,v 1.64 2021/07/09 11:24:55 stsp Exp $ */
+/* $OpenBSD: if_iwmreg.h,v 1.65 2021/10/11 09:03:22 stsp Exp $ */
/******************************************************************************
*
@@ -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
diff --git a/sys/dev/pci/if_iwmvar.h b/sys/dev/pci/if_iwmvar.h
index 1d94b1a708b..fe8490a324c 100644
--- a/sys/dev/pci/if_iwmvar.h
+++ b/sys/dev/pci/if_iwmvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwmvar.h,v 1.70 2021/10/07 08:15:04 stsp Exp $ */
+/* $OpenBSD: if_iwmvar.h,v 1.71 2021/10/11 09:03:22 stsp Exp $ */
/*
* Copyright (c) 2014 genua mbh <info@genua.de>
@@ -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;