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
intiwm_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 *);
intiwm_binding_cmd(struct iwm_softc *, struct iwm_node *, uint32_t);
intiwm_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);
intiwm_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);
intiwm_send_cmd(struct iwm_softc *, struct iwm_host_cmd *);
intiwm_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 *);
intiwm_lmac_scan_abort(struct iwm_softc *);
intiwm_scan_abort(struct iwm_softc *);
intiwm_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);
intiwm_auth(struct iwm_softc *);
intiwm_deauth(struct iwm_softc *);
intiwm_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, >mac_ctxt_task);
}
+void
+iwm_phy_ctxt_task(void *arg)
+{
+ struct iwm_softc *sc = arg;
+ struct ieee80211com *ic = >sc_ic;
+ struct iwm_node *in = (void *)ic->ic_bss;
+ struct ieee80211_node *ni = >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(>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
+