/* * Initialize the tables for a node. */ static void ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni) { #define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) #define DOT11RATE(_ix) (rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL) #define MCS(_ix) (ni->ni_htrates.rs_rates[_ix] | IEEE80211_RATE_MCS) struct ath_node *an = ATH_NODE(ni); struct sample_node *sn = ATH_NODE_SAMPLE(an); const HAL_RATE_TABLE *rt = sc->sc_currates; int x, y, rix; KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); KASSERT(sc->sc_curmode < IEEE80211_MODE_MAX+2, ("curmode %u", sc->sc_curmode)); sn->sched = mrr_schedules[sc->sc_curmode]; KASSERT(sn->sched != NULL, ("no mrr schedule for mode %u", sc->sc_curmode)); sn->static_rix = -1; ath_rate_update_static_rix(sc, ni); /* * Construct a bitmask of usable rates. This has all * negotiated rates minus those marked by the hal as * to be ignored for doing rate control. */ sn->ratemask = 0; /* MCS rates */ if (ni->ni_flags & IEEE80211_NODE_HT) { for (x = 0; x < ni->ni_htrates.rs_nrates; x++) { rix = sc->sc_rixmap[MCS(x)]; if (rix == 0xff) continue; /* skip rates marked broken by hal */ if (!rt->info[rix].valid) continue; KASSERT(rix < SAMPLE_MAXRATES, ("mcs %u has rix %d", MCS(x), rix)); sn->ratemask |= 1<<rix; } } /* Legacy rates */ for (x = 0; x < ni->ni_rates.rs_nrates; x++) { rix = sc->sc_rixmap[RATE(x)]; if (rix == 0xff) continue; /* skip rates marked broken by hal */ if (!rt->info[rix].valid) continue; KASSERT(rix < SAMPLE_MAXRATES, ("rate %u has rix %d", RATE(x), rix)); sn->ratemask |= 1<<rix; } #ifdef IEEE80211_DEBUG if (ieee80211_msg(ni->ni_vap, IEEE80211_MSG_RATECTL)) { uint32_t mask; ieee80211_note(ni->ni_vap, "[%6D] %s: size 1600 rate/tt", ni->ni_macaddr, ":", __func__); for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { if ((mask & 1) == 0) continue; printf(" %d %s/%d", dot11rate(rt, rix), dot11rate_label(rt, rix), calc_usecs_unicast_packet(sc, 1600, rix, 0,0, (ni->ni_chw == 40))); } printf("\n"); }
static void update_stats(struct ath_softc *sc, struct ath_node *an, int frame_size, int rix0, int tries0, int rix1, int tries1, int rix2, int tries2, int rix3, int tries3, int short_tries, int tries, int status, int nframes, int nbad) { struct sample_node *sn = ATH_NODE_SAMPLE(an); struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc); #ifdef IEEE80211_DEBUG const HAL_RATE_TABLE *rt = sc->sc_currates; #endif const int size_bin = size_to_bin(frame_size); const int size = bin_to_size(size_bin); int tt, tries_so_far; int is_ht40 = (an->an_node.ni_chw == 40); if (!IS_RATE_DEFINED(sn, rix0)) return; tt = calc_usecs_unicast_packet(sc, size, rix0, short_tries, MIN(tries0, tries) - 1, is_ht40); tries_so_far = tries0; if (tries1 && tries_so_far < tries) { if (!IS_RATE_DEFINED(sn, rix1)) return; tt += calc_usecs_unicast_packet(sc, size, rix1, short_tries, MIN(tries1 + tries_so_far, tries) - tries_so_far - 1, is_ht40); tries_so_far += tries1; } if (tries2 && tries_so_far < tries) { if (!IS_RATE_DEFINED(sn, rix2)) return; tt += calc_usecs_unicast_packet(sc, size, rix2, short_tries, MIN(tries2 + tries_so_far, tries) - tries_so_far - 1, is_ht40); tries_so_far += tries2; } if (tries3 && tries_so_far < tries) { if (!IS_RATE_DEFINED(sn, rix3)) return; tt += calc_usecs_unicast_packet(sc, size, rix3, short_tries, MIN(tries3 + tries_so_far, tries) - tries_so_far - 1, is_ht40); } if (sn->stats[size_bin][rix0].total_packets < ssc->smoothing_minpackets) { /* just average the first few packets */ int avg_tx = sn->stats[size_bin][rix0].average_tx_time; int packets = sn->stats[size_bin][rix0].total_packets; sn->stats[size_bin][rix0].average_tx_time = (tt+(avg_tx*packets))/(packets+nframes); } else { /* use a ewma */ sn->stats[size_bin][rix0].average_tx_time = ((sn->stats[size_bin][rix0].average_tx_time * ssc->smoothing_rate) + (tt * (100 - ssc->smoothing_rate))) / 100; } /* * XXX Don't mark the higher bit rates as also having failed; as this * unfortunately stops those rates from being tasted when trying to * TX. This happens with 11n aggregation. */ if (nframes == nbad) { #if 0 int y; #endif sn->stats[size_bin][rix0].successive_failures += nbad; #if 0 for (y = size_bin+1; y < NUM_PACKET_SIZE_BINS; y++) { /* * Also say larger packets failed since we * assume if a small packet fails at a * bit-rate then a larger one will also. */ sn->stats[y][rix0].successive_failures += nbad; sn->stats[y][rix0].last_tx = ticks; sn->stats[y][rix0].tries += tries; sn->stats[y][rix0].total_packets += nframes; } #endif } else { sn->stats[size_bin][rix0].packets_acked += (nframes - nbad); sn->stats[size_bin][rix0].successive_failures = 0; } sn->stats[size_bin][rix0].tries += tries; sn->stats[size_bin][rix0].last_tx = ticks; sn->stats[size_bin][rix0].total_packets += nframes; if (rix0 == sn->current_sample_rix[size_bin]) { IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, &an->an_node, "%s: size %d %s sample rate %d %s tries (%d/%d) tt %d avg_tt (%d/%d) nfrm %d nbad %d", __func__, size, status ? "FAIL" : "OK", dot11rate(rt, rix0), dot11rate_label(rt, rix0), short_tries, tries, tt, sn->stats[size_bin][rix0].average_tx_time, sn->stats[size_bin][rix0].perfect_tx_time, nframes, nbad); sn->sample_tt[size_bin] = tt; sn->current_sample_rix[size_bin] = -1; } }
/* * Initialize the tables for a node. */ static void ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni) { #define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) #define DOT11RATE(_ix) (rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL) struct ath_node *an = ATH_NODE(ni); const struct ieee80211_txparam *tp = ni->ni_txparms; struct sample_node *sn = ATH_NODE_SAMPLE(an); const HAL_RATE_TABLE *rt = sc->sc_currates; #ifdef IEEE80211_DEBUG char ethstr[ETHER_ADDRSTRLEN + 1]; #endif int x, y, srate, rix; KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); KASSERT(sc->sc_curmode < IEEE80211_MODE_MAX+2, ("curmode %u", sc->sc_curmode)); sn->sched = mrr_schedules[sc->sc_curmode]; KASSERT(sn->sched != NULL, ("no mrr schedule for mode %u", sc->sc_curmode)); sn->static_rix = -1; if (tp != NULL && tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { /* * A fixed rate is to be used; ucastrate is the IEEE code * for this rate (sans basic bit). Check this against the * negotiated rate set for the node. Note the fixed rate * may not be available for various reasons so we only * setup the static rate index if the lookup is successful. * XXX handle MCS */ for (srate = ni->ni_rates.rs_nrates - 1; srate >= 0; srate--) if (RATE(srate) == tp->ucastrate) { sn->static_rix = sc->sc_rixmap[tp->ucastrate]; break; } #ifdef IEEE80211_DEBUG if (sn->static_rix == -1) { IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, "%s: ucastrate %u not found, nrates %u", __func__, tp->ucastrate, ni->ni_rates.rs_nrates); } #endif } /* * Construct a bitmask of usable rates. This has all * negotiated rates minus those marked by the hal as * to be ignored for doing rate control. */ sn->ratemask = 0; for (x = 0; x < ni->ni_rates.rs_nrates; x++) { rix = sc->sc_rixmap[RATE(x)]; if (rix == 0xff) continue; /* skip rates marked broken by hal */ if (!rt->info[rix].valid) continue; KASSERT(rix < SAMPLE_MAXRATES, ("rate %u has rix %d", RATE(x), rix)); sn->ratemask |= 1<<rix; } #ifdef IEEE80211_DEBUG if (ieee80211_msg(ni->ni_vap, IEEE80211_MSG_RATECTL)) { uint32_t mask; ieee80211_note(ni->ni_vap, "[%s] %s: size 1600 rate/tt", kether_ntoa(ni->ni_macaddr, ethstr), __func__); for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { if ((mask & 1) == 0) continue; kprintf(" %d/%d", DOT11RATE(rix) / 2, calc_usecs_unicast_packet(sc, 1600, rix, 0,0)); } kprintf("\n"); }
static void update_stats(struct ath_softc *sc, struct ath_node *an, int frame_size, int rix0, int tries0, int rix1, int tries1, int rix2, int tries2, int rix3, int tries3, int short_tries, int tries, int status) { struct sample_node *sn = ATH_NODE_SAMPLE(an); struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc); const int size_bin = size_to_bin(frame_size); const int size = bin_to_size(size_bin); int tt, tries_so_far; if (!IS_RATE_DEFINED(sn, rix0)) return; tt = calc_usecs_unicast_packet(sc, size, rix0, short_tries, MIN(tries0, tries) - 1); tries_so_far = tries0; if (tries1 && tries_so_far < tries) { if (!IS_RATE_DEFINED(sn, rix1)) return; tt += calc_usecs_unicast_packet(sc, size, rix1, short_tries, MIN(tries1 + tries_so_far, tries) - tries_so_far - 1); tries_so_far += tries1; } if (tries2 && tries_so_far < tries) { if (!IS_RATE_DEFINED(sn, rix2)) return; tt += calc_usecs_unicast_packet(sc, size, rix2, short_tries, MIN(tries2 + tries_so_far, tries) - tries_so_far - 1); tries_so_far += tries2; } if (tries3 && tries_so_far < tries) { if (!IS_RATE_DEFINED(sn, rix3)) return; tt += calc_usecs_unicast_packet(sc, size, rix3, short_tries, MIN(tries3 + tries_so_far, tries) - tries_so_far - 1); } if (sn->stats[size_bin][rix0].total_packets < ssc->smoothing_minpackets) { /* just average the first few packets */ int avg_tx = sn->stats[size_bin][rix0].average_tx_time; int packets = sn->stats[size_bin][rix0].total_packets; sn->stats[size_bin][rix0].average_tx_time = (tt+(avg_tx*packets))/(packets+1); } else { /* use a ewma */ sn->stats[size_bin][rix0].average_tx_time = ((sn->stats[size_bin][rix0].average_tx_time * ssc->smoothing_rate) + (tt * (100 - ssc->smoothing_rate))) / 100; } if (status != 0) { int y; sn->stats[size_bin][rix0].successive_failures++; for (y = size_bin+1; y < NUM_PACKET_SIZE_BINS; y++) { /* * Also say larger packets failed since we * assume if a small packet fails at a * bit-rate then a larger one will also. */ sn->stats[y][rix0].successive_failures++; sn->stats[y][rix0].last_tx = ticks; sn->stats[y][rix0].tries += tries; sn->stats[y][rix0].total_packets++; } } else { sn->stats[size_bin][rix0].packets_acked++; sn->stats[size_bin][rix0].successive_failures = 0; } sn->stats[size_bin][rix0].tries += tries; sn->stats[size_bin][rix0].last_tx = ticks; sn->stats[size_bin][rix0].total_packets++; if (rix0 == sn->current_sample_rix[size_bin]) { IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, &an->an_node, "%s: size %d %s sample rate %d tries (%d/%d) tt %d avg_tt (%d/%d)", __func__, size, status ? "FAIL" : "OK", rix0, short_tries, tries, tt, sn->stats[size_bin][rix0].average_tx_time, sn->stats[size_bin][rix0].perfect_tx_time); sn->sample_tt[size_bin] = tt; sn->current_sample_rix[size_bin] = -1; } }
/* * Initialize the tables for a node. */ static void ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni) { #define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) struct ieee80211com *ic = &sc->sc_ic; struct ath_node *an = ATH_NODE(ni); struct sample_node *sn = ATH_NODE_SAMPLE(an); const HAL_RATE_TABLE *rt = sc->sc_currates; int x, y, srate; KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); sn->static_rate_ndx = -1; if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) { /* * A fixed rate is to be used; ic_fixed_rate is the * IEEE code for this rate (sans basic bit). Convert this * to the index into the negotiated rate set for * the node. */ /* NB: the rate set is assumed sorted */ srate = ni->ni_rates.rs_nrates - 1; for (; srate >= 0 && RATE(srate) != ic->ic_fixed_rate; srate--) ; /* * The fixed rate may not be available due to races * and mode settings. Also orphaned nodes created in * adhoc mode may not have any rate set so this lookup * can fail. */ if (srate >= 0) sn->static_rate_ndx = srate; } DPRINTF(sc, ATH_DEBUG_RATE, "%s: %s size 1600 rate/tt", __func__, ether_sprintf(ni->ni_macaddr)); sn->num_rates = ni->ni_rates.rs_nrates; for (x = 0; x < ni->ni_rates.rs_nrates; x++) { sn->rates[x].rate = ni->ni_rates.rs_rates[x] & IEEE80211_RATE_VAL; sn->rates[x].rix = sc->sc_rixmap[sn->rates[x].rate]; if (sn->rates[x].rix == 0xff) { DPRINTF(sc, ATH_DEBUG_RATE, "%s: ignore bogus rix at %d\n", __func__, x); continue; } sn->rates[x].rateCode = rt->info[sn->rates[x].rix].rateCode; sn->rates[x].shortPreambleRateCode = rt->info[sn->rates[x].rix].rateCode | rt->info[sn->rates[x].rix].shortPreamble; DPRINTF(sc, ATH_DEBUG_RATE, " %d/%d", sn->rates[x].rate, calc_usecs_unicast_packet(sc, 1600, sn->rates[x].rix, 0,0)); } DPRINTF(sc, ATH_DEBUG_RATE, "%s\n", ""); /* set the visible bit-rate to the lowest one available */ ni->ni_txrate = 0; sn->num_rates = ni->ni_rates.rs_nrates; for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { int size = bin_to_size(y); int ndx = 0; sn->packets_sent[y] = 0; sn->current_sample_ndx[y] = -1; sn->last_sample_ndx[y] = 0; for (x = 0; x < ni->ni_rates.rs_nrates; x++) { sn->stats[y][x].successive_failures = 0; sn->stats[y][x].tries = 0; sn->stats[y][x].total_packets = 0; sn->stats[y][x].packets_acked = 0; sn->stats[y][x].last_tx = 0; sn->stats[y][x].perfect_tx_time = calc_usecs_unicast_packet(sc, size, sn->rates[x].rix, 0, 0); sn->stats[y][x].average_tx_time = sn->stats[y][x].perfect_tx_time; } /* set the initial rate */ for (ndx = sn->num_rates-1; ndx > 0; ndx--) { if (sn->rates[ndx].rate <= 72) { break; } } sn->current_rate[y] = ndx; } DPRINTF(sc, ATH_DEBUG_RATE, "%s: %s %d rates %d%sMbps (%dus)- %d%sMbps (%dus)\n", __func__, ether_sprintf(ni->ni_macaddr), sn->num_rates, sn->rates[0].rate/2, sn->rates[0].rate % 0x1 ? ".5" : "", sn->stats[1][0].perfect_tx_time, sn->rates[sn->num_rates-1].rate/2, sn->rates[sn->num_rates-1].rate % 0x1 ? ".5" : "", sn->stats[1][sn->num_rates-1].perfect_tx_time ); if (sn->static_rate_ndx != -1) ni->ni_txrate = sn->static_rate_ndx; else ni->ni_txrate = sn->current_rate[0]; #undef RATE }
static void update_stats(struct ath_softc *sc, struct ath_node *an, int frame_size, int ndx0, int tries0, int ndx1, int tries1, int ndx2, int tries2, int ndx3, int tries3, int short_tries, int tries, int status) { struct sample_node *sn = ATH_NODE_SAMPLE(an); struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc); int tt = 0; int tries_so_far = 0; int size_bin = 0; int size = 0; int rate = 0; size_bin = size_to_bin(frame_size); size = bin_to_size(size_bin); if (!(0 <= ndx0 && ndx0 < sn->num_rates)) { printf("%s: bogus ndx0 %d, max %u, mode %u\n", __func__, ndx0, sn->num_rates, sc->sc_curmode); return; } rate = sn->rates[ndx0].rate; tt += calc_usecs_unicast_packet(sc, size, sn->rates[ndx0].rix, short_tries, MIN(tries0, tries) - 1); tries_so_far += tries0; if (tries1 && tries0 < tries) { if (!(0 <= ndx1 && ndx1 < sn->num_rates)) { printf("%s: bogus ndx1 %d, max %u, mode %u\n", __func__, ndx1, sn->num_rates, sc->sc_curmode); return; } tt += calc_usecs_unicast_packet(sc, size, sn->rates[ndx1].rix, short_tries, MIN(tries1 + tries_so_far, tries) - tries_so_far - 1); } tries_so_far += tries1; if (tries2 && tries0 + tries1 < tries) { if (!(0 <= ndx2 && ndx2 < sn->num_rates)) { printf("%s: bogus ndx2 %d, max %u, mode %u\n", __func__, ndx2, sn->num_rates, sc->sc_curmode); return; } tt += calc_usecs_unicast_packet(sc, size, sn->rates[ndx2].rix, short_tries, MIN(tries2 + tries_so_far, tries) - tries_so_far - 1); } tries_so_far += tries2; if (tries3 && tries0 + tries1 + tries2 < tries) { if (!(0 <= ndx3 && ndx3 < sn->num_rates)) { printf("%s: bogus ndx3 %d, max %u, mode %u\n", __func__, ndx3, sn->num_rates, sc->sc_curmode); return; } tt += calc_usecs_unicast_packet(sc, size, sn->rates[ndx3].rix, short_tries, MIN(tries3 + tries_so_far, tries) - tries_so_far - 1); } if (sn->stats[size_bin][ndx0].total_packets < (100 / (100 - ssc->ath_smoothing_rate))) { /* just average the first few packets */ int avg_tx = sn->stats[size_bin][ndx0].average_tx_time; int packets = sn->stats[size_bin][ndx0].total_packets; sn->stats[size_bin][ndx0].average_tx_time = (tt+(avg_tx*packets))/(packets+1); } else { /* use a ewma */ sn->stats[size_bin][ndx0].average_tx_time = ((sn->stats[size_bin][ndx0].average_tx_time * ssc->ath_smoothing_rate) + (tt * (100 - ssc->ath_smoothing_rate))) / 100; } if (status) { int y; sn->stats[size_bin][ndx0].successive_failures++; for (y = size_bin+1; y < NUM_PACKET_SIZE_BINS; y++) { /* also say larger packets failed since we * assume if a small packet fails at a lower * bit-rate then a larger one will also. */ sn->stats[y][ndx0].successive_failures++; sn->stats[y][ndx0].last_tx = ticks; sn->stats[y][ndx0].tries += tries; sn->stats[y][ndx0].total_packets++; } } else { sn->stats[size_bin][ndx0].packets_acked++; sn->stats[size_bin][ndx0].successive_failures = 0; } sn->stats[size_bin][ndx0].tries += tries; sn->stats[size_bin][ndx0].last_tx = ticks; sn->stats[size_bin][ndx0].total_packets++; if (ndx0 == sn->current_sample_ndx[size_bin]) { DPRINTF(sc, ATH_DEBUG_RATE, "%s: %s size %d %s sample rate %d tries (%d/%d) tt %d avg_tt (%d/%d)\n", __func__, ether_sprintf(an->an_node.ni_macaddr), size, status ? "FAIL" : "OK", rate, short_tries, tries, tt, sn->stats[size_bin][ndx0].average_tx_time, sn->stats[size_bin][ndx0].perfect_tx_time); sn->sample_tt[size_bin] = tt; sn->current_sample_ndx[size_bin] = -1; } }
/* * Initialize the tables for a node. */ static void ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni) { #define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) struct ieee80211com *ic = &sc->sc_ic; struct ath_node *an = ATH_NODE(ni); struct sample_node *sn = ATH_NODE_SAMPLE(an); const HAL_RATE_TABLE *rt = sc->sc_currates; int x, y, srate; KASSERTMSG(rt != NULL, "no rate table, mode %u", sc->sc_curmode); sn->static_rate_ndx = -1; if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) { /* * A fixed rate is to be used; ic_fixed_rate is an * index into the supported rate set. Convert this * to the index into the negotiated rate set for * the node. We know the rate is there because the * rate set is checked when the station associates. */ const struct ieee80211_rateset *rs = &ic->ic_sup_rates[ic->ic_curmode]; int r = rs->rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL; /* NB: the rate set is assumed sorted */ srate = ni->ni_rates.rs_nrates - 1; for (; srate >= 0 && RATE(srate) != r; srate--) ; KASSERTMSG(srate >= 0, "fixed rate %d not in rate set", ic->ic_fixed_rate); sn->static_rate_ndx = srate; } DPRINTF(sc, "%s: %s size 1600 rate/tt", __func__, ether_sprintf(ni->ni_macaddr)); sn->num_rates = ni->ni_rates.rs_nrates; for (x = 0; x < ni->ni_rates.rs_nrates; x++) { sn->rates[x].rate = ni->ni_rates.rs_rates[x] & IEEE80211_RATE_VAL; sn->rates[x].rix = sc->sc_rixmap[sn->rates[x].rate]; sn->rates[x].rateCode = rt->info[sn->rates[x].rix].rateCode; sn->rates[x].shortPreambleRateCode = rt->info[sn->rates[x].rix].rateCode | rt->info[sn->rates[x].rix].shortPreamble; DPRINTF(sc, " %d/%d", sn->rates[x].rate, calc_usecs_unicast_packet(sc, 1600, sn->rates[x].rix, 0,0)); } DPRINTF(sc, "%s\n", ""); /* set the visible bit-rate to the lowest one available */ ni->ni_txrate = 0; sn->num_rates = ni->ni_rates.rs_nrates; for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { int size = bin_to_size(y); int ndx = 0; sn->packets_sent[y] = 0; sn->current_sample_ndx[y] = -1; sn->last_sample_ndx[y] = 0; for (x = 0; x < ni->ni_rates.rs_nrates; x++) { sn->stats[y][x].successive_failures = 0; sn->stats[y][x].tries = 0; sn->stats[y][x].total_packets = 0; sn->stats[y][x].packets_acked = 0; sn->stats[y][x].last_tx = 0; sn->stats[y][x].perfect_tx_time = calc_usecs_unicast_packet(sc, size, sn->rates[x].rix, 0, 0); sn->stats[y][x].average_tx_time = sn->stats[y][x].perfect_tx_time; } /* set the initial rate */ for (ndx = sn->num_rates-1; ndx > 0; ndx--) { if (sn->rates[ndx].rate <= 72) { break; } } sn->current_rate[y] = ndx; } DPRINTF(sc, "%s: %s %d rates %d%sMbps (%dus)- %d%sMbps (%dus)\n", __func__, ether_sprintf(ni->ni_macaddr), sn->num_rates, sn->rates[0].rate/2, sn->rates[0].rate % 0x1 ? ".5" : "", sn->stats[1][0].perfect_tx_time, sn->rates[sn->num_rates-1].rate/2, sn->rates[sn->num_rates-1].rate % 0x1 ? ".5" : "", sn->stats[1][sn->num_rates-1].perfect_tx_time ); ni->ni_txrate = sn->current_rate[0]; #undef RATE }