diff options
-rw-r--r-- | sys/dev/pci/if_iwn.c | 160 | ||||
-rw-r--r-- | sys/dev/pci/if_iwnreg.h | 6 | ||||
-rw-r--r-- | sys/dev/pci/if_iwnvar.h | 4 |
3 files changed, 134 insertions, 36 deletions
diff --git a/sys/dev/pci/if_iwn.c b/sys/dev/pci/if_iwn.c index 0ca26cfb9cd..2639a6c1335 100644 --- a/sys/dev/pci/if_iwn.c +++ b/sys/dev/pci/if_iwn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwn.c,v 1.252 2021/11/12 11:40:35 stsp Exp $ */ +/* $OpenBSD: if_iwn.c,v 1.253 2021/11/12 11:41:04 stsp Exp $ */ /*- * Copyright (c) 2007-2010 Damien Bergamini <damien.bergamini@free.fr> @@ -241,12 +241,16 @@ uint16_t iwn_get_passive_dwell_time(struct iwn_softc *, uint16_t); int iwn_scan(struct iwn_softc *, uint16_t, int); void iwn_scan_abort(struct iwn_softc *); int iwn_bgscan(struct ieee80211com *); +void iwn_rxon_configure_ht40(struct ieee80211com *, + struct ieee80211_node *); +int iwn_rxon_ht40_enabled(struct iwn_softc *); int iwn_auth(struct iwn_softc *, int); int iwn_run(struct iwn_softc *); int iwn_set_key(struct ieee80211com *, struct ieee80211_node *, struct ieee80211_key *); void iwn_delete_key(struct ieee80211com *, struct ieee80211_node *, struct ieee80211_key *); +void iwn_updatechan(struct ieee80211com *); void iwn_updateprot(struct ieee80211com *); void iwn_updateslot(struct ieee80211com *); void iwn_update_rxon_restore_power(struct iwn_softc *); @@ -491,13 +495,15 @@ iwn_attach(struct device *parent, struct device *self, void *aux) ic->ic_caps |= (IEEE80211_C_QOS | IEEE80211_C_TX_AMPDU); /* Set HT capabilities. */ ic->ic_htcaps = IEEE80211_HTCAP_SGI20; + /* 6200 devices have issues with SGI40 for some reason. */ + if ((sc->sc_flags & IWN_FLAG_INTERNAL_PA) == 0) + ic->ic_htcaps |= IEEE80211_HTCAP_SGI40; + ic->ic_htcaps |= IEEE80211_HTCAP_CBW20_40; #ifdef notyet ic->ic_htcaps |= #if IWN_RBUF_SIZE == 8192 IEEE80211_HTCAP_AMSDU7935 | #endif - IEEE80211_HTCAP_CBW20_40 | - IEEE80211_HTCAP_SGI40; if (sc->hw_type != IWN_HW_REV_TYPE_4965) ic->ic_htcaps |= IEEE80211_HTCAP_GF; if (sc->hw_type == IWN_HW_REV_TYPE_6050) @@ -543,6 +549,7 @@ iwn_attach(struct device *parent, struct device *self, void *aux) ic->ic_updateedca = iwn_updateedca; ic->ic_set_key = iwn_set_key; ic->ic_delete_key = iwn_delete_key; + ic->ic_updatechan = iwn_updatechan; ic->ic_updateprot = iwn_updateprot; ic->ic_updateslot = iwn_updateslot; ic->ic_ampdu_rx_start = iwn_ampdu_rx_start; @@ -1477,8 +1484,8 @@ iwn4965_read_eeprom(struct iwn_softc *sc) /* Read regulatory domain (4 ASCII characters). */ iwn_read_prom_data(sc, IWN4965_EEPROM_DOMAIN, sc->eeprom_domain, 4); - /* Read the list of authorized channels (20MHz ones only). */ - for (i = 0; i < 5; i++) { + /* Read the list of authorized channels. */ + for (i = 0; i < 7; i++) { addr = iwn4965_regulatory_bands[i]; iwn_read_eeprom_channels(sc, i, addr); } @@ -1562,8 +1569,8 @@ iwn5000_read_eeprom(struct iwn_softc *sc) iwn_read_prom_data(sc, base + IWN5000_EEPROM_DOMAIN, sc->eeprom_domain, 4); - /* Read the list of authorized channels (20MHz ones only). */ - for (i = 0; i < 5; i++) { + /* Read the list of authorized channels. */ + for (i = 0; i < 7; i++) { addr = base + iwn5000_regulatory_bands[i]; iwn_read_eeprom_channels(sc, i, addr); } @@ -1633,7 +1640,7 @@ iwn_read_eeprom_channels(struct iwn_softc *sc, int n, uint32_t addr) IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; - } else { /* 5GHz band */ + } else if (n < 5) { /* 5GHz band */ /* * Some adapters support channels 7, 8, 11 and 12 * both in the 2GHz and 4.9GHz bands. @@ -1648,22 +1655,29 @@ iwn_read_eeprom_channels(struct iwn_softc *sc, int n, uint32_t addr) ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_A; /* We have at least one valid 5GHz channel. */ sc->sc_flags |= IWN_FLAG_HAS_5GHZ; + } else { /* 40 MHz */ + sc->maxpwr40[chan] = channels[i].maxpwr; + ic->ic_channels[chan].ic_flags |= IEEE80211_CHAN_40MHZ; } - /* Is active scan allowed on this channel? */ - if (!(channels[i].flags & IWN_EEPROM_CHAN_ACTIVE)) { - ic->ic_channels[chan].ic_flags |= - IEEE80211_CHAN_PASSIVE; - } + if (n < 5) { + /* Is active scan allowed on this channel? */ + if (!(channels[i].flags & IWN_EEPROM_CHAN_ACTIVE)) { + ic->ic_channels[chan].ic_flags |= + IEEE80211_CHAN_PASSIVE; + } - /* Save maximum allowed TX power for this channel. */ - sc->maxpwr[chan] = channels[i].maxpwr; + /* Save maximum allowed TX power for this channel. */ + sc->maxpwr[chan] = channels[i].maxpwr; - if (sc->sc_flags & IWN_FLAG_HAS_11N) - ic->ic_channels[chan].ic_flags |= IEEE80211_CHAN_HT; + if (sc->sc_flags & IWN_FLAG_HAS_11N) + ic->ic_channels[chan].ic_flags |= + IEEE80211_CHAN_HT; + } - DPRINTF(("adding chan %d flags=0x%x maxpwr=%d\n", - chan, channels[i].flags, sc->maxpwr[chan])); + DPRINTF(("adding chan %d flags=0x%x maxpwr=%d maxpwr40=%d\n", + chan, channels[i].flags, sc->maxpwr[chan], + sc->maxpwr40[chan])); } } @@ -2287,8 +2301,9 @@ iwn_ht_single_rate_control(struct iwn_softc *sc, struct ieee80211_node *ni, struct iwn_node *wn = (void *)ni; int mcs = rate; const struct ieee80211_ht_rateset *rs = - ieee80211_ra_get_ht_rateset(rate, 0 /* chan40 */, - ieee80211_ra_use_ht_sgi(ni)); + ieee80211_ra_get_ht_rateset(rate, + ieee80211_node_supports_ht_chan40(ni), + ieee80211_ra_use_ht_sgi(ni)); unsigned int retries = 0, i; /* @@ -2488,6 +2503,8 @@ iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc, DPRINTFN(3, ("received statistics (cmd=%d)\n", desc->type)); sc->calib_cnt = 0; /* Reset TX power calibration timeout. */ + sc->rx_stats_flags = htole32(stats->flags); + /* Test if temperature has changed. */ if (stats->general.temp != sc->rawtemp) { /* Convert "raw" temperature to degC. */ @@ -3537,7 +3554,9 @@ iwn_tx(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) if ((ni->ni_flags & IEEE80211_NODE_HT) && tx->id != sc->broadcast_id) { tx->rflags = rinfo->ht_flags; - if (ni->ni_htcaps & IEEE80211_HTCAP_SGI20) + if (iwn_rxon_ht40_enabled(sc)) + tx->rflags |= IWN_RFLAG_HT40; + if (ieee80211_ra_use_ht_sgi(ni)) tx->rflags |= IWN_RFLAG_SGI; } else @@ -3925,12 +3944,17 @@ iwn_set_link_quality(struct iwn_softc *sc, struct ieee80211_node *ni) linkq.retry[i].plcp = rinfo->ht_plcp; linkq.retry[i].rflags = rinfo->ht_flags; - if (ni->ni_htcaps & IEEE80211_HTCAP_SGI20) - linkq.retry[i].rflags |= IWN_RFLAG_SGI; - /* XXX set correct ant mask for MIMO rates here */ linkq.retry[i].rflags |= IWN_RFLAG_ANT(txant); + /* First two Tx attempts may use 40MHz/SGI. */ + if (i < 2) { + if (iwn_rxon_ht40_enabled(sc)) + linkq.retry[i].rflags |= IWN_RFLAG_HT40; + if (ieee80211_ra_use_ht_sgi(ni)) + linkq.retry[i].rflags |= IWN_RFLAG_SGI; + } + if (++i >= IWN_MAX_TX_RETRIES) break; } @@ -4121,8 +4145,8 @@ iwn4965_set_txpower(struct iwn_softc *sc, int async) struct iwn4965_eeprom_chan_samples *chans; const uint8_t *rf_gain, *dsp_gain; int32_t vdiff, tdiff; - int i, c, grp, maxpwr; - uint8_t chan; + int i, c, grp, maxpwr, is_ht40 = 0; + uint8_t chan, ext_chan; /* Retrieve current channel from last RXON. */ chan = sc->rxon.chan; @@ -4175,17 +4199,26 @@ iwn4965_set_txpower(struct iwn_softc *sc, int async) chans = sc->bands[i].chans; DPRINTF(("chan %d sub-band=%d\n", chan, i)); + if (iwn_rxon_ht40_enabled(sc)) { + is_ht40 = 1; + if (le32toh(sc->rxon.flags) & IWN_RXON_HT_HT40MINUS) + ext_chan = chan - 2; + else + ext_chan = chan + 2; + } else + ext_chan = chan; + for (c = 0; c < 2; c++) { uint8_t power, gain, temp; int maxchpwr, pwr, ridx, idx; - power = interpolate(chan, + power = interpolate(ext_chan, chans[0].num, chans[0].samples[c][1].power, chans[1].num, chans[1].samples[c][1].power, 1); - gain = interpolate(chan, + gain = interpolate(ext_chan, chans[0].num, chans[0].samples[c][1].gain, chans[1].num, chans[1].samples[c][1].gain, 1); - temp = interpolate(chan, + temp = interpolate(ext_chan, chans[0].num, chans[0].samples[c][1].temp, chans[1].num, chans[1].samples[c][1].temp, 1); DPRINTF(("TX chain %d: power=%d gain=%d temp=%d\n", @@ -4198,7 +4231,10 @@ iwn4965_set_txpower(struct iwn_softc *sc, int async) for (ridx = 0; ridx <= IWN_RIDX_MAX; ridx++) { /* Convert dBm to half-dBm. */ - maxchpwr = sc->maxpwr[chan] * 2; + if (is_ht40) + maxchpwr = sc->maxpwr40[chan] * 2; + else + maxchpwr = sc->maxpwr[chan] * 2; #ifdef notyet if (ridx > iwn_mcs2ridx[7] && ridx < iwn_mcs2ridx[16]) maxchpwr -= 6; /* MIMO 2T: -3dB */ @@ -4334,9 +4370,15 @@ iwn4965_get_temperature(struct iwn_softc *sc) struct iwn_ucode_info *uc = &sc->ucode_info; int32_t r1, r2, r3, r4, temp; - r1 = letoh32(uc->temp[0].chan20MHz); - r2 = letoh32(uc->temp[1].chan20MHz); - r3 = letoh32(uc->temp[2].chan20MHz); + if (sc->rx_stats_flags & IWN_STATS_FLAGS_BAND_HT40) { + r1 = letoh32(uc->temp[0].chan40MHz); + r2 = letoh32(uc->temp[1].chan40MHz); + r3 = letoh32(uc->temp[2].chan40MHz); + } else { + r1 = letoh32(uc->temp[0].chan20MHz); + r2 = letoh32(uc->temp[1].chan20MHz); + r3 = letoh32(uc->temp[2].chan20MHz); + } r4 = letoh32(sc->rawtemp); if (r1 == r3) /* Prevents division by 0 (should not happen). */ @@ -5375,6 +5417,37 @@ iwn_bgscan(struct ieee80211com *ic) return error; } +void +iwn_rxon_configure_ht40(struct ieee80211com *ic, struct ieee80211_node *ni) +{ + struct iwn_softc *sc = ic->ic_softc; + uint8_t sco = (ni->ni_htop0 & IEEE80211_HTOP0_SCO_MASK); + enum ieee80211_htprot htprot = (ni->ni_htop1 & + IEEE80211_HTOP1_PROT_MASK); + + sc->rxon.flags &= ~htole32(IWN_RXON_HT_CHANMODE_MIXED2040 | + IWN_RXON_HT_CHANMODE_PURE40 | IWN_RXON_HT_HT40MINUS); + + if (ieee80211_node_supports_ht_chan40(ni) && + (sco == IEEE80211_HTOP0_SCO_SCA || + sco == IEEE80211_HTOP0_SCO_SCB)) { + if (sco == IEEE80211_HTOP0_SCO_SCB) + sc->rxon.flags |= htole32(IWN_RXON_HT_HT40MINUS); + if (htprot == IEEE80211_HTPROT_20MHZ) + sc->rxon.flags |= htole32(IWN_RXON_HT_CHANMODE_PURE40); + else + sc->rxon.flags |= htole32( + IWN_RXON_HT_CHANMODE_MIXED2040); + } +} + +int +iwn_rxon_ht40_enabled(struct iwn_softc *sc) +{ + return ((le32toh(sc->rxon.flags) & IWN_RXON_HT_CHANMODE_MIXED2040) || + (le32toh(sc->rxon.flags) & IWN_RXON_HT_CHANMODE_PURE40)) ? 1 : 0; +} + int iwn_auth(struct iwn_softc *sc, int arg) { @@ -5418,6 +5491,8 @@ iwn_auth(struct iwn_softc *sc, int arg) sc->rxon.cck_mask = 0x0f; sc->rxon.ofdm_mask = 0x15; } + /* Configure 40MHz early to avoid problems on 6205 devices. */ + iwn_rxon_configure_ht40(ic, ni); DPRINTF(("%s: rxon chan %d flags %x cck %x ofdm %x\n", __func__, sc->rxon.chan, le32toh(sc->rxon.flags), sc->rxon.cck_mask, sc->rxon.ofdm_mask)); @@ -5503,6 +5578,8 @@ iwn_run(struct iwn_softc *sc) } else sc->rxon.flags &= ~htole32(IWN_RXON_HT_PROTMODE(3)); + iwn_rxon_configure_ht40(ic, ni); + if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) { /* 11a or 11n 5GHz */ sc->rxon.cck_mask = 0; @@ -5554,6 +5631,8 @@ iwn_run(struct iwn_softc *sc) (ic->ic_ampdu_params & IEEE80211_AMPDU_PARAM_LE)) | IWN_AMDPU_DENSITY( (ic->ic_ampdu_params & IEEE80211_AMPDU_PARAM_SS) >> 2)); + if (iwn_rxon_ht40_enabled(sc)) + node.htflags |= htole32(IWN_40MHZ_ENABLE); } DPRINTF(("adding BSS node\n")); error = ops->add_node(sc, &node, 1); @@ -5652,6 +5731,19 @@ iwn_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni, } void +iwn_updatechan(struct ieee80211com *ic) +{ + struct iwn_softc *sc = ic->ic_softc; + + if (ic->ic_state != IEEE80211_S_RUN) + return; + + iwn_rxon_configure_ht40(ic, ic->ic_bss); + sc->ops.update_rxon(sc); + iwn_set_link_quality(sc, ic->ic_bss); +} + +void iwn_updateprot(struct ieee80211com *ic) { struct iwn_softc *sc = ic->ic_softc; diff --git a/sys/dev/pci/if_iwnreg.h b/sys/dev/pci/if_iwnreg.h index a6ed77338a0..110efd376fd 100644 --- a/sys/dev/pci/if_iwnreg.h +++ b/sys/dev/pci/if_iwnreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwnreg.h,v 1.58 2021/11/12 11:40:36 stsp Exp $ */ +/* $OpenBSD: if_iwnreg.h,v 1.59 2021/11/12 11:41:04 stsp Exp $ */ /*- * Copyright (c) 2007, 2008 @@ -637,6 +637,8 @@ struct iwn_node_info { uint32_t htflags; #define IWN_AMDPU_SIZE_FACTOR(x) ((x) << 19) #define IWN_AMDPU_SIZE_FACTOR_MASK ((0x3) << 19) +#define IWN_40MHZ_ENABLE (1 << 21) +#define IWN_MIMO_DISABLE (1 << 22) #define IWN_AMDPU_DENSITY(x) ((x) << 23) #define IWN_AMDPU_DENSITY_MASK ((0x7) << 23) @@ -1537,6 +1539,8 @@ struct iwn_general_stats { struct iwn_stats { uint32_t flags; +#define IWN_STATS_FLAGS_BAND_24G 0x02 +#define IWN_STATS_FLAGS_BAND_HT40 0x08 struct iwn_rx_stats rx; struct iwn_tx_stats tx; struct iwn_general_stats general; diff --git a/sys/dev/pci/if_iwnvar.h b/sys/dev/pci/if_iwnvar.h index dc0534d3237..f02248896ca 100644 --- a/sys/dev/pci/if_iwnvar.h +++ b/sys/dev/pci/if_iwnvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwnvar.h,v 1.41 2021/11/11 13:36:58 stsp Exp $ */ +/* $OpenBSD: if_iwnvar.h,v 1.42 2021/11/12 11:41:04 stsp Exp $ */ /*- * Copyright (c) 2007, 2008 @@ -280,6 +280,7 @@ struct iwn_softc { #define IWN_LAST_RX_AMPDU 0x02 struct iwn_ucode_info ucode_info; struct iwn_rxon rxon; + uint32_t rx_stats_flags; uint32_t rawtemp; int temp; int noise; @@ -298,6 +299,7 @@ struct iwn_softc { int8_t maxpwr2GHz; int8_t maxpwr5GHz; int8_t maxpwr[IEEE80211_CHAN_MAX]; + int8_t maxpwr40[IEEE80211_CHAN_MAX]; int8_t enh_maxpwr[35]; uint8_t reset_noise_gain; |