Index: sys/dev/iwn/if_iwn.c =================================================================== --- sys/dev/iwn/if_iwn.c (revision 270068) +++ sys/dev/iwn/if_iwn.c (working copy) @@ -393,6 +393,15 @@ } static int +iwn_is_3stream_device(struct iwn_softc *sc) +{ + /* XXX for now only 5300, until the 5350 can be tested */ + if (sc->hw_type == IWN_HW_REV_TYPE_5300) + return (1); + return (0); +} + +static int iwn_attach(device_t dev) { struct iwn_softc *sc = (struct iwn_softc *)device_get_softc(dev); @@ -594,21 +603,16 @@ ic->ic_txstream = sc->ntxchains; /* - * The NICs we currently support cap out at 2x2 support - * separate from the chains being used. - * - * This is a total hack to work around that until some - * per-device method is implemented to return the - * actual stream support. - * - * XXX Note: the 5350 is a 3x3 device; so we shouldn't - * cap this! But, anything that touches rates in the - * driver needs to be audited first before 3x3 is enabled. + * Some of the 3 antenna devices (ie, the 4965) only supports + * 2x2 operation. So correct the number of streams if + * it's not a 3-stream device. */ - if (ic->ic_rxstream > 2) - ic->ic_rxstream = 2; - if (ic->ic_txstream > 2) - ic->ic_txstream = 2; + if (! iwn_is_3stream_device(sc)) { + if (ic->ic_rxstream > 2) + ic->ic_rxstream = 2; + if (ic->ic_txstream > 2) + ic->ic_txstream = 2; + } ic->ic_htcaps = IEEE80211_HTCAP_SMPS_OFF /* SMPS mode disabled */ @@ -2633,6 +2637,52 @@ return 0; } +static int +iwn_get_1stream_tx_antmask(struct iwn_softc *sc) +{ + + return IWN_LSB(sc->txchainmask); +} + +static int +iwn_get_2stream_tx_antmask(struct iwn_softc *sc) +{ + int tx; + + /* + * The '2 stream' setup is a bit .. odd. + * + * For NICs that support only 1 antenna, default to IWN_ANT_AB or + * the firmware panics (eg Intel 5100.) + * + * For NICs that support two antennas, we use ANT_AB. + * + * For NICs that support three antennas, we use the two that + * wasn't the default one. + * + * XXX TODO: if bluetooth (full concurrent) is enabled, restrict + * this to only one antenna. + */ + + /* Default - transmit on the other antennas */ + tx = (sc->txchainmask & ~IWN_LSB(sc->txchainmask)); + + /* Now, if it's zero, set it to IWN_ANT_AB, so to not panic firmware */ + if (tx == 0) + tx = IWN_ANT_AB; + + /* + * If the NIC is a two-stream TX NIC, configure the TX mask to + * the default chainmask + */ + else if (sc->ntxchains == 2) + tx = sc->txchainmask; + + return (tx); +} + + + /* * Calculate the required PLCP value from the given rate, * to the given node. @@ -2646,14 +2696,9 @@ { #define RV(v) ((v) & IEEE80211_RATE_VAL) struct ieee80211com *ic = ni->ni_ic; - uint8_t txant1, txant2; uint32_t plcp = 0; int ridx; - /* Use the first valid TX antenna. */ - txant1 = IWN_LSB(sc->txchainmask); - txant2 = IWN_LSB(sc->txchainmask & ~txant1); - /* * If it's an MCS rate, let's set the plcp correctly * and set the relevant flags based on the node config. @@ -2685,15 +2730,15 @@ } /* - * If it's a two stream rate, enable TX on both - * antennas. - * - * XXX three stream rates? + * Ensure the selected rate matches the link quality + * table entries being used. */ - if (rate > 0x87) - plcp |= IWN_RFLAG_ANT(txant1 | txant2); + if (rate > 0x8f) + plcp |= IWN_RFLAG_ANT(sc->txchainmask); + else if (rate > 0x87) + plcp |= IWN_RFLAG_ANT(iwn_get_2stream_tx_antmask(sc)); else - plcp |= IWN_RFLAG_ANT(txant1); + plcp |= IWN_RFLAG_ANT(iwn_get_1stream_tx_antmask(sc)); } else { /* * Set the initial PLCP - fine for both @@ -2715,7 +2760,8 @@ plcp |= IWN_RFLAG_CCK; /* Set antenna configuration */ - plcp |= IWN_RFLAG_ANT(txant1); + /* XXX TODO: is this the right antenna to use for legacy? */ + plcp |= IWN_RFLAG_ANT(iwn_get_1stream_tx_antmask(sc)); } DPRINTF(sc, IWN_DEBUG_TXRATE, "%s: rate=0x%02x, plcp=0x%08x\n", @@ -3047,8 +3093,9 @@ uint16_t ssn; uint8_t tid; int ackfailcnt = 0, i, lastidx, qid, *res, shift; + int tx_ok = 0, tx_err = 0; - DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); + DPRINTF(sc, IWN_DEBUG_TRACE | IWN_DEBUG_XMIT, "->%s begin\n", __func__); bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); @@ -3108,10 +3155,12 @@ for (i = 0; bitmap; i++) { if ((bitmap & 1) == 0) { ifp->if_oerrors++; + tx_err ++; ieee80211_ratectl_tx_complete(ni->ni_vap, ni, IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL); } else { ifp->if_opackets++; + tx_ok ++; ieee80211_ratectl_tx_complete(ni->ni_vap, ni, IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL); } @@ -3118,7 +3167,7 @@ bitmap >>= 1; } - DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); + DPRINTF(sc, IWN_DEBUG_TRACE | IWN_DEBUG_XMIT, "->%s: end; %d ok; %d err\n",__func__, tx_ok, tx_err); } @@ -4441,12 +4490,13 @@ data->ni = ni; DPRINTF(sc, IWN_DEBUG_XMIT, - "%s: qid %d idx %d len %d nsegs %d rate %04x plcp 0x%08x\n", + "%s: qid %d idx %d len %d nsegs %d flags 0x%08x rate 0x%04x plcp 0x%08x\n", __func__, ring->qid, ring->cur, m->m_pkthdr.len, nsegs, + flags, rate, tx->rate); @@ -4974,50 +5024,16 @@ struct iwn_node *wn = (void *)ni; struct ieee80211_rateset *rs; struct iwn_cmd_link_quality linkq; - uint8_t txant; int i, rate, txrate; int is_11n; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); - /* Use the first valid TX antenna. */ - txant = IWN_LSB(sc->txchainmask); - memset(&linkq, 0, sizeof linkq); linkq.id = wn->id; - linkq.antmsk_1stream = txant; + linkq.antmsk_1stream = iwn_get_1stream_tx_antmask(sc); + linkq.antmsk_2stream = iwn_get_2stream_tx_antmask(sc); - /* - * The '2 stream' setup is a bit .. odd. - * - * For NICs that support only 1 antenna, default to IWN_ANT_AB or - * the firmware panics (eg Intel 5100.) - * - * For NICs that support two antennas, we use ANT_AB. - * - * For NICs that support three antennas, we use the two that - * wasn't the default one. - * - * XXX TODO: if bluetooth (full concurrent) is enabled, restrict - * this to only one antenna. - */ - - /* So - if there's no secondary antenna, assume IWN_ANT_AB */ - - /* Default - transmit on the other antennas */ - linkq.antmsk_2stream = (sc->txchainmask & ~IWN_LSB(sc->txchainmask)); - - /* Now, if it's zero, set it to IWN_ANT_AB, so to not panic firmware */ - if (linkq.antmsk_2stream == 0) - linkq.antmsk_2stream = IWN_ANT_AB; - - /* - * If the NIC is a two-stream TX NIC, configure the TX mask to - * the default chainmask - */ - else if (sc->ntxchains == 2) - linkq.antmsk_2stream = sc->txchainmask; - linkq.ampdu_max = 32; /* XXX negotiated? */ linkq.ampdu_threshold = 3; linkq.ampdu_limit = htole16(4000); /* 4ms */ @@ -5053,22 +5069,29 @@ for (i = 0; i < IWN_MAX_TX_RETRIES; i++) { uint32_t plcp; + /* + * XXX TODO: ensure the last two slots are the two lowest + * rate entries, just for now. + */ + if (i == 14 || i == 15) + txrate = 0; + if (is_11n) rate = IEEE80211_RATE_MCS | rs->rs_rates[txrate]; else rate = RV(rs->rs_rates[txrate]); + /* Do rate -> PLCP config mapping */ + plcp = iwn_rate_to_plcp(sc, ni, rate); + linkq.retry[i] = plcp; DPRINTF(sc, IWN_DEBUG_XMIT, - "%s: i=%d, txrate=%d, rate=0x%02x\n", + "%s: i=%d, txrate=%d, rate=0x%02x, plcp=0x%08x\n", __func__, i, txrate, - rate); + rate, + le32toh(plcp)); - /* Do rate -> PLCP config mapping */ - plcp = iwn_rate_to_plcp(sc, ni, rate); - linkq.retry[i] = plcp; - /* * The mimo field is an index into the table which * indicates the first index where it and subsequent entries @@ -5088,7 +5111,16 @@ if (txrate > 0) txrate--; } + /* + * If we reached the end of the list and indeed we hit + * all MIMO rates (eg 5300 doing MCS23-15) then yes, + * set mimo to 15. Setting it to 16 panics the firmware. + */ + if (linkq.mimo > 15) + linkq.mimo = 15; + DPRINTF(sc, IWN_DEBUG_XMIT, "%s: mimo = %d\n", __func__, linkq.mimo); + DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); return iwn_cmd(sc, IWN_CMD_LINK_QUALITY, &linkq, sizeof linkq, 1); @@ -5125,13 +5157,14 @@ memset(&linkq, 0, sizeof linkq); linkq.id = sc->broadcast_id; - linkq.antmsk_1stream = txant; - linkq.antmsk_2stream = IWN_ANT_AB; + linkq.antmsk_1stream = iwn_get_1stream_tx_antmask(sc); + linkq.antmsk_2stream = iwn_get_2stream_tx_antmask(sc); linkq.ampdu_max = 64; linkq.ampdu_threshold = 3; linkq.ampdu_limit = htole16(4000); /* 4ms */ /* Use lowest mandatory bit-rate. */ + /* XXX rate table lookup? */ if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) linkq.retry[0] = htole32(0xd); else @@ -5438,6 +5471,7 @@ int async) { struct iwn5000_cmd_txpower cmd; + int cmdid; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); @@ -5449,8 +5483,12 @@ cmd.global_limit = 2 * IWN5000_TXPOWER_MAX_DBM; /* 16 dBm */ cmd.flags = IWN5000_TXPOWER_NO_CLOSED; cmd.srv_limit = IWN5000_TXPOWER_AUTO; - DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: setting TX power\n", __func__); - return iwn_cmd(sc, IWN_CMD_TXPOWER_DBM, &cmd, sizeof cmd, async); + DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_XMIT, "%s: setting TX power; rev=%d\n", __func__, IWN_UCODE_API(sc->ucode_rev)); + if (IWN_UCODE_API(sc->ucode_rev) == 1) + cmdid = IWN_CMD_TXPOWER_DBM_V1; + else + cmdid = IWN_CMD_TXPOWER_DBM; + return iwn_cmd(sc, cmdid, &cmd, sizeof cmd, async); } /* @@ -5650,7 +5688,7 @@ for (i = 0; i < 3; i++) if (val - calib->rssi[i] > 15 * 20) sc->chainmask &= ~(1 << i); - DPRINTF(sc, IWN_DEBUG_CALIBRATE, + DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_XMIT, "%s: RX chains mask: theoretical=0x%x, actual=0x%x\n", __func__, sc->rxchainmask, sc->chainmask); @@ -5775,7 +5813,7 @@ cmd.gain[i - 1] |= 1 << 2; /* sign bit */ } } - DPRINTF(sc, IWN_DEBUG_CALIBRATE, + DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_XMIT, "setting differential gains Ant B/C: %x/%x (%x)\n", cmd.gain[0], cmd.gain[1], sc->chainmask); return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 1); @@ -6309,9 +6347,10 @@ } /* Configure valid TX chains for >=5000 Series. */ - if (sc->hw_type != IWN_HW_REV_TYPE_4965) { + if (sc->hw_type != IWN_HW_REV_TYPE_4965 && + IWN_UCODE_API(sc->ucode_rev) > 1) { txmask = htole32(sc->txchainmask); - DPRINTF(sc, IWN_DEBUG_RESET, + DPRINTF(sc, IWN_DEBUG_RESET | IWN_DEBUG_XMIT, "%s: configuring valid TX chains 0x%x\n", __func__, txmask); error = iwn_cmd(sc, IWN5000_CMD_TX_ANT_CONFIG, &txmask, sizeof txmask, 0); @@ -6367,11 +6406,24 @@ sc->rxon->ht_single_mask = 0xff; sc->rxon->ht_dual_mask = 0xff; sc->rxon->ht_triple_mask = 0xff; + /* + * In active association mode, ensure that + * all the receive chains are enabled. + * + * Since we're not yet doing SMPS, don't allow the + * number of idle RX chains to be less than the active + * number. + */ rxchain = IWN_RXCHAIN_VALID(sc->rxchainmask) | - IWN_RXCHAIN_MIMO_COUNT(2) | - IWN_RXCHAIN_IDLE_COUNT(2); + IWN_RXCHAIN_MIMO_COUNT(sc->nrxchains) | + IWN_RXCHAIN_IDLE_COUNT(sc->nrxchains); sc->rxon->rxchain = htole16(rxchain); + DPRINTF(sc, IWN_DEBUG_RESET | IWN_DEBUG_XMIT, + "%s: rxchainmask=0x%x, nrxchains=%d\n", + __func__, + sc->rxchainmask, + sc->nrxchains); DPRINTF(sc, IWN_DEBUG_RESET, "%s: setting configuration\n", __func__); if (sc->sc_is_scanning) device_printf(sc->sc_dev, @@ -7806,6 +7858,8 @@ ptr = (const uint32_t *)fw->data; rev = le32toh(*ptr++); + sc->ucode_rev = rev; + /* Check firmware API version. */ if (IWN_FW_API(rev) <= 1) { device_printf(sc->sc_dev, @@ -7871,6 +7925,7 @@ } DPRINTF(sc, IWN_DEBUG_RESET, "FW: \"%.64s\", build 0x%x\n", hdr->descr, le32toh(hdr->build)); + sc->ucode_rev = le32toh(hdr->rev); /* * Select the closest supported alternative that is less than @@ -8018,6 +8073,8 @@ return error; } + device_printf(sc->sc_dev, "%s: ucode rev=0x%08x\n", __func__, sc->ucode_rev); + /* Make sure text and data sections fit in hardware memory. */ if (fw->main.textsz > sc->fw_text_maxsz || fw->main.datasz > sc->fw_data_maxsz || Index: sys/dev/iwn/if_iwnreg.h =================================================================== --- sys/dev/iwn/if_iwnreg.h (revision 270068) +++ sys/dev/iwn/if_iwnreg.h (working copy) @@ -489,6 +489,7 @@ #define IWN_CMD_TXPOWER_DBM 149 #define IWN_CMD_TXPOWER 151 #define IWN5000_CMD_TX_ANT_CONFIG 152 +#define IWN_CMD_TXPOWER_DBM_V1 152 #define IWN_CMD_BT_COEX 155 #define IWN_CMD_GET_STATISTICS 156 #define IWN_CMD_SET_CRITICAL_TEMP 164 Index: sys/dev/iwn/if_iwnvar.h =================================================================== --- sys/dev/iwn/if_iwnvar.h (revision 270068) +++ sys/dev/iwn/if_iwnvar.h (working copy) @@ -414,6 +414,9 @@ /* For specific params */ const struct iwn_base_params *base_params; + +#define IWN_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) + uint32_t ucode_rev; }; #define IWN_LOCK_INIT(_sc) \