void ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an, const struct ath_rc_series *rc, const struct ath_tx_status *ts, int frame_size, int nframes, int nbad) { struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct sample_node *sn = ATH_NODE_SAMPLE(an); int final_rix, short_tries, long_tries; const HAL_RATE_TABLE *rt = sc->sc_currates; int status = ts->ts_status; int mrr; final_rix = rt->rateCodeToIndex[ts->ts_rate]; short_tries = ts->ts_shortretry; long_tries = ts->ts_longretry + 1; if (frame_size == 0) /* NB: should not happen */ frame_size = 1500; if (sn->ratemask == 0) { IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, &an->an_node, "%s: size %d %s rate/try %d/%d no rates yet", __func__, bin_to_size(size_to_bin(frame_size)), status ? "FAIL" : "OK", short_tries, long_tries); return; } mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT); if (!mrr || ts->ts_finaltsi == 0) { if (!IS_RATE_DEFINED(sn, final_rix)) { badrate(ifp, 0, ts->ts_rate, long_tries, status); return; } /* * Only one rate was used; optimize work. */ IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, &an->an_node, "%s: size %d (%d bytes) %s rate/try %d %s/%d/%d nframes/nbad [%d/%d]", __func__, bin_to_size(size_to_bin(frame_size)), frame_size, status ? "FAIL" : "OK", dot11rate(rt, final_rix), dot11rate_label(rt, final_rix), short_tries, long_tries, nframes, nbad); update_stats(sc, an, frame_size, final_rix, long_tries, 0, 0, 0, 0, 0, 0, short_tries, long_tries, status, nframes, nbad); update_ewma_stats(sc, an, frame_size, final_rix, long_tries, 0, 0, 0, 0, 0, 0, short_tries, long_tries, status, nframes, nbad); } else { int finalTSIdx = ts->ts_finaltsi; int i; /* * Process intermediate rates that failed. */ IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, &an->an_node, "%s: size %d (%d bytes) finaltsidx %d tries %d %s rate/try [%d %s/%d %d %s/%d %d %s/%d %d %s/%d] nframes/nbad [%d/%d]", __func__, bin_to_size(size_to_bin(frame_size)), frame_size, finalTSIdx, long_tries, status ? "FAIL" : "OK", dot11rate(rt, rc[0].rix), dot11rate_label(rt, rc[0].rix), rc[0].tries, dot11rate(rt, rc[1].rix), dot11rate_label(rt, rc[1].rix), rc[1].tries, dot11rate(rt, rc[2].rix), dot11rate_label(rt, rc[2].rix), rc[2].tries, dot11rate(rt, rc[3].rix), dot11rate_label(rt, rc[3].rix), rc[3].tries, nframes, nbad); for (i = 0; i < 4; i++) { if (rc[i].tries && !IS_RATE_DEFINED(sn, rc[i].rix)) badrate(ifp, 0, rc[i].ratecode, rc[i].tries, status); } /* * NB: series > 0 are not penalized for failure * based on the try counts under the assumption * that losses are often bursty and since we * sample higher rates 1 try at a time doing so * may unfairly penalize them. */ if (rc[0].tries) { update_stats(sc, an, frame_size, rc[0].rix, rc[0].tries, rc[1].rix, rc[1].tries, rc[2].rix, rc[2].tries, rc[3].rix, rc[3].tries, short_tries, long_tries, long_tries > rc[0].tries, nframes, nbad); long_tries -= rc[0].tries; } if (rc[1].tries && finalTSIdx > 0) { update_stats(sc, an, frame_size, rc[1].rix, rc[1].tries, rc[2].rix, rc[2].tries, rc[3].rix, rc[3].tries, 0, 0, short_tries, long_tries, status, nframes, nbad); long_tries -= rc[1].tries; } if (rc[2].tries && finalTSIdx > 1) { update_stats(sc, an, frame_size, rc[2].rix, rc[2].tries, rc[3].rix, rc[3].tries, 0, 0, 0, 0, short_tries, long_tries, status, nframes, nbad); long_tries -= rc[2].tries; } if (rc[3].tries && finalTSIdx > 2) { update_stats(sc, an, frame_size, rc[3].rix, rc[3].tries, 0, 0, 0, 0, 0, 0, short_tries, long_tries, status, nframes, nbad); } update_ewma_stats(sc, an, frame_size, rc[0].rix, rc[0].tries, rc[1].rix, rc[1].tries, rc[2].rix, rc[2].tries, rc[3].rix, rc[3].tries, short_tries, long_tries, long_tries > rc[0].tries, nframes, nbad); } }
void ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an, const struct ath_buf *bf) { struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct sample_node *sn = ATH_NODE_SAMPLE(an); const struct ath_tx_status *ts = &bf->bf_status.ds_txstat; const struct ath_desc *ds0 = &bf->bf_desc[0]; int final_rix, short_tries, long_tries, frame_size; const HAL_RATE_TABLE *rt = sc->sc_currates; int mrr; final_rix = rt->rateCodeToIndex[ts->ts_rate]; short_tries = ts->ts_shortretry; long_tries = ts->ts_longretry + 1; frame_size = ds0->ds_ctl0 & 0x0fff; /* low-order 12 bits of ds_ctl0 */ if (frame_size == 0) /* NB: should not happen */ frame_size = 1500; if (sn->ratemask == 0) { IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, &an->an_node, "%s: size %d %s rate/try %d/%d no rates yet", __func__, bin_to_size(size_to_bin(frame_size)), ts->ts_status ? "FAIL" : "OK", short_tries, long_tries); return; } mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT); if (!mrr || ts->ts_finaltsi == 0) { if (!IS_RATE_DEFINED(sn, final_rix)) { badrate(ifp, 0, ts->ts_rate, long_tries, ts->ts_status); return; } /* * Only one rate was used; optimize work. */ IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, &an->an_node, "%s: size %d %s rate/try %d/%d/%d", __func__, bin_to_size(size_to_bin(frame_size)), ts->ts_status ? "FAIL" : "OK", final_rix, short_tries, long_tries); update_stats(sc, an, frame_size, final_rix, long_tries, 0, 0, 0, 0, 0, 0, short_tries, long_tries, ts->ts_status); } else { int hwrate0, rix0, tries0; int hwrate1, rix1, tries1; int hwrate2, rix2, tries2; int hwrate3, rix3, tries3; int finalTSIdx = ts->ts_finaltsi; /* * Process intermediate rates that failed. */ if (sc->sc_ah->ah_magic != 0x20065416) { hwrate0 = MS(ds0->ds_ctl3, AR_XmitRate0); hwrate1 = MS(ds0->ds_ctl3, AR_XmitRate1); hwrate2 = MS(ds0->ds_ctl3, AR_XmitRate2); hwrate3 = MS(ds0->ds_ctl3, AR_XmitRate3); } else { hwrate0 = MS(ds0->ds_ctl3, AR5416_XmitRate0); hwrate1 = MS(ds0->ds_ctl3, AR5416_XmitRate1); hwrate2 = MS(ds0->ds_ctl3, AR5416_XmitRate2); hwrate3 = MS(ds0->ds_ctl3, AR5416_XmitRate3); } rix0 = rt->rateCodeToIndex[hwrate0]; tries0 = MS(ds0->ds_ctl2, AR_XmitDataTries0); rix1 = rt->rateCodeToIndex[hwrate1]; tries1 = MS(ds0->ds_ctl2, AR_XmitDataTries1); rix2 = rt->rateCodeToIndex[hwrate2]; tries2 = MS(ds0->ds_ctl2, AR_XmitDataTries2); rix3 = rt->rateCodeToIndex[hwrate3]; tries3 = MS(ds0->ds_ctl2, AR_XmitDataTries3); IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL, &an->an_node, "%s: size %d finaltsidx %d tries %d %s rate/try [%d/%d %d/%d %d/%d %d/%d]", __func__, bin_to_size(size_to_bin(frame_size)), finalTSIdx, long_tries, ts->ts_status ? "FAIL" : "OK", rix0, tries0, rix1, tries1, rix2, tries2, rix3, tries3); if (tries0 && !IS_RATE_DEFINED(sn, rix0)) badrate(ifp, 0, hwrate0, tries0, ts->ts_status); if (tries1 && !IS_RATE_DEFINED(sn, rix1)) badrate(ifp, 1, hwrate1, tries1, ts->ts_status); if (tries2 && !IS_RATE_DEFINED(sn, rix2)) badrate(ifp, 2, hwrate2, tries2, ts->ts_status); if (tries3 && !IS_RATE_DEFINED(sn, rix3)) badrate(ifp, 3, hwrate3, tries3, ts->ts_status); /* * NB: series > 0 are not penalized for failure * based on the try counts under the assumption * that losses are often bursty and since we * sample higher rates 1 try at a time doing so * may unfairly penalize them. */ if (tries0) { update_stats(sc, an, frame_size, rix0, tries0, rix1, tries1, rix2, tries2, rix3, tries3, short_tries, long_tries, long_tries > tries0); long_tries -= tries0; } if (tries1 && finalTSIdx > 0) { update_stats(sc, an, frame_size, rix1, tries1, rix2, tries2, rix3, tries3, 0, 0, short_tries, long_tries, ts->ts_status); long_tries -= tries1; } if (tries2 && finalTSIdx > 1) { update_stats(sc, an, frame_size, rix2, tries2, rix3, tries3, 0, 0, 0, 0, short_tries, long_tries, ts->ts_status); long_tries -= tries2; } if (tries3 && finalTSIdx > 2) { update_stats(sc, an, frame_size, rix3, tries3, 0, 0, 0, 0, 0, 0, short_tries, long_tries, ts->ts_status); } } }
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; } }
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; } }