/* * Fill in the rate array information based on the current * node configuration and the choices made by the rate * selection code and ath_buf setup code. * * Later on, this may end up also being made by the * rate control code, but for now it can live here. * * This needs to be called just before the packet is * queued to the software queue or hardware queue, * so all of the needed fields in bf_state are setup. */ void ath_tx_rate_fill_rcflags(struct ath_softc *sc, struct ath_buf *bf) { struct ieee80211_node *ni = bf->bf_node; struct ieee80211com *ic = ni->ni_ic; const HAL_RATE_TABLE *rt = sc->sc_currates; struct ath_rc_series *rc = bf->bf_state.bfs_rc; uint8_t rate; int i; for (i = 0; i < ATH_RC_NUM; i++) { rc[i].flags = 0; if (rc[i].tries == 0) continue; rate = rt->info[rc[i].rix].rateCode; /* * XXX only do this for legacy rates? */ if (bf->bf_state.bfs_shpream) rate |= rt->info[rc[i].rix].shortPreamble; /* * Save this, used by the TX and completion code */ rc[i].ratecode = rate; if (bf->bf_state.bfs_txflags & (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA)) rc[i].flags |= ATH_RC_RTSCTS_FLAG; /* Only enable shortgi, 2040, dual-stream if HT is set */ if (IS_HT_RATE(rate)) { rc[i].flags |= ATH_RC_HT_FLAG; if (ni->ni_chw == 40) rc[i].flags |= ATH_RC_CW40_FLAG; if (ni->ni_chw == 40 && ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40 && ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) rc[i].flags |= ATH_RC_SGI_FLAG; if (ni->ni_chw == 20 && ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20 && ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20) rc[i].flags |= ATH_RC_SGI_FLAG; /* XXX dual stream? and 3-stream? */ } /* * Calculate the maximum 4ms frame length based * on the MCS rate, SGI and channel width flags. */ if ((rc[i].flags & ATH_RC_HT_FLAG) && (HT_RC_2_MCS(rate) < 32)) { int j; if (rc[i].flags & ATH_RC_CW40_FLAG) { if (rc[i].flags & ATH_RC_SGI_FLAG) j = MCS_HT40_SGI; else j = MCS_HT40; } else { if (rc[i].flags & ATH_RC_SGI_FLAG) j = MCS_HT20_SGI; else j = MCS_HT20; } rc[i].max4msframelen = ath_max_4ms_framelen[j][HT_RC_2_MCS(rate)]; } else rc[i].max4msframelen = 0; DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, "%s: i=%d, rate=0x%x, flags=0x%x, max4ms=%d\n", __func__, i, rate, rc[i].flags, rc[i].max4msframelen); } }
/* * Return the number of delimiters to be added to * meet the minimum required mpdudensity. * * Caller should make sure that the rate is HT. * * TODO: is this delimiter calculation supposed to be the * total frame length, the hdr length, the data length (including * delimiters, padding, CRC, etc) or ? * * TODO: this should ensure that the rate control information * HAS been setup for the first rate. * * TODO: ensure this is only called for MCS rates. * * TODO: enforce MCS < 31 */ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_buf *first_bf, uint16_t pktlen) { const HAL_RATE_TABLE *rt = sc->sc_currates; struct ieee80211_node *ni = first_bf->bf_node; struct ieee80211vap *vap = ni->ni_vap; int ndelim, mindelim = 0; int mpdudensity; /* in 1/100'th of a microsecond */ uint8_t rc, rix, flags; int width, half_gi; uint32_t nsymbits, nsymbols; uint16_t minlen; /* * vap->iv_ampdu_density is a value, rather than the actual * density. */ if (vap->iv_ampdu_density > IEEE80211_HTCAP_MPDUDENSITY_16) mpdudensity = 1600; /* maximum density */ else mpdudensity = ieee80211_mpdudensity_map[vap->iv_ampdu_density]; /* Select standard number of delimiters based on frame length */ ndelim = ATH_AGGR_GET_NDELIM(pktlen); /* * If encryption is enabled, add extra delimiters to let the * crypto hardware catch up. This could be tuned per-MAC and * per-rate, but for now we'll simply assume encryption is * always enabled. */ ndelim += ATH_AGGR_ENCRYPTDELIM; DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, "%s: pktlen=%d, ndelim=%d, mpdudensity=%d\n", __func__, pktlen, ndelim, mpdudensity); /* * If the MPDU density is 0, we can return here. * Otherwise, we need to convert the desired mpdudensity * into a byte length, based on the rate in the subframe. */ if (mpdudensity == 0) return ndelim; /* * Convert desired mpdu density from microeconds to bytes based * on highest rate in rate series (i.e. first rate) to determine * required minimum length for subframe. Take into account * whether high rate is 20 or 40Mhz and half or full GI. */ rix = first_bf->bf_state.bfs_rc[0].rix; rc = rt->info[rix].rateCode; flags = first_bf->bf_state.bfs_rc[0].flags; width = !! (flags & ATH_RC_CW40_FLAG); half_gi = !! (flags & ATH_RC_SGI_FLAG); /* * mpdudensity is in 1/100th of a usec, so divide by 100 */ if (half_gi) nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(mpdudensity); else nsymbols = NUM_SYMBOLS_PER_USEC(mpdudensity); nsymbols /= 100; if (nsymbols == 0) nsymbols = 1; nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width]; minlen = (nsymbols * nsymbits) / BITS_PER_BYTE; /* * Min length is the minimum frame length for the * required MPDU density. */ if (pktlen < minlen) { mindelim = (minlen - pktlen) / ATH_AGGR_DELIM_SZ; ndelim = MAX(mindelim, ndelim); } DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, "%s: pktlen=%d, minlen=%d, rix=%x, rc=%x, width=%d, hgi=%d, ndelim=%d\n", __func__, pktlen, minlen, rix, rc, width, half_gi, ndelim); return ndelim; }
/* * Fill in the rate array information based on the current * node configuration and the choices made by the rate * selection code and ath_buf setup code. * * Later on, this may end up also being made by the * rate control code, but for now it can live here. * * This needs to be called just before the packet is * queued to the software queue or hardware queue, * so all of the needed fields in bf_state are setup. */ void ath_tx_rate_fill_rcflags(struct ath_softc *sc, struct ath_buf *bf) { struct ieee80211_node *ni = bf->bf_node; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; const HAL_RATE_TABLE *rt = sc->sc_currates; struct ath_rc_series *rc = bf->bf_state.bfs_rc; uint8_t rate; int i; int do_ldpc; int do_stbc; /* * We only do LDPC if the rate is 11n, both we and the * receiver support LDPC and it's enabled. * * It's a global flag, not a per-try flag, so we clear * it if any of the rate entries aren't 11n. */ do_ldpc = 0; if ((ni->ni_vap->iv_htcaps & IEEE80211_HTCAP_LDPC) && (ni->ni_htcap & IEEE80211_HTCAP_LDPC)) do_ldpc = 1; do_stbc = 0; for (i = 0; i < ATH_RC_NUM; i++) { rc[i].flags = 0; if (rc[i].tries == 0) continue; rate = rt->info[rc[i].rix].rateCode; /* * Only enable short preamble for legacy rates */ if ((! IS_HT_RATE(rate)) && bf->bf_state.bfs_shpream) rate |= rt->info[rc[i].rix].shortPreamble; /* * Save this, used by the TX and completion code */ rc[i].ratecode = rate; if (bf->bf_state.bfs_txflags & (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA)) rc[i].flags |= ATH_RC_RTSCTS_FLAG; /* * If we can't do LDPC, don't. */ if (! IS_HT_RATE(rate)) do_ldpc = 0; /* Only enable shortgi, 2040, dual-stream if HT is set */ if (IS_HT_RATE(rate)) { rc[i].flags |= ATH_RC_HT_FLAG; if (ni->ni_chw == 40) rc[i].flags |= ATH_RC_CW40_FLAG; if (ni->ni_chw == 40 && ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40 && ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40 && vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40) rc[i].flags |= ATH_RC_SGI_FLAG; if (ni->ni_chw == 20 && ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20 && ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20 && vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) rc[i].flags |= ATH_RC_SGI_FLAG; /* * If we have STBC TX enabled and the receiver * can receive (at least) 1 stream STBC, AND it's * MCS 0-7, AND we have at least two chains enabled, * enable STBC. * * XXX TODO: .. and the rate is an 11n rate? */ if (ic->ic_htcaps & IEEE80211_HTCAP_TXSTBC && ni->ni_vap->iv_flags_ht & IEEE80211_FHT_STBC_TX && ni->ni_htcap & IEEE80211_HTCAP_RXSTBC_1STREAM && (sc->sc_cur_txchainmask > 1) && HT_RC_2_STREAMS(rate) == 1) { rc[i].flags |= ATH_RC_STBC_FLAG; do_stbc = 1; } /* * Dual / Triple stream rate? */ if (HT_RC_2_STREAMS(rate) == 2) rc[i].flags |= ATH_RC_DS_FLAG; else if (HT_RC_2_STREAMS(rate) == 3) rc[i].flags |= ATH_RC_TS_FLAG; } /* * Calculate the maximum TX power cap for the current * node. */ rc[i].tx_power_cap = ieee80211_get_node_txpower(ni); /* * Calculate the maximum 4ms frame length based * on the MCS rate, SGI and channel width flags. */ if ((rc[i].flags & ATH_RC_HT_FLAG) && (HT_RC_2_MCS(rate) < 32)) { int j; if (rc[i].flags & ATH_RC_CW40_FLAG) { if (rc[i].flags & ATH_RC_SGI_FLAG) j = MCS_HT40_SGI; else j = MCS_HT40; } else { if (rc[i].flags & ATH_RC_SGI_FLAG) j = MCS_HT20_SGI; else j = MCS_HT20; } rc[i].max4msframelen = ath_max_4ms_framelen[j][HT_RC_2_MCS(rate)]; } else rc[i].max4msframelen = 0; DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, "%s: i=%d, rate=0x%x, flags=0x%x, max4ms=%d\n", __func__, i, rate, rc[i].flags, rc[i].max4msframelen); } /* * LDPC is a global flag, so ... */ if (do_ldpc) { bf->bf_state.bfs_txflags |= HAL_TXDESC_LDPC; sc->sc_stats.ast_tx_ldpc++; } if (do_stbc) { sc->sc_stats.ast_tx_stbc++; } }