diff --git a/sys/dev/iwx/if_iwx.c b/sys/dev/iwx/if_iwx.c index e317ff9e271c..8d669c2dfffc 100644 --- a/sys/dev/iwx/if_iwx.c +++ b/sys/dev/iwx/if_iwx.c @@ -648,6 +648,197 @@ const struct ieee80211_rateset ieee80211_std_rateset_11b = const struct ieee80211_rateset ieee80211_std_rateset_11g = { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } }; +/** + * @brief Return the firmware code for a legacy (CCK/OFDM) rate. + * + * This returns the firmware code for a legacy CCK/OFDM 11abg + * rate, or -1 if it is not said legacy rate. + */ +static int +iwx_lookup_fw_plcp_legacy(struct iwx_softc *sc, int dot11rate) +{ + switch (dot11rate) { + /* CCK dot11rate entries */ + case 2: + return (IWX_RATE_1M_PLCP); + case 4: + return (IWX_RATE_2M_PLCP); + case 11: + return (IWX_RATE_5M_PLCP); + case 22: + return (IWX_RATE_11M_PLCP); + + /* OFDM dot11rate entries */ + case 12: + return (IWX_RATE_6M_PLCP); + case 18: + return (IWX_RATE_9M_PLCP); + case 24: + return (IWX_RATE_12M_PLCP); + case 36: + return (IWX_RATE_18M_PLCP); + case 48: + return (IWX_RATE_24M_PLCP); + case 76: + return (IWX_RATE_36M_PLCP); + case 96: + return (IWX_RATE_48M_PLCP); + case 108: + return (IWX_RATE_54M_PLCP); + + default: + return (-1); + } +} + +static bool +iwx_lookup_fw_legacy_plcp_is_cck(struct iwx_softc *sc, int dot11rate) +{ + switch (dot11rate) { + case IWX_RATE_1M_PLCP: + case IWX_RATE_2M_PLCP: + case IWX_RATE_5M_PLCP: + case IWX_RATE_11M_PLCP: + return (true); + default: + return (false); + } +} + + +/* + * @brief Return the firmware code for legacy, HT or VHT rate + * + * This routine returns the firmware rate field (but not the + * rest of the rate_n_flags mask, which specifies things such as + * the rate type, 1/2 stream, antenna requirements, etc) for the + * given ieee80211_node_txrate. + * + * Callers can call this to see if it's a known/supported rate + * by firmware and if it returns -1 then it knows it's not a supported + * rate and should default to a known good minimum rate. + */ +static int +iwx_lookup_fw_plcp(struct iwx_softc *sc, const struct ieee80211_node_txrate *txr) +{ + struct ieee80211com *ic = &sc->sc_ic; + + switch (txr->type) { + case IEEE80211_NODE_TXRATE_LEGACY: + return (iwx_lookup_fw_plcp_legacy(sc, txr->dot11rate)); + case IEEE80211_NODE_TXRATE_HT: + /* + * Map MCS straight to fw; could do with some firmware bounds + * checking in case we're asked to do something out of whack. + */ + return (IWX_RATE_HT_SISO_MCS_0_PLCP + txr->mcs); + case IEEE80211_NODE_TXRATE_VHT: + /* + * Map VHT MCS/NSS to firmware. Again, should sanity check + * the values so we don't try to send garbage to firmware. + */ + return (IWX_RATE_VHT_SISO_MCS_0_PLCP + (txr->nss * 10) + + txr->mcs); + default: + net80211_ic_printf(ic, "%s: unknown rate type (%d)\n", + __func__, + txr->type); + return (-1); + } +} + +/** + * @brief Assemble a full rate_n_flags field for the given ieee80211_node_txrate. + * + * This looks at the driver state / firmware version and then assembles + * a rate_n_flags field suitable for the given firmware rate (given in plcp.) + * + * Note - this currently won't set the HT/VHT configuration fields besides + * the minimum required for HT20/VHT20 to work - no SGI, no 40/80 width, etc. + * + * @param sc driver softc + * @param txr node transmit rate + * @returns a rate_n_flags field, or 0xffffffff if error. + */ +static uint32_t +iwx_assemble_rate_n_flags(struct iwx_softc *sc, const struct ieee80211_node_txrate *txr) +{ + uint32_t rate_flags = 0; + int plcp; + + /* + * Do the rate lookup; if we can't find a plcp value to use then + * return an error. + */ + plcp = iwx_lookup_fw_plcp(sc, txr); + if (plcp < 0) + return (0xffffffff); + + /* Default to antenna A */ + rate_flags = IWX_RATE_MCS_ANT_A_MSK; + + /* Mask in the correct flags based on the rate type */ + switch (txr->type) { + case IEEE80211_NODE_TXRATE_LEGACY: + if (iwx_lookup_fw_legacy_plcp_is_cck(sc, plcp)) { + if (sc->sc_rate_n_flags_version >= 2) + rate_flags |= IWX_RATE_MCS_CCK_MSK; + else + rate_flags |= IWX_RATE_MCS_CCK_MSK_V1; + } else { + if (sc->sc_rate_n_flags_version >= 2) + rate_flags |= IWX_RATE_MCS_LEGACY_OFDM_MSK; + } + break; + + case IEEE80211_NODE_TXRATE_HT: + rate_flags |= IWX_RATE_MCS_HT_MSK; + if (plcp >= 8) + rate_flags |= IWX_RATE_MCS_ANT_AB_MSK; + break; + case IEEE80211_NODE_TXRATE_VHT: + rate_flags |= IWX_RATE_MCS_VHT_MSK; + if (txr->nss > 1) + rate_flags |= IWX_RATE_MCS_ANT_AB_MSK; + break; + default: + return (0xffffffff); + } + + /* Mask in the plcp and return */ + rate_flags |= plcp; + + return (rate_flags); +} + +#if 0 + rate_flags = IWX_RATE_MCS_ANT_A_MSK; + if (IWX_RIDX_IS_CCK(ridx)) { + if (sc->sc_rate_n_flags_version >= 2) + rate_flags |= IWX_RATE_MCS_CCK_MSK; + else + rate_flags |= IWX_RATE_MCS_CCK_MSK_V1; + } else if (sc->sc_rate_n_flags_version >= 2) + rate_flags |= IWX_RATE_MCS_LEGACY_OFDM_MSK; + + rval = (rs->rs_rates[ieee80211_node_get_txrate_dot11rate(ni)] + & IEEE80211_RATE_VAL); + IWX_DPRINTF(sc, IWX_DEBUG_TXRATE, "%s:%d: rval=%i dot11 %d\n", __func__, __LINE__, + rval, rs->rs_rates[ieee80211_node_get_txrate_dot11rate(ni)]); + + if (sc->sc_rate_n_flags_version >= 2) { + if (rate_flags & IWX_RATE_MCS_LEGACY_OFDM_MSK) { + rate_flags |= (iwx_fw_rateidx_ofdm(rval) & + IWX_RATE_LEGACY_RATE_MSK); + } else { + rate_flags |= (iwx_fw_rateidx_cck(rval) & + IWX_RATE_LEGACY_RATE_MSK); + } + } else + rate_flags |= rinfo->plcp; +#endif + +/* TODO: just net80211 has a call for this now */ inline int ieee80211_has_addr4(const struct ieee80211_frame *wh) { @@ -5505,6 +5696,8 @@ iwx_min_basic_rate(struct ieee80211com *ic) /* * Determine the Tx command flags and Tx rate+flags to use. * Return the selected Tx rate. + * + * If a rate can't be found, then NULL is returned. */ static const struct iwx_rate * iwx_tx_fill_cmd(struct iwx_softc *sc, struct iwx_node *in, @@ -5709,6 +5902,7 @@ iwx_tx(struct iwx_softc *sc, struct mbuf *m, struct ieee80211_node *ni) cmd->hdr.qid = ring->qid; cmd->hdr.idx = ring->cur; + /* Note: rinfo is currently only used for wtap rate, so it's easy to get rid of */ rinfo = iwx_tx_fill_cmd(sc, in, wh, &flags, &rate_n_flags, m); if (rinfo == NULL) return EINVAL; diff --git a/sys/net80211/ieee80211_ht.c b/sys/net80211/ieee80211_ht.c index a8a767785fce..3d3cdb8a4049 100644 --- a/sys/net80211/ieee80211_ht.c +++ b/sys/net80211/ieee80211_ht.c @@ -1130,6 +1130,8 @@ ieee80211_ampdu_reorder(struct ieee80211_node *ni, struct mbuf *m, */ if (rap->rxa_qframes != 0) { /* XXX honor batimeout? */ + + /* XXX time comparison macro? */ if (ticks - rap->rxa_age > ieee80211_ampdu_age) { /* * Too long since we received the first @@ -1392,6 +1394,7 @@ ieee80211_ht_node_age(struct ieee80211_node *ni) * See above for more details on what's happening here. */ /* XXX honor batimeout? */ + /* XXX time comparison macro? */ if (ticks - rap->rxa_age > ieee80211_ampdu_age) { /* * Too long since we received the first @@ -2819,7 +2822,8 @@ ieee80211_ampdu_request(struct ieee80211_node *ni, /* defer next try so we don't slam the driver with requests */ tap->txa_attempts = ieee80211_addba_maxtries; /* NB: check in case driver wants to override */ - if (tap->txa_nextrequest <= ticks) + /* XXX TODO: verify this is the correct ticks math */ + if (ieee80211_time_before_eq(tap->txa_nextrequest, ticks)) tap->txa_nextrequest = ticks + ieee80211_addba_backoff; return 0; }