diff options
Diffstat (limited to 'sys/dev/pci')
-rw-r--r-- | sys/dev/pci/if_iwn.c | 322 | ||||
-rw-r--r-- | sys/dev/pci/if_iwnreg.h | 61 | ||||
-rw-r--r-- | sys/dev/pci/if_iwnvar.h | 4 |
3 files changed, 305 insertions, 82 deletions
diff --git a/sys/dev/pci/if_iwn.c b/sys/dev/pci/if_iwn.c index 1d295c5104a..91b7195a87f 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.148 2015/11/25 03:09:59 dlg Exp $ */ +/* $OpenBSD: if_iwn.c,v 1.149 2016/01/04 13:54:19 stsp Exp $ */ /*- * Copyright (c) 2007-2010 Damien Bergamini <damien.bergamini@free.fr> @@ -148,7 +148,7 @@ int iwn_newstate(struct ieee80211com *, enum ieee80211_state, int); void iwn_iter_func(void *, struct ieee80211_node *); void iwn_calib_timeout(void *); int iwn_ccmp_decap(struct iwn_softc *, struct mbuf *, - struct ieee80211_key *); + struct ieee80211_node *); void iwn_rx_phy(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); void iwn_rx_done(struct iwn_softc *, struct iwn_rx_desc *, @@ -189,7 +189,7 @@ int iwn5000_add_node(struct iwn_softc *, struct iwn_node_info *, int); int iwn_set_link_quality(struct iwn_softc *, struct ieee80211_node *); -int iwn_add_broadcast_node(struct iwn_softc *, int); +int iwn_add_broadcast_node(struct iwn_softc *, int, int); void iwn_updateedca(struct ieee80211com *); void iwn_set_led(struct iwn_softc *, uint8_t, uint8_t, uint8_t); int iwn_set_critical_temp(struct iwn_softc *); @@ -280,7 +280,7 @@ void iwn_stop(struct ifnet *, int); #ifdef IWN_DEBUG #define DPRINTF(x) do { if (iwn_debug > 0) printf x; } while (0) #define DPRINTFN(n, x) do { if (iwn_debug >= (n)) printf x; } while (0) -int iwn_debug = 0; +int iwn_debug = 1; #else #define DPRINTF(x) #define DPRINTFN(n, x) @@ -458,6 +458,15 @@ iwn_attach(struct device *parent, struct device *self, void *aux) IEEE80211_C_PMGT; /* power saving supported */ #ifndef IEEE80211_NO_HT + /* No optional HT features supported for now, */ + ic->ic_htcaps = 0; + ic->ic_htxcaps = 0; + ic->ic_txbfcaps = 0; + ic->ic_aselcaps = 0; +#endif + +#ifdef notyet +#ifndef IEEE80211_NO_HT if (sc->sc_flags & IWN_FLAG_HAS_11N) { /* Set HT capabilities. */ ic->ic_htcaps = @@ -475,6 +484,7 @@ iwn_attach(struct device *parent, struct device *self, void *aux) ic->ic_htcaps |= IEEE80211_HTCAP_SMPS_DIS; } #endif /* !IEEE80211_NO_HT */ +#endif /* notyet */ /* Set supported legacy rates. */ ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b; @@ -487,10 +497,12 @@ iwn_attach(struct device *parent, struct device *self, void *aux) if (sc->sc_flags & IWN_FLAG_HAS_11N) { /* Set supported HT rates. */ ic->ic_sup_mcs[0] = 0xff; /* MCS 0-7 */ +#ifdef notyet if (sc->nrxchains > 1) - ic->ic_sup_mcs[1] = 0xff; /* MCS 7-15 */ + ic->ic_sup_mcs[1] = 0xff; /* MCS 8-15 */ if (sc->nrxchains > 2) ic->ic_sup_mcs[2] = 0xff; /* MCS 16-23 */ +#endif } #endif @@ -515,9 +527,11 @@ iwn_attach(struct device *parent, struct device *self, void *aux) #ifndef IEEE80211_NO_HT ic->ic_ampdu_rx_start = iwn_ampdu_rx_start; ic->ic_ampdu_rx_stop = iwn_ampdu_rx_stop; +#ifdef notyet ic->ic_ampdu_tx_start = iwn_ampdu_tx_start; ic->ic_ampdu_tx_stop = iwn_ampdu_tx_stop; #endif +#endif /* Override 802.11 state transition machine. */ sc->sc_newstate = ic->ic_newstate; @@ -1635,6 +1649,11 @@ iwn_read_eeprom_channels(struct iwn_softc *sc, int n, uint32_t addr) /* Save maximum allowed TX power for this channel. */ sc->maxpwr[chan] = channels[i].maxpwr; +#ifndef IEEE80211_NO_HT + if (sc->sc_flags & IWN_FLAG_HAS_11N) + ic->ic_channels[chan].ic_flags |= IEEE80211_CHAN_HT; +#endif + DPRINTF(("adding chan %d flags=0x%x maxpwr=%d\n", chan, channels[i].flags, sc->maxpwr[chan])); } @@ -1693,13 +1712,18 @@ iwn_newassoc(struct ieee80211com *ic, struct ieee80211_node *ni, int isnew) ieee80211_amrr_node_init(&sc->amrr, &wn->amn); /* Start at lowest available bit-rate, AMRR will raise. */ ni->ni_txrate = 0; +#ifndef IEEE80211_NO_HT + ni->ni_txmcs = 0; +#endif for (i = 0; i < ni->ni_rates.rs_nrates; i++) { rate = ni->ni_rates.rs_rates[i] & IEEE80211_RATE_VAL; /* Map 802.11 rate to HW rate index. */ - for (ridx = 0; ridx <= IWN_RIDX_MAX; ridx++) - if (iwn_rates[ridx].rate == rate) + for (ridx = 0; ridx <= IWN_RIDX_MAX; ridx++) { + if (iwn_rates[ridx].plcp != IWN_PLCP_INVALID && + iwn_rates[ridx].rate == rate) break; + } wn->ridx[i] = ridx; } } @@ -1716,12 +1740,17 @@ iwn_media_change(struct ifnet *ifp) if (error != ENETRESET) return error; +#ifndef IEEE80211_NO_HT + if (ic->ic_fixed_mcs != -1) + sc->fixed_ridx = iwn_mcs2ridx[ic->ic_fixed_mcs]; +#endif if (ic->ic_fixed_rate != -1) { rate = ic->ic_sup_rates[ic->ic_curmode]. rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL; /* Map 802.11 rate to HW rate index. */ for (ridx = 0; ridx <= IWN_RIDX_MAX; ridx++) - if (iwn_rates[ridx].rate == rate) + if (iwn_rates[ridx].plcp != IWN_PLCP_INVALID && + iwn_rates[ridx].rate == rate) break; sc->fixed_ridx = ridx; } @@ -1816,7 +1845,7 @@ iwn_calib_timeout(void *arg) if (++sc->calib_cnt >= 120) { uint32_t flags = 0; - DPRINTF(("sending request for statistics\n")); + DPRINTFN(2, ("sending request for statistics\n")); (void)iwn_cmd(sc, IWN_CMD_GET_STATISTICS, &flags, sizeof flags, 1); sc->calib_cnt = 0; @@ -1828,13 +1857,15 @@ iwn_calib_timeout(void *arg) } int -iwn_ccmp_decap(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_key *k) +iwn_ccmp_decap(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) { + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_key *k = &ni->ni_pairwise_key; struct ieee80211_frame *wh; uint64_t pn, *prsc; uint8_t *ivp; uint8_t tid; - int hdrlen; + int hdrlen, hasqos; wh = mtod(m, struct ieee80211_frame *); hdrlen = ieee80211_get_hdrlen(wh); @@ -1845,8 +1876,8 @@ iwn_ccmp_decap(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_key *k) DPRINTF(("CCMP decap ExtIV not set\n")); return 1; } - tid = ieee80211_has_qos(wh) ? - ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0; + hasqos = ieee80211_has_qos(wh); + tid = hasqos ? ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0; prsc = &k->k_rsc[tid]; /* Extract the 48-bit PN from the CCMP header. */ @@ -1857,12 +1888,38 @@ iwn_ccmp_decap(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_key *k) (uint64_t)ivp[6] << 32 | (uint64_t)ivp[7] << 40; if (pn <= *prsc) { - /* - * Not necessarily a replayed frame since we did not check - * the sequence number of the 802.11 header yet. - */ - DPRINTF(("CCMP replayed\n")); - return 1; + if (hasqos && (sc->last_rx_valid & IWN_LAST_RX_AMPDU)) { + /* + * This is an A-MPDU subframe. + * Such frames may be received out of order due to + * legitimate retransmissions of failed subframes + * in previous A-MPDUs. Duplicates will be handled + * in ieee80211_input() as part of A-MPDU reordering. + */ + } else if (ieee80211_has_seq(wh)) { + /* + * Not necessarily a replayed frame since we did not + * check the sequence number of the 802.11 header yet. + */ + int nrxseq, orxseq; + + nrxseq = letoh16(*(u_int16_t *)wh->i_seq) >> + IEEE80211_SEQ_SEQ_SHIFT; + if (hasqos) + orxseq = ni->ni_qos_rxseqs[tid]; + else + orxseq = ni->ni_rxseq; + if (nrxseq < orxseq) { + DPRINTF(("CCMP replayed (n=%d < o=%d)\n", + nrxseq, orxseq)); + ic->ic_stats.is_ccmp_replays++; + return 1; + } + } else { + DPRINTF(("CCMP replayed\n")); + ic->ic_stats.is_ccmp_replays++; + return 1; + } } /* Update last seen packet number. */ *prsc = pn; @@ -1892,7 +1949,13 @@ iwn_rx_phy(struct iwn_softc *sc, struct iwn_rx_desc *desc, /* Save RX statistics, they will be used on MPDU_RX_DONE. */ memcpy(&sc->last_rx_stat, stat, sizeof (*stat)); - sc->last_rx_valid = 1; + sc->last_rx_valid = IWN_LAST_RX_VALID; + /* + * The firmware does not send separate RX_PHY + * notifications for A-MPDU subframes. + */ + if (stat->flags & htole16(IWN_STAT_FLAG_AGG)) + sc->last_rx_valid |= IWN_LAST_RX_AMPDU; } /* @@ -1922,8 +1985,18 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, DPRINTF(("missing RX_PHY\n")); return; } - sc->last_rx_valid = 0; + sc->last_rx_valid &= ~IWN_LAST_RX_VALID; stat = &sc->last_rx_stat; + if ((sc->last_rx_valid & IWN_LAST_RX_AMPDU) && + (stat->flags & htole16(IWN_STAT_FLAG_AGG)) == 0) { + DPRINTF(("missing RX_PHY (expecting A-MPDU)\n")); + return; + } + if ((sc->last_rx_valid & IWN_LAST_RX_AMPDU) == 0 && + (stat->flags & htole16(IWN_STAT_FLAG_AGG))) { + DPRINTF(("missing RX_PHY (unexpected A-MPDU)\n")); + return; + } } else stat = (struct iwn_rx_stat *)(desc + 1); @@ -2030,7 +2103,7 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, m_freem(m); return; } - if (iwn_ccmp_decap(sc, m, &ni->ni_pairwise_key) != 0) { + if (iwn_ccmp_decap(sc, m, ni) != 0) { ifp->if_ierrors++; m_freem(m); return; @@ -2281,9 +2354,10 @@ iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, int ackfailcnt, if (ackfailcnt > 0) wn->amn.amn_retrycnt++; - if (status != 1 && status != 2) + if (status != 1 && status != 2) { + DPRINTF(("%s: status=0x%x\n", __func__, status)); ifp->if_oerrors++; - else + } else ifp->if_opackets++; /* Unmap and free mbuf. */ @@ -2397,7 +2471,7 @@ iwn_notif_intr(struct iwn_softc *sc) * If more than 5 consecutive beacons are missed, * reinitialize the sensitivity state machine. */ - DPRINTF(("beacons missed %d/%d\n", + DPRINTFN(2, ("beacons missed %d/%d\n", letoh32(miss->consecutive), letoh32(miss->total))); if (ic->ic_state == IEEE80211_S_RUN && letoh32(miss->consecutive) > 5) @@ -2778,15 +2852,24 @@ iwn_tx(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) /* Choose a TX rate index. */ if (IEEE80211_IS_MULTICAST(wh->i_addr1) || - type != IEEE80211_FC0_TYPE_DATA) { - ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? + type != IEEE80211_FC0_TYPE_DATA) + ridx = (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) ? IWN_RIDX_OFDM6 : IWN_RIDX_CCK1; - } else if (ic->ic_fixed_rate != -1) { +#ifndef IEEE80211_NO_HT + else if (ic->ic_fixed_mcs != -1) ridx = sc->fixed_ridx; - } else - ridx = wn->ridx[ni->ni_txrate]; +#endif + else if (ic->ic_fixed_rate != -1) + ridx = sc->fixed_ridx; + else { +#ifndef IEEE80211_NO_HT + if (ni->ni_flags & IEEE80211_NODE_HT) + ridx = iwn_mcs2ridx[ni->ni_txmcs]; + else +#endif + ridx = wn->ridx[ni->ni_txrate]; + } rinfo = &iwn_rates[ridx]; - #if NBPFILTER > 0 if (sc->sc_drvbpf != NULL) { struct mbuf mb; @@ -2795,7 +2878,15 @@ iwn_tx(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) tap->wt_flags = 0; tap->wt_chan_freq = htole16(ni->ni_chan->ic_freq); tap->wt_chan_flags = htole16(ni->ni_chan->ic_flags); - tap->wt_rate = rinfo->rate; +#ifndef IEEE80211_NO_HT + if ((ni->ni_flags & IEEE80211_NODE_HT) && + !IEEE80211_IS_MULTICAST(wh->i_addr1) && + type == IEEE80211_FC0_TYPE_DATA) { + /* XXX need a way to pass current MCS in 11n mode */ + tap->wt_rate = 0; + } else +#endif + tap->wt_rate = rinfo->rate; tap->wt_hwqueue = ac; if ((ic->ic_flags & IEEE80211_F_WEPON) && (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) @@ -2857,7 +2948,7 @@ iwn_tx(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) /* Check if frame must be protected using RTS/CTS or CTS-to-self. */ if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { - /* NB: Group frames are sent using CCK in 802.11b/g. */ + /* NB: Group frames are sent using CCK in 802.11b/g/n (2GHz). */ if (totlen + IEEE80211_CRC_LEN > ic->ic_rtsthreshold) { flags |= IWN_TX_NEED_RTS; } else if ((ic->ic_flags & IEEE80211_F_USEPROT) && @@ -2867,6 +2958,10 @@ iwn_tx(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) flags |= IWN_TX_NEED_RTS; } +#ifndef IEEE80211_NO_HT + else if (ni->ni_flags & IEEE80211_NODE_HT) + flags |= IWN_TX_NEED_RTS; +#endif if (flags & (IWN_TX_NEED_RTS | IWN_TX_NEED_CTS)) { if (sc->hw_type != IWN_HW_REV_TYPE_4965) { /* 5000 autoselects RTS/CTS or CTS-to-self. */ @@ -2911,8 +3006,22 @@ iwn_tx(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) tx->rts_ntries = 60; tx->data_ntries = 15; tx->lifetime = htole32(IWN_LIFETIME_INFINITE); - tx->plcp = rinfo->plcp; - tx->rflags = rinfo->flags; + +#ifndef IEEE80211_NO_HT + if ((ni->ni_flags & IEEE80211_NODE_HT) && + tx->id != sc->broadcast_id) + tx->plcp = rinfo->ht_plcp; + else +#endif + tx->plcp = rinfo->plcp; + +#ifndef IEEE80211_NO_HT + if ((ni->ni_flags & IEEE80211_NODE_HT) && + tx->id != sc->broadcast_id) + tx->rflags = rinfo->ht_flags; + else +#endif + tx->rflags = rinfo->flags; if (tx->id == sc->broadcast_id) { /* Group or management frame. */ tx->linkq = 0; @@ -2920,7 +3029,12 @@ iwn_tx(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) txant = IWN_LSB(sc->txchainmask); tx->rflags |= IWN_RFLAG_ANT(txant); } else { - tx->linkq = ni->ni_rates.rs_nrates - ni->ni_txrate - 1; +#ifndef IEEE80211_NO_HT + if (ni->ni_flags & IEEE80211_NODE_HT) + tx->linkq = 7 - ni->ni_txmcs; /* XXX revisit for MIMO */ + else +#endif + tx->linkq = ni->ni_rates.rs_nrates - ni->ni_txrate - 1; flags |= IWN_TX_LINKQ; /* enable MRR */ } /* Set physical address of "scratch area". */ @@ -3308,17 +3422,45 @@ iwn_set_link_quality(struct iwn_softc *sc, struct ieee80211_node *ni) linkq.ampdu_threshold = 3; linkq.ampdu_limit = htole16(4000); /* 4ms */ - /* Start at highest available bit-rate. */ - txrate = rs->rs_nrates - 1; - for (i = 0; i < IWN_MAX_TX_RETRIES; i++) { - rinfo = &iwn_rates[wn->ridx[txrate]]; - linkq.retry[i].plcp = rinfo->plcp; - linkq.retry[i].rflags = rinfo->flags; - linkq.retry[i].rflags |= IWN_RFLAG_ANT(txant); - /* Next retry at immediate lower bit-rate. */ - if (txrate > 0) - txrate--; +#ifndef IEEE80211_NO_HT + if (ni->ni_flags & IEEE80211_NODE_HT) { + /* Fill LQ table with MCS 7 - 0 (XXX revisit for MIMO) */ + i = 0; + for (txrate = 7; txrate >= 0; txrate--) { + rinfo = &iwn_rates[iwn_mcs2ridx[txrate]]; + linkq.retry[i].plcp = rinfo->ht_plcp; + linkq.retry[i].rflags = rinfo->ht_flags; + + /* XXX set correct ant mask for MIMO rates here */ + linkq.retry[i].rflags |= IWN_RFLAG_ANT(txant); + + if (i++ >= IWN_MAX_TX_RETRIES) + break; + } + /* Fill the rest with MCS 0. */ + rinfo = &iwn_rates[iwn_mcs2ridx[0]]; + while (i < IWN_MAX_TX_RETRIES) { + linkq.retry[i].plcp = rinfo->ht_plcp; + linkq.retry[i].rflags = rinfo->ht_flags; + linkq.retry[i].rflags |= IWN_RFLAG_ANT(txant); + i++; + } + } else +#endif + { + /* Start at highest available bit-rate. */ + txrate = rs->rs_nrates - 1; + for (i = 0; i < IWN_MAX_TX_RETRIES; i++) { + rinfo = &iwn_rates[wn->ridx[txrate]]; + linkq.retry[i].plcp = rinfo->plcp; + linkq.retry[i].rflags = rinfo->flags; + linkq.retry[i].rflags |= IWN_RFLAG_ANT(txant); + /* Next retry at immediate lower bit-rate. */ + if (txrate > 0) + txrate--; + } } + return iwn_cmd(sc, IWN_CMD_LINK_QUALITY, &linkq, sizeof linkq, 1); } @@ -3326,7 +3468,7 @@ iwn_set_link_quality(struct iwn_softc *sc, struct ieee80211_node *ni) * Broadcast node is used to send group-addressed and management frames. */ int -iwn_add_broadcast_node(struct iwn_softc *sc, int async) +iwn_add_broadcast_node(struct iwn_softc *sc, int async, int ridx) { struct iwn_ops *ops = &sc->ops; struct iwn_node_info node; @@ -3354,8 +3496,7 @@ iwn_add_broadcast_node(struct iwn_softc *sc, int async) linkq.ampdu_limit = htole16(4000); /* 4ms */ /* Use lowest mandatory bit-rate. */ - rinfo = (sc->sc_ic.ic_curmode != IEEE80211_MODE_11A) ? - &iwn_rates[IWN_RIDX_CCK1] : &iwn_rates[IWN_RIDX_OFDM6]; + rinfo = &iwn_rates[ridx]; linkq.retry[0].plcp = rinfo->plcp; linkq.retry[0].rflags = rinfo->flags; linkq.retry[0].rflags |= IWN_RFLAG_ANT(txant); @@ -3564,8 +3705,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 ((ridx / 8) & 1) +#ifdef notyet + if (ridx > iwn_mcs2ridx[7] && ridx < iwn_mcs2ridx[16]) maxchpwr -= 6; /* MIMO 2T: -3dB */ +#endif pwr = maxpwr; @@ -3584,7 +3727,7 @@ iwn4965_set_txpower(struct iwn_softc *sc, int async) pwr = maxchpwr; idx = gain - (pwr - power) - tdiff - vdiff; - if ((ridx / 8) & 1) /* MIMO */ + if (ridx > iwn_mcs2ridx[7]) /* MIMO */ idx += (int32_t)letoh32(uc->atten[grp][c]); if (cmd.band == 0) @@ -3766,7 +3909,7 @@ iwn_init_sensitivity(struct iwn_softc *sc) /* Request statistics at each beacon interval. */ flags = 0; - DPRINTF(("sending request for statistics\n")); + DPRINTFN(2, ("sending request for statistics\n")); return iwn_cmd(sc, IWN_CMD_GET_STATISTICS, &flags, sizeof flags, 1); } @@ -4277,7 +4420,7 @@ iwn_config(struct iwn_softc *sc) struct ifnet *ifp = &ic->ic_if; uint32_t txmask; uint16_t rxchain; - int error; + int error, ridx; /* Set radio temperature sensor offset. */ if (sc->hw_type == IWN_HW_REV_TYPE_6005) { @@ -4343,8 +4486,13 @@ iwn_config(struct iwn_softc *sc) IEEE80211_ADDR_COPY(sc->rxon.wlap, ic->ic_myaddr); sc->rxon.chan = ieee80211_chan2ieee(ic, ic->ic_ibss_chan); sc->rxon.flags = htole32(IWN_RXON_TSF | IWN_RXON_CTS_TO_SELF); - if (IEEE80211_IS_CHAN_2GHZ(ic->ic_ibss_chan)) + if (IEEE80211_IS_CHAN_2GHZ(ic->ic_ibss_chan)) { sc->rxon.flags |= htole32(IWN_RXON_AUTO | IWN_RXON_24GHZ); + if (ic->ic_flags & IEEE80211_F_USEPROT) + sc->rxon.flags |= htole32(IWN_RXON_TGG_PROT); + DPRINTF(("%s: 2ghz prot 0x%x\n", __func__, + le32toh(sc->rxon.flags))); + } switch (ic->ic_opmode) { case IEEE80211_M_STA: sc->rxon.mode = IWN_MODE_STA; @@ -4376,7 +4524,9 @@ iwn_config(struct iwn_softc *sc) return error; } - if ((error = iwn_add_broadcast_node(sc, 0)) != 0) { + ridx = (sc->sc_ic.ic_curmode == IEEE80211_MODE_11A) ? + IWN_RIDX_OFDM6 : IWN_RIDX_CCK1; + if ((error = iwn_add_broadcast_node(sc, 0, ridx)) != 0) { printf("%s: could not add broadcast node\n", sc->sc_dev.dv_xname); return error; @@ -4664,14 +4814,19 @@ iwn_auth(struct iwn_softc *sc) struct iwn_ops *ops = &sc->ops; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = ic->ic_bss; - int error; + int error, ridx; /* Update adapter configuration. */ IEEE80211_ADDR_COPY(sc->rxon.bssid, ni->ni_bssid); sc->rxon.chan = ieee80211_chan2ieee(ic, ni->ni_chan); sc->rxon.flags = htole32(IWN_RXON_TSF | IWN_RXON_CTS_TO_SELF); - if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) + if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) { sc->rxon.flags |= htole32(IWN_RXON_AUTO | IWN_RXON_24GHZ); + if (ic->ic_flags & IEEE80211_F_USEPROT) + sc->rxon.flags |= htole32(IWN_RXON_TGG_PROT); + DPRINTF(("%s: 2ghz prot 0x%x\n", __func__, + le32toh(sc->rxon.flags))); + } if (ic->ic_flags & IEEE80211_F_SHSLOT) sc->rxon.flags |= htole32(IWN_RXON_SHSLOT); if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) @@ -4685,12 +4840,13 @@ iwn_auth(struct iwn_softc *sc) sc->rxon.cck_mask = 0x03; sc->rxon.ofdm_mask = 0; break; - default: /* Assume 802.11b/g. */ + default: /* Assume 802.11b/g/n. */ sc->rxon.cck_mask = 0x0f; sc->rxon.ofdm_mask = 0x15; } - DPRINTF(("rxon chan %d flags %x cck %x ofdm %x\n", sc->rxon.chan, - sc->rxon.flags, sc->rxon.cck_mask, sc->rxon.ofdm_mask)); + 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)); error = iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, sc->rxonsz, 1); if (error != 0) { printf("%s: RXON command failed\n", sc->sc_dev.dv_xname); @@ -4706,7 +4862,9 @@ iwn_auth(struct iwn_softc *sc) * Reconfiguring RXON clears the firmware nodes table so we must * add the broadcast node again. */ - if ((error = iwn_add_broadcast_node(sc, 1)) != 0) { + ridx = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? + IWN_RIDX_OFDM6 : IWN_RIDX_CCK1; + if ((error = iwn_add_broadcast_node(sc, 1, ridx)) != 0) { printf("%s: could not add broadcast node\n", sc->sc_dev.dv_xname); return error; @@ -4742,7 +4900,40 @@ iwn_run(struct iwn_softc *sc) if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) sc->rxon.flags |= htole32(IWN_RXON_SHPREAMBLE); sc->rxon.filter |= htole32(IWN_FILTER_BSS); - DPRINTF(("rxon chan %d flags %x\n", sc->rxon.chan, sc->rxon.flags)); +#ifndef IEEE80211_NO_HT + /* HT is negotiated when associating. */ + if (ni->ni_flags & IEEE80211_NODE_HT) { + enum ieee80211_htprot htprot = + (ni->ni_htop1 & IEEE80211_HTOP1_PROT_MASK); + DPRINTF(("%s: htprot = %d\n", __func__, htprot)); + sc->rxon.flags |= htole32(IWN_RXON_HT_PROTMODE(htprot)); + } else + sc->rxon.flags &= ~htole32(IWN_RXON_HT_PROTMODE(3)); +#endif + if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) { + /* 11a or 11n 5GHz */ + sc->rxon.cck_mask = 0; + sc->rxon.ofdm_mask = 0x15; +#ifndef IEEE80211_NO_HT + } else if (ni->ni_flags & IEEE80211_NODE_HT) { + /* 11n 2GHz */ + sc->rxon.cck_mask = 0x0f; + sc->rxon.ofdm_mask = 0x15; +#endif + } else { + if (ni->ni_rates.rs_nrates == 4) { + /* 11b */ + sc->rxon.cck_mask = 0x03; + sc->rxon.ofdm_mask = 0; + } else { + /* assume 11g */ + sc->rxon.cck_mask = 0x0f; + sc->rxon.ofdm_mask = 0x15; + } + } + 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)); error = iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, sc->rxonsz, 1); if (error != 0) { printf("%s: could not update configuration\n", @@ -4879,8 +5070,9 @@ iwn_ampdu_rx_start(struct ieee80211com *ic, struct ieee80211_node *ni, node.flags = IWN_FLAG_SET_ADDBA; node.addba_tid = tid; node.addba_ssn = htole16(ba->ba_winstart); - DPRINTFN(2, ("ADDBA RA=%d TID=%d SSN=%d\n", wn->id, tid, + DPRINTF(("ADDBA RA=%d TID=%d SSN=%d\n", wn->id, tid, ba->ba_winstart)); + /* XXX async command, so firmware may still fail to add BA agreement */ return ops->add_node(sc, &node, 1); } @@ -4902,7 +5094,7 @@ iwn_ampdu_rx_stop(struct ieee80211com *ic, struct ieee80211_node *ni, node.control = IWN_NODE_UPDATE; node.flags = IWN_FLAG_SET_DELBA; node.delba_tid = tid; - DPRINTFN(2, ("DELBA RA=%d TID=%d\n", wn->id, tid)); + DPRINTF(("DELBA RA=%d TID=%d\n", wn->id, tid)); (void)ops->add_node(sc, &node, 1); } @@ -6007,7 +6199,7 @@ iwn_hw_init(struct iwn_softc *sc) IWN_FH_RX_CONFIG_IGN_RXF_EMPTY | /* HW bug workaround */ IWN_FH_RX_CONFIG_IRQ_DST_HOST | IWN_FH_RX_CONFIG_SINGLE_FRAME | - IWN_FH_RX_CONFIG_RB_TIMEOUT(0) | + IWN_FH_RX_CONFIG_RB_TIMEOUT(0x11) | /* about 1/2 msec */ IWN_FH_RX_CONFIG_NRBD(IWN_RX_RING_COUNT_LOG)); iwn_nic_unlock(sc); IWN_WRITE(sc, IWN_FH_RX_WPTR, (IWN_RX_RING_COUNT - 1) & ~7); diff --git a/sys/dev/pci/if_iwnreg.h b/sys/dev/pci/if_iwnreg.h index 14cb12ea42f..cd0018a7fdd 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.49 2014/09/09 18:56:24 sthen Exp $ */ +/* $OpenBSD: if_iwnreg.h,v 1.50 2016/01/04 13:54:19 stsp Exp $ */ /*- * Copyright (c) 2007, 2008 @@ -301,7 +301,7 @@ #define IWN_FH_RX_CONFIG_RB_SIZE_8K (1U << 16) #define IWN_FH_RX_CONFIG_SINGLE_FRAME (1U << 15) #define IWN_FH_RX_CONFIG_IRQ_DST_HOST (1U << 12) -#define IWN_FH_RX_CONFIG_RB_TIMEOUT(x) ((x) << 4) +#define IWN_FH_RX_CONFIG_RB_TIMEOUT(x) ((x) << 4) /* units 32 usec */ #define IWN_FH_RX_CONFIG_IGN_RXF_EMPTY (1U << 2) /* Possible flags for register IWN_FH_TX_CONFIG. */ @@ -383,6 +383,12 @@ struct iwn_rx_status { struct iwn_rx_desc { uint32_t len; +#define IWN_RX_DESC_LEN_MASK 0x00003fff +#define IWN_RX_DESC_LEN_SHIFT 0 +#define IWN_RX_DESC_FLAG_FLUSH_RB_REQ 0x80000000 +#define IWN_RX_DESC_FLAG_IGNORE_TC 0x40000000 +#define IWN_RX_DESC_FLAG_FAST_IRQ 0x20000000 + uint8_t type; #define IWN_UC_READY 1 #define IWN_ADD_NODE_DONE 24 @@ -400,7 +406,7 @@ struct iwn_rx_desc { #define IWN_RX_DONE 195 #define IWN_RX_COMPRESSED_BA 197 - uint8_t flags; + uint8_t flags; /* XXX iwlwifi calls this "group_id" */ uint8_t idx; uint8_t qid; } __packed; @@ -488,12 +494,17 @@ struct iwn_rxon { #define IWN_RXON_24GHZ (1 << 0) #define IWN_RXON_CCK (1 << 1) #define IWN_RXON_AUTO (1 << 2) +#define IWN_RXON_TGG_PROT (1 << 3) #define IWN_RXON_SHSLOT (1 << 4) #define IWN_RXON_SHPREAMBLE (1 << 5) #define IWN_RXON_NODIVERSITY (1 << 7) #define IWN_RXON_ANTENNA_A (1 << 8) #define IWN_RXON_ANTENNA_B (1 << 9) #define IWN_RXON_TSF (1 << 15) +#define IWN_RXON_HT_HT40MINUS (1 << 22) +#define IWN_RXON_HT_PROTMODE(x) ((x) << 23) /* 2 bits */ +#define IWN_RXON_HT_CHANMODE_PURE40 (1 << 25) +#define IWN_RXON_HT_CHANMODE_MIXED2040 (2 << 25) #define IWN_RXON_CTS_TO_SELF (1 << 30) uint32_t filter; @@ -630,7 +641,12 @@ struct iwn4965_node_info { uint32_t reserved7; } __packed; +#define IWN_RFLAG_MCS (1 << 0) #define IWN_RFLAG_CCK (1 << 1) +#define IWN_RFLAG_GREENFIELD (1 << 2) +#define IWN_RFLAG_HT40 (1 << 3) +#define IWN_RFLAG_DUPLICATE (1 << 4) +#define IWN_RFLAG_SGI (1 << 5) #define IWN_RFLAG_ANT(x) ((x) << 6) /* Structure for command IWN_CMD_TX_DATA. */ @@ -1222,7 +1238,12 @@ struct iwn_rx_stat { uint64_t tstamp; uint32_t beacon; uint16_t flags; +#define IWN_STAT_FLAG_24GHZ (1 << 0) +#define IWN_STAT_FLAG_MOD_CCK (1 << 1) #define IWN_STAT_FLAG_SHPREAMBLE (1 << 2) +#define IWN_STAT_FLAG_NARROW_BAND (1 << 3) +#define IWN_STAT_FLAG_ANT(x) ((x) << 4) /* 3 bits */ +#define IWN_STAT_FLAG_AGG (1 << 7) uint16_t chan; uint8_t phybuf[32]; @@ -1659,26 +1680,34 @@ static const struct iwn_chan_band { #define IWN_RIDX_CCK1 0 #define IWN_RIDX_OFDM6 4 +#define IWN_PLCP_INVALID 0xff + static const struct iwn_rate { uint8_t rate; uint8_t plcp; uint8_t flags; + uint8_t ht_plcp; + uint8_t ht_flags; } iwn_rates[IWN_RIDX_MAX + 1] = { - { 2, 10, IWN_RFLAG_CCK }, - { 4, 20, IWN_RFLAG_CCK }, - { 11, 55, IWN_RFLAG_CCK }, - { 22, 110, IWN_RFLAG_CCK }, - { 12, 0xd, 0 }, - { 18, 0xf, 0 }, - { 24, 0x5, 0 }, - { 36, 0x7, 0 }, - { 48, 0x9, 0 }, - { 72, 0xb, 0 }, - { 96, 0x1, 0 }, - { 108, 0x3, 0 }, - { 120, 0x3, 0 } + /* Legacy */ /* HT */ + { 2, 10, IWN_RFLAG_CCK, IWN_PLCP_INVALID, 0 }, + { 4, 20, IWN_RFLAG_CCK, IWN_PLCP_INVALID, 0 }, + { 11, 55, IWN_RFLAG_CCK, IWN_PLCP_INVALID, 0 }, + { 22, 110, IWN_RFLAG_CCK, IWN_PLCP_INVALID, 0 }, + { 12, 0xd, 0, 0, IWN_RFLAG_MCS }, + { 18, 0xf, 0, IWN_PLCP_INVALID, 0 }, + { 24, 0x5, 0, 1, IWN_RFLAG_MCS }, + { 36, 0x7, 0, 2, IWN_RFLAG_MCS, }, + { 48, 0x9, 0, 3, IWN_RFLAG_MCS, }, + { 72, 0xb, 0, 4, IWN_RFLAG_MCS, }, + { 96, 0x1, 0, 5, IWN_RFLAG_MCS, }, + { 108, 0x3, 0, 6, IWN_RFLAG_MCS, }, + { 128, IWN_PLCP_INVALID, 0, 7, IWN_RFLAG_MCS, } }; +/* Convert an MCS index into an iwn_rates[] index. */ +const int iwn_mcs2ridx[] = { 4, 6, 7, 8, 9, 10, 11, 12 }; + #define IWN4965_MAX_PWR_INDEX 107 /* diff --git a/sys/dev/pci/if_iwnvar.h b/sys/dev/pci/if_iwnvar.h index a20522cbcda..e1370e0c6b7 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.28 2014/09/09 18:55:08 sthen Exp $ */ +/* $OpenBSD: if_iwnvar.h,v 1.29 2016/01/04 13:54:19 stsp Exp $ */ /*- * Copyright (c) 2007, 2008 @@ -259,6 +259,8 @@ struct iwn_softc { struct iwn_rx_stat last_rx_stat; int last_rx_valid; +#define IWN_LAST_RX_VALID 0x01 +#define IWN_LAST_RX_AMPDU 0x02 struct iwn_ucode_info ucode_info; struct iwn_rxon rxon; uint32_t rawtemp; |