summaryrefslogtreecommitdiff
path: root/sys/dev/pci
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/pci')
-rw-r--r--sys/dev/pci/if_iwn.c322
-rw-r--r--sys/dev/pci/if_iwnreg.h61
-rw-r--r--sys/dev/pci/if_iwnvar.h4
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;