/* * Clear any frames queued on a node's power save queue. * The number of frames that were present is returned. */ int ath_node_pwrsaveq_drain(ath_node_t node) { struct ath_node *an = ATH_NODE(node); int qlen; struct ath_node_pwrsaveq *dataq,*mgtq; ath_wbuf_t athwbuf; dataq = ATH_NODE_PWRSAVEQ_DATAQ(an); mgtq = ATH_NODE_PWRSAVEQ_MGMTQ(an); qlen = ATH_NODE_PWRSAVEQ_QLEN(dataq); qlen += ATH_NODE_PWRSAVEQ_QLEN(mgtq); /* * free all the frames. */ ATH_NODE_PWRSAVEQ_LOCK(dataq); ATH_NODE_PWRSAVEQ_DEQUEUE(dataq, athwbuf); while(athwbuf) { ath_node_pwrsaveq_complete_athwbuf(an, athwbuf); ATH_NODE_PWRSAVEQ_DEQUEUE(dataq, athwbuf); } ATH_NODE_PWRSAVEQ_UNLOCK(dataq); ATH_NODE_PWRSAVEQ_LOCK(mgtq); ATH_NODE_PWRSAVEQ_DEQUEUE(mgtq, athwbuf); while(athwbuf) { ath_node_pwrsaveq_complete_athwbuf(an, athwbuf); ATH_NODE_PWRSAVEQ_DEQUEUE(mgtq, athwbuf); } ATH_NODE_PWRSAVEQ_UNLOCK(mgtq); return qlen; }
static void rate_cb(void *arg, struct ieee80211_node *ni) { struct ath_softc *sc = arg; ath_rate_newassoc(sc, ATH_NODE(ni), 1); }
/* * Age frames on the power save queue. The aging interval is * 4 times the listen interval specified by the station. This * number is factored into the age calculations when the frame * is placed on the queue. We store ages as time differences * so we can check and/or adjust only the head of the list. * If a frame's age exceeds the threshold then discard it. * The number of frames discarded is returned so the caller * can check if it needs to adjust the tim. */ int ath_node_pwrsaveq_age(ath_node_t node) { struct ath_node *an = ATH_NODE(node); struct ath_softc *sc = an->an_sc; int discard = 0; struct ath_node_pwrsaveq *dataq,*mgtq; dataq = ATH_NODE_PWRSAVEQ_DATAQ(an); mgtq = ATH_NODE_PWRSAVEQ_MGMTQ(an); if ((ATH_NODE_PWRSAVEQ_QLEN(dataq) != 0) || (ATH_NODE_PWRSAVEQ_QLEN(mgtq) != 0)) { ath_wbuf_t athwbuf; for (;;) { ATH_NODE_PWRSAVEQ_LOCK(dataq); ATH_NODE_PWRSAVEQ_POLL(dataq, athwbuf); if((athwbuf == NULL) || (wbuf_get_age(athwbuf->wbuf) >= ATH_NODE_INACT_WAIT)) { if (athwbuf != NULL) wbuf_set_age(athwbuf->wbuf, wbuf_get_age(athwbuf->wbuf) - ATH_NODE_INACT_WAIT); ATH_NODE_PWRSAVEQ_UNLOCK(dataq); break; } DPRINTF(sc, ATH_DEBUG_PWR_SAVE, "discard data frame, age %u \n", wbuf_get_age(athwbuf->wbuf)); ATH_NODE_PWRSAVEQ_DEQUEUE(dataq, athwbuf); ATH_NODE_PWRSAVEQ_UNLOCK(dataq); ath_node_pwrsaveq_complete_athwbuf(an, athwbuf); discard++; } for (;;) { ATH_NODE_PWRSAVEQ_LOCK(mgtq); ATH_NODE_PWRSAVEQ_POLL(mgtq, athwbuf); if((athwbuf == NULL) || (wbuf_get_age(athwbuf->wbuf) >= ATH_NODE_INACT_WAIT)) { if (athwbuf != NULL) wbuf_set_age(athwbuf->wbuf, wbuf_get_age(athwbuf->wbuf) - ATH_NODE_INACT_WAIT); ATH_NODE_PWRSAVEQ_UNLOCK(mgtq); break; } DPRINTF(sc, ATH_DEBUG_PWR_SAVE, "discard mgt frame, age %u \n", wbuf_get_age(athwbuf->wbuf)); ATH_NODE_PWRSAVEQ_DEQUEUE(mgtq, athwbuf); ATH_NODE_PWRSAVEQ_UNLOCK(mgtq); ath_node_pwrsaveq_complete_athwbuf(an, athwbuf); discard++; } DPRINTF(sc, ATH_DEBUG_PWR_SAVE, "discard %u frames for age \n", discard); } return discard; }
/* * Reset the rate control state for each 802.11 state transition. */ void ath_rate_newstate(struct ath_softc *sc, enum ieee80211_state state) { struct ieee80211com *ic = &sc->sc_ic; if (state == IEEE80211_S_RUN) { if (ic->ic_opmode != IEEE80211_M_STA) { /* * Sync rates for associated stations and neighbors. */ ieee80211_iterate_nodes(&ic->ic_sta, rate_cb, sc); } ath_rate_newassoc(sc, ATH_NODE(ic->ic_bss), 1); } }
void ath_node_pwrsaveq_set_param(ath_node_t node, u_int8_t param, u_int32_t val) { struct ath_node *an = ATH_NODE(node); switch((enum ath_node_pwrsaveq_param)param) { case ATH_NODE_PWRSAVEQ_DATA_Q_LEN: an->an_dataq.nsq_max_len = val; break; case ATH_NODE_PWRSAVEQ_MGMT_Q_LEN: an->an_mgmtq.nsq_max_len = val; break; default: break; } }
void ath_node_pwrsaveq_get_info(ath_node_t node, void *info) { struct ath_node *an = ATH_NODE(node); struct ath_node_pwrsaveq *dataq,*mgtq; dataq = ATH_NODE_PWRSAVEQ_DATAQ(an); mgtq = ATH_NODE_PWRSAVEQ_MGMTQ(an); ATH_NODE_PWRSAVEQ_LOCK(dataq); ATH_NODE_PWRSAVEQ_LOCK(mgtq); ((ath_node_pwrsaveq_info *)info)->data_count = ATH_NODE_PWRSAVEQ_QLEN(dataq); ((ath_node_pwrsaveq_info *)info)->mgt_count = ATH_NODE_PWRSAVEQ_QLEN(mgtq); ((ath_node_pwrsaveq_info *)info)->data_len = ATH_NODE_PWRSAVEQ_BYTES(dataq); ((ath_node_pwrsaveq_info *)info)->mgt_len = ATH_NODE_PWRSAVEQ_BYTES(mgtq); ((ath_node_pwrsaveq_info *)info)->ps_frame_count = mgtq->nsq_num_ps_frames; ATH_NODE_PWRSAVEQ_UNLOCK(mgtq); ATH_NODE_PWRSAVEQ_UNLOCK(dataq); }
static void ath_rate_update_static_rix(struct ath_softc *sc, struct ieee80211_node *ni) { struct ath_node *an = ATH_NODE(ni); const struct ieee80211_txparam *tp = ni->ni_txparms; struct sample_node *sn = ATH_NODE_SAMPLE(an); 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. */ sn->static_rix = ath_rate_get_static_rix(sc, ni); } else { sn->static_rix = -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 ath_rate_update(struct ath_softc *sc, struct ieee80211_node *ni, int rate) { struct ath_node *an = ATH_NODE(ni); struct onoe_node *on = ATH_NODE_ONOE(an); const HAL_RATE_TABLE *rt = sc->sc_currates; u_int8_t rix; KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); DPRINTF(sc, "%s: set xmit rate for %s to %dM\n", __func__, ether_sprintf(ni->ni_macaddr), ni->ni_rates.rs_nrates > 0 ? (ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL) / 2 : 0); ni->ni_txrate = rate; /* * Before associating a node has no rate set setup * so we can't calculate any transmit codes to use. * This is ok since we should never be sending anything * but management frames and those always go at the * lowest hardware rate. */ if (ni->ni_rates.rs_nrates == 0) goto done; on->on_tx_rix0 = sc->sc_rixmap[ ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL]; on->on_tx_rate0 = rt->info[on->on_tx_rix0].rateCode; on->on_tx_rate0sp = on->on_tx_rate0 | rt->info[on->on_tx_rix0].shortPreamble; if (sc->sc_mrretry) { /* * Hardware supports multi-rate retry; setup two * step-down retry rates and make the lowest rate * be the ``last chance''. We use 4, 2, 2, 2 tries * respectively (4 is set here, the rest are fixed * in the xmit routine). */ on->on_tx_try0 = 1 + 3; /* 4 tries at rate 0 */ if (--rate >= 0) { rix = sc->sc_rixmap[ ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL]; on->on_tx_rate1 = rt->info[rix].rateCode; on->on_tx_rate1sp = on->on_tx_rate1 | rt->info[rix].shortPreamble; } else { on->on_tx_rate1 = on->on_tx_rate1sp = 0; } if (--rate >= 0) { rix = sc->sc_rixmap[ ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL]; on->on_tx_rate2 = rt->info[rix].rateCode; on->on_tx_rate2sp = on->on_tx_rate2 | rt->info[rix].shortPreamble; } else { on->on_tx_rate2 = on->on_tx_rate2sp = 0; } if (rate > 0) { /* NB: only do this if we didn't already do it above */ on->on_tx_rate3 = rt->info[0].rateCode; on->on_tx_rate3sp = on->on_tx_rate3 | rt->info[0].shortPreamble; } else { on->on_tx_rate3 = on->on_tx_rate3sp = 0; } } else { on->on_tx_try0 = ATH_TXMAXTRY; /* max tries at rate 0 */ on->on_tx_rate1 = on->on_tx_rate1sp = 0; on->on_tx_rate2 = on->on_tx_rate2sp = 0; on->on_tx_rate3 = on->on_tx_rate3sp = 0; } done: on->on_tx_ok = on->on_tx_err = on->on_tx_retr = on->on_tx_upper = 0; }
/* * Examine and potentially adjust the transmit rate. */ static void ath_rate_ctl(void *arg, struct ieee80211_node *ni) { struct ath_softc *sc = arg; struct onoe_node *on = ATH_NODE_ONOE(ATH_NODE(ni)); struct ieee80211_rateset *rs = &ni->ni_rates; int dir = 0, nrate, enough; /* * Rate control * XXX: very primitive version. */ enough = (on->on_tx_ok + on->on_tx_err >= 10); /* no packet reached -> down */ if (on->on_tx_err > 0 && on->on_tx_ok == 0) dir = -1; /* all packets needs retry in average -> down */ if (enough && on->on_tx_ok < on->on_tx_retr) dir = -1; /* no error and less than rate_raise% of packets need retry -> up */ if (enough && on->on_tx_err == 0 && on->on_tx_retr < (on->on_tx_ok * ath_rate_raise) / 100) dir = 1; DPRINTF(sc, "%s: ok %d err %d retr %d upper %d dir %d\n", ether_sprintf(ni->ni_macaddr), on->on_tx_ok, on->on_tx_err, on->on_tx_retr, on->on_tx_upper, dir); nrate = ni->ni_txrate; switch (dir) { case 0: if (enough && on->on_tx_upper > 0) on->on_tx_upper--; break; case -1: if (nrate > 0) { nrate--; sc->sc_stats.ast_rate_drop++; } on->on_tx_upper = 0; break; case 1: /* raise rate if we hit rate_raise_threshold */ if (++on->on_tx_upper < ath_rate_raise_threshold) break; on->on_tx_upper = 0; if (nrate + 1 < rs->rs_nrates) { nrate++; sc->sc_stats.ast_rate_raise++; } break; } if (nrate != ni->ni_txrate) { DPRINTF(sc, "%s: %dM -> %dM (%d ok, %d err, %d retr)\n", __func__, (rs->rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL) / 2, (rs->rs_rates[nrate] & IEEE80211_RATE_VAL) / 2, on->on_tx_ok, on->on_tx_err, on->on_tx_retr); ath_rate_update(sc, ni, nrate); } else if (enough) on->on_tx_ok = on->on_tx_err = on->on_tx_retr = 0; }
int ath_ald_collect_ni_data(ath_dev_t dev, ath_node_t an, ath_ald_t ald_data, ath_ni_ald_t ald_ni_data) { u_int32_t ccf; u_int32_t myCcf = 0; u_int32_t aggrAverage = 0; struct ath_softc *sc = ATH_DEV_TO_SC(dev); struct atheros_softc *asc = (struct atheros_softc*)sc->sc_rc; struct ath_node *ant = ATH_NODE(an); struct atheros_node *pSib; TX_RATE_CTRL *pRc; const RATE_TABLE_11N *pRateTable = (const RATE_TABLE_11N *)asc->hwRateTable[sc->sc_curmode]; //an = ATH_NODE(ATH_NODE_NET80211(ni)->an_sta); pSib = ATH_NODE_ATHEROS(ant); pRc = (TX_RATE_CTRL *)(pSib); ald_ni_data->ald_lastper = pRc->state[pRc->lastRateIndex].per; if(pRc->TxRateCount != 0) { ald_ni_data->ald_avgtxrate = pRc->TxRateInMbps / pRc->TxRateCount; ald_ni_data->ald_avgmax4msaggr = pRc->Max4msFrameLen / (pRc->TxRateCount * ald_data->msdu_size); } pRc->TxRateInMbps = 0; pRc->Max4msFrameLen = 0; pRc->TxRateCount = 0; if (ald_ni_data->ald_avgmax4msaggr > 32) ald_ni_data->ald_avgmax4msaggr = 32; if(sc->sc_ald.sc_ald_txairtime != 0){ //ccf = (ald_data->msdu_size/(sc->sc_ald.sc_ald_txairtime/ald_ni_data->ald_pktnum))*8; ccf = ald_ni_data->ald_avgtxrate; myCcf = sc->sc_ald.sc_ald_pktlen*8/sc->sc_ald.sc_ald_txairtime; aggrAverage = sc->sc_ald.sc_ald_pktnum/sc->sc_ald.sc_ald_counter; } else { if(ald_ni_data->ald_avgtxrate) { ccf = ald_ni_data->ald_avgtxrate; aggrAverage = ald_ni_data->ald_avgmax4msaggr/2; } else { ccf = pRateTable->info[INIT_RATE_MAX_40-4].rateKbps/1000; aggrAverage = MAX_AGGR_LIMIT/2; } } if (sc->sc_ald.sc_ald_counter) { ald_data->ald_txbuf_used = sc->sc_ald.sc_ald_bfused/sc->sc_ald.sc_ald_counter; } else { ald_data->ald_txbuf_used = 0; } ald_data->ald_curThroughput = sc->sc_ald.sc_ald_pktnum * ald_data->msdu_size * 8 / 1000000; if (ald_data->ald_curThroughput < 1) { aggrAverage = MAX_AGGR_LIMIT/2; } if (ccf != 0) { ald_ni_data->ald_capacity = ccf; ald_ni_data->ald_aggr = aggrAverage; ald_ni_data->ald_phyerr = ald_data->phyerr_rate; if (ald_data->msdu_size < DEFAULT_MSDU_SIZE) { ald_ni_data->ald_msdusize = ALD_MSDU_SIZE; } else { ald_ni_data->ald_msdusize = ald_data->msdu_size; } } sc->sc_ald.sc_ald_txairtime = 0; sc->sc_ald.sc_ald_pktnum = 0; sc->sc_ald.sc_ald_pktlen = 0; sc->sc_ald.sc_ald_bfused = 0; sc->sc_ald.sc_ald_counter = 0; ald_ni_data->ald_txrate = 0; ald_ni_data->ald_max4msframelen = 0; ald_ni_data->ald_txcount = 0; ald_ni_data->ald_avgtxrate = 0; ald_ni_data->ald_avgmax4msaggr = 0; return 0; }
/* * 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 }
/* * 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 }
/* * send one frme out of power save queue . * called in reponse to PS poll. * returns 1 if succesfully sends a frame. 0 other wise. */ int ath_node_pwrsaveq_send(ath_node_t node, u_int8_t frame_type) { struct ath_node *an = ATH_NODE(node); struct ath_softc *sc = an->an_sc; ath_wbuf_t athwbuf; wbuf_t wbuf = NULL; int qlen; struct ath_node_pwrsaveq *dataq, *mgtq; ieee80211_tx_control_t *txctl; struct ieee80211_frame *wh; u_int8_t more_frag; dataq = ATH_NODE_PWRSAVEQ_DATAQ(an); mgtq = ATH_NODE_PWRSAVEQ_MGMTQ(an); next_frag: ATH_NODE_PWRSAVEQ_LOCK(dataq); ATH_NODE_PWRSAVEQ_LOCK(mgtq); if (frame_type == IEEE80211_FC0_TYPE_MGT) { ATH_NODE_PWRSAVEQ_DEQUEUE(mgtq, athwbuf); if (athwbuf) wbuf = athwbuf->wbuf; if (wbuf && wbuf_is_pwrsaveframe(wbuf)) { /* ps frame (null (or) pspoll frame) */ --mgtq->nsq_num_ps_frames; } } else { ATH_NODE_PWRSAVEQ_DEQUEUE(dataq, athwbuf); if (athwbuf) wbuf = athwbuf->wbuf; } if (athwbuf == NULL || wbuf == NULL) { ATH_NODE_PWRSAVEQ_UNLOCK(mgtq); ATH_NODE_PWRSAVEQ_UNLOCK(dataq); return 0; } qlen = ATH_NODE_PWRSAVEQ_QLEN(dataq); qlen += ATH_NODE_PWRSAVEQ_QLEN(mgtq); ATH_NODE_PWRSAVEQ_UNLOCK(mgtq); ATH_NODE_PWRSAVEQ_UNLOCK(dataq); wh = (struct ieee80211_frame *)wbuf_header(wbuf); more_frag = wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG; /* * If there are more packets, set the more packets bit * in the packet dispatched to the station; otherwise * turn off the TIM bit. */ if (qlen != 0) { DPRINTF(sc, ATH_DEBUG_PWR_SAVE, "send packet, %u still queued \n", qlen); /* * encap will set more data bit. */ wbuf_set_moredata(wbuf); if (wbuf_is_moredata(wbuf)) { wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; } } else { DPRINTF(sc, ATH_DEBUG_PWR_SAVE, "%s", "send packet, queue empty \n"); /* TIM bit will be set by UMAC caller */ } wbuf_clear_legacy_ps(wbuf); txctl = &athwbuf->txctl; if (sc->sc_ath_ops.tx(sc, wbuf, txctl) != 0) { DPRINTF(sc, ATH_DEBUG_PWR_SAVE, "%s: send error, comple the wbuf\n", __func__); ath_node_pwrsaveq_complete_athwbuf(an, athwbuf); /* process all fragment together */ if (more_frag) goto next_frag; return 0; } if (athwbuf) { OS_FREE_PS(athwbuf); } /* process all fragments together */ if (more_frag) goto next_frag; return 1; }
/** * The code below assumes that we are dealing with hardware multi rate retry * I have no idea what will happen if you try to use this module with another * type of hardware. Your machine might catch fire or it might work with * horrible performance... */ static void ath_rate_update(struct ath_softc *sc, struct ieee80211_node *ni, int rate) { struct ath_node *an = ATH_NODE(ni); struct amrr_node *amn = ATH_NODE_AMRR(an); struct ieee80211vap *vap = ni->ni_vap; const HAL_RATE_TABLE *rt = sc->sc_currates; u_int8_t rix; KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); IEEE80211_NOTE(vap, IEEE80211_MSG_RATECTL, ni, "%s: set xmit rate to %dM", __func__, ni->ni_rates.rs_nrates > 0 ? (ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL) / 2 : 0); amn->amn_rix = rate; /* * Before associating a node has no rate set setup * so we can't calculate any transmit codes to use. * This is ok since we should never be sending anything * but management frames and those always go at the * lowest hardware rate. */ if (ni->ni_rates.rs_nrates > 0) { ni->ni_txrate = ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL; amn->amn_tx_rix0 = sc->sc_rixmap[ni->ni_txrate]; amn->amn_tx_rate0 = rt->info[amn->amn_tx_rix0].rateCode; amn->amn_tx_rate0sp = amn->amn_tx_rate0 | rt->info[amn->amn_tx_rix0].shortPreamble; if (sc->sc_mrretry) { amn->amn_tx_try0 = 1; amn->amn_tx_try1 = 1; amn->amn_tx_try2 = 1; amn->amn_tx_try3 = 1; if (--rate >= 0) { rix = sc->sc_rixmap[ ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL]; amn->amn_tx_rate1 = rt->info[rix].rateCode; amn->amn_tx_rate1sp = amn->amn_tx_rate1 | rt->info[rix].shortPreamble; } else { amn->amn_tx_rate1 = amn->amn_tx_rate1sp = 0; } if (--rate >= 0) { rix = sc->sc_rixmap[ ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL]; amn->amn_tx_rate2 = rt->info[rix].rateCode; amn->amn_tx_rate2sp = amn->amn_tx_rate2 | rt->info[rix].shortPreamble; } else { amn->amn_tx_rate2 = amn->amn_tx_rate2sp = 0; } if (rate > 0) { /* NB: only do this if we didn't already do it above */ amn->amn_tx_rate3 = rt->info[0].rateCode; amn->amn_tx_rate3sp = amn->amn_tx_rate3 | rt->info[0].shortPreamble; } else { amn->amn_tx_rate3 = amn->amn_tx_rate3sp = 0; } } else { amn->amn_tx_try0 = ATH_TXMAXTRY; /* theorically, these statements are useless because * the code which uses them tests for an_tx_try0 == ATH_TXMAXTRY */ amn->amn_tx_try1 = 0; amn->amn_tx_try2 = 0; amn->amn_tx_try3 = 0; amn->amn_tx_rate1 = amn->amn_tx_rate1sp = 0; amn->amn_tx_rate2 = amn->amn_tx_rate2sp = 0; amn->amn_tx_rate3 = amn->amn_tx_rate3sp = 0; } } node_reset(amn); amn->amn_interval = ath_rateinterval; if (vap->iv_opmode == IEEE80211_M_STA) amn->amn_interval /= 2; amn->amn_interval = (amn->amn_interval * hz) / 1000; }
/* * 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"); }
/* * node saveq flush. */ void ath_node_pwrsaveq_flush(ath_node_t node) { struct ath_node *an = ATH_NODE(node); struct ath_softc *sc = an->an_sc; ath_wbuf_t athwbuf; wbuf_t wbuf; struct ath_node_pwrsaveq *dataq,*mgtq; int dqlen, mqlen; ieee80211_tx_control_t *txctl; dataq = ATH_NODE_PWRSAVEQ_DATAQ(an); mgtq = ATH_NODE_PWRSAVEQ_MGMTQ(an); /* XXX if no stations in ps mode, flush mc frames */ dqlen = ATH_NODE_PWRSAVEQ_QLEN(dataq); /* * Flush queued mgmt frames. */ ATH_NODE_PWRSAVEQ_LOCK(mgtq); if (ATH_NODE_PWRSAVEQ_QLEN(mgtq) != 0) { DPRINTF(sc, ATH_DEBUG_PWR_SAVE, "flush mgt ps queue, %u packets queued \n", ATH_NODE_PWRSAVEQ_QLEN(mgtq)); for (;;) { ATH_NODE_PWRSAVEQ_DEQUEUE(mgtq, athwbuf); if (athwbuf == NULL) break; wbuf = athwbuf->wbuf; ASSERT(wbuf); mqlen = ATH_NODE_PWRSAVEQ_QLEN(mgtq); DPRINTF(sc, ATH_DEBUG_PWR_SAVE, "sendmgmt ps queue, %u packets remaining \n", mqlen); /* * For a Station node (non bss node) If this is the last packet, turn off the TIM bit, * Set the PWR_SAV bit on every frame but the last one * to allow encap to test for * adding more MORE_DATA bit to wh. */ if (mqlen || dqlen) { wbuf_set_moredata(wbuf); if (wbuf_is_moredata(wbuf)) { struct ieee80211_frame *wh = (struct ieee80211_frame *)wbuf_header(wbuf); wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; } } wbuf_clear_legacy_ps(wbuf); txctl = &athwbuf->txctl; if (sc->sc_ath_ops.tx(sc, wbuf, txctl) != 0) { DPRINTF(sc, ATH_DEBUG_PWR_SAVE, "%s: send error, comple the wbuf\n", __func__); ath_node_pwrsaveq_complete_athwbuf(an, athwbuf); } else { if (athwbuf) { OS_FREE_PS(athwbuf); } } } } mgtq->nsq_num_ps_frames = 0; ATH_NODE_PWRSAVEQ_UNLOCK(mgtq); /* * Flush queued unicast frames. */ ATH_NODE_PWRSAVEQ_LOCK(dataq); if (ATH_NODE_PWRSAVEQ_QLEN(dataq) != 0) { DPRINTF(sc, ATH_DEBUG_PWR_SAVE, "flush data ps queue, %u packets queued \n", ATH_NODE_PWRSAVEQ_QLEN(dataq)); for (;;) { ATH_NODE_PWRSAVEQ_DEQUEUE(dataq, athwbuf); if (athwbuf == NULL) break; wbuf = athwbuf->wbuf; ASSERT(wbuf); dqlen = ATH_NODE_PWRSAVEQ_QLEN(dataq); DPRINTF(sc, ATH_DEBUG_PWR_SAVE, "senddata ps queue, %u packets remaining \n", dqlen); /* * For a Station node (non bss node) If this is the last packet, turn off the TIM bit, * Set the PWR_SAV bit on every frame but the last one * to allow encap to test for * adding more MORE_DATA bit to wh. */ if (dqlen) { wbuf_set_moredata(wbuf); if (wbuf_is_moredata(wbuf)) { struct ieee80211_frame *wh = (struct ieee80211_frame *)wbuf_header(wbuf); wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; } } wbuf_clear_legacy_ps(wbuf); txctl = &athwbuf->txctl; if (sc->sc_ath_ops.tx(sc, wbuf, txctl) != 0) { DPRINTF(sc, ATH_DEBUG_PWR_SAVE, "%s: send error, comple the wbuf\n", __func__); ath_node_pwrsaveq_complete_athwbuf(an, athwbuf); } else { if (athwbuf) { OS_FREE_PS(athwbuf); } } } } ATH_NODE_PWRSAVEQ_UNLOCK(dataq); /* TIM will be set by UMAC caller */ }
/* * Save an outbound packet for a node in power-save sleep state. * The new packet is placed on the node's saved queue, and the TIM * is changed by UMAC caller. */ void ath_node_pwrsaveq_queue(ath_node_t node, ath_wbuf_t athwbuf, u_int8_t frame_type) { struct ath_node *an = ATH_NODE(node); struct ath_softc *sc = an->an_sc; int qlen, age; struct ath_node_pwrsaveq *dataq,*mgtq,*psq; dataq = ATH_NODE_PWRSAVEQ_DATAQ(an); mgtq = ATH_NODE_PWRSAVEQ_MGMTQ(an); ATH_NODE_PWRSAVEQ_LOCK(dataq); ATH_NODE_PWRSAVEQ_LOCK(mgtq); if (frame_type == IEEE80211_FC0_TYPE_MGT) { psq = mgtq; } else { psq = dataq; } if (ATH_NODE_PWRSAVEQ_FULL(psq)) { ATH_NODE_PWRSAVEQ_UNLOCK(mgtq); ATH_NODE_PWRSAVEQ_UNLOCK(dataq); DPRINTF(sc, ATH_DEBUG_ANY, "%s pwr save q: overflow, drops (size %d) \n", (psq == dataq) ? "data" : "mgt", ATH_NODE_PWRSAVEQ_MAX_LEN); ath_node_pwrsaveq_complete_athwbuf(an, athwbuf); return; } /* * special handling of frames with PS = 1. */ ath_node_pwrsaveq_handle_ps_frames(an, athwbuf, frame_type); /* By default use the 4 * beacon intval as the aging time */ age = (ATH_NODE_AGE_INTVAL << 2) >> 10; /* TU -> secs */ /* * Note: our aging algorithm is not working well. In fact, due to the long interval * when the aging algorithm is called (ATH_NODE_INACT_WAIT is 150 secs), we depend on * the associated station node to be disassociated to clear its stale frames. However, * as a temporary fix, I will make sure that the age is at least greater than * ATH_NODE_INACT_WAIT. Otherwise, we will discard all frames in ps queue even though * it is just queued. */ if (age < ATH_NODE_INACT_WAIT) { DPRINTF(sc, ATH_DEBUG_PWR_SAVE, "%s Note: increased age from %d to %d secs.\n", __func__, age, ATH_NODE_INACT_WAIT); age = ATH_NODE_INACT_WAIT; } ATH_NODE_PWRSAVEQ_ENQUEUE(psq, athwbuf, qlen, age); /* * calculate the combined queue length of management and data queues. */ qlen = ATH_NODE_PWRSAVEQ_QLEN(dataq); qlen += ATH_NODE_PWRSAVEQ_QLEN(mgtq); ATH_NODE_PWRSAVEQ_UNLOCK(mgtq); ATH_NODE_PWRSAVEQ_UNLOCK(dataq); DPRINTF(sc, ATH_DEBUG_PWR_SAVE, "%s pwr queue:save frame, %u now queued \n", (psq == dataq) ? "data" : "mgt" ,qlen); /* TIM bit will be set by UMAC caller */ }
/* * Examine and potentially adjust the transmit rate. */ static void ath_rate_ctl(void *arg, struct ieee80211_node *ni) { struct ath_softc *sc = arg; struct amrr_node *amn = ATH_NODE_AMRR(ATH_NODE (ni)); int old_rate; #define is_success(amn) \ (amn->amn_tx_try1_cnt < (amn->amn_tx_try0_cnt/10)) #define is_enough(amn) \ (amn->amn_tx_try0_cnt > 10) #define is_failure(amn) \ (amn->amn_tx_try1_cnt > (amn->amn_tx_try0_cnt/3)) #define is_max_rate(ni) \ ((ni->ni_txrate + 1) >= ni->ni_rates.rs_nrates) #define is_min_rate(ni) \ (ni->ni_txrate == 0) old_rate = ni->ni_txrate; DPRINTF (sc, "cnt0: %d cnt1: %d cnt2: %d cnt3: %d -- threshold: %d\n", amn->amn_tx_try0_cnt, amn->amn_tx_try1_cnt, amn->amn_tx_try2_cnt, amn->amn_tx_try3_cnt, amn->amn_success_threshold); if (is_success (amn) && is_enough (amn)) { amn->amn_success++; if (amn->amn_success == amn->amn_success_threshold && !is_max_rate (ni)) { amn->amn_recovery = 1; amn->amn_success = 0; ni->ni_txrate++; DPRINTF (sc, "increase rate to %d\n", ni->ni_txrate); } else { amn->amn_recovery = 0; } } else if (is_failure (amn)) { amn->amn_success = 0; if (!is_min_rate (ni)) { if (amn->amn_recovery) { /* recovery failure. */ amn->amn_success_threshold *= 2; amn->amn_success_threshold = min (amn->amn_success_threshold, (u_int)ath_rate_max_success_threshold); DPRINTF (sc, "decrease rate recovery thr: %d\n", amn->amn_success_threshold); } else { /* simple failure. */ amn->amn_success_threshold = ath_rate_min_success_threshold; DPRINTF (sc, "decrease rate normal thr: %d\n", amn->amn_success_threshold); } amn->amn_recovery = 0; ni->ni_txrate--; } else { amn->amn_recovery = 0; } } if (is_enough (amn) || old_rate != ni->ni_txrate) { /* reset counters. */ amn->amn_tx_try0_cnt = 0; amn->amn_tx_try1_cnt = 0; amn->amn_tx_try2_cnt = 0; amn->amn_tx_try3_cnt = 0; amn->amn_tx_failure_cnt = 0; } if (old_rate != ni->ni_txrate) { ath_rate_update(sc, ni, ni->ni_txrate); } }
/* * Examine and potentially adjust the transmit rate. */ static void ath_rate_ctl(void *arg, struct ieee80211_node *ni) { struct ath_softc *sc = arg; struct amrr_node *amn = ATH_NODE_AMRR(ATH_NODE (ni)); int rix; #define is_success(amn) \ (amn->amn_tx_try1_cnt < (amn->amn_tx_try0_cnt/10)) #define is_enough(amn) \ (amn->amn_tx_try0_cnt > 10) #define is_failure(amn) \ (amn->amn_tx_try1_cnt > (amn->amn_tx_try0_cnt/3)) rix = amn->amn_rix; IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, "cnt0: %d cnt1: %d cnt2: %d cnt3: %d -- threshold: %d", amn->amn_tx_try0_cnt, amn->amn_tx_try1_cnt, amn->amn_tx_try2_cnt, amn->amn_tx_try3_cnt, amn->amn_success_threshold); if (is_success (amn) && is_enough (amn)) { amn->amn_success++; if (amn->amn_success == amn->amn_success_threshold && rix + 1 < ni->ni_rates.rs_nrates) { amn->amn_recovery = 1; amn->amn_success = 0; rix++; IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, "increase rate to %d", rix); } else { amn->amn_recovery = 0; } } else if (is_failure (amn)) { amn->amn_success = 0; if (rix > 0) { if (amn->amn_recovery) { /* recovery failure. */ amn->amn_success_threshold *= 2; amn->amn_success_threshold = min (amn->amn_success_threshold, (u_int)ath_rate_max_success_threshold); IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, "decrease rate recovery thr: %d", amn->amn_success_threshold); } else { /* simple failure. */ amn->amn_success_threshold = ath_rate_min_success_threshold; IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, "decrease rate normal thr: %d", amn->amn_success_threshold); } amn->amn_recovery = 0; rix--; } else { amn->amn_recovery = 0; } } if (is_enough (amn) || rix != amn->amn_rix) { /* reset counters. */ amn->amn_tx_try0_cnt = 0; amn->amn_tx_try1_cnt = 0; amn->amn_tx_try2_cnt = 0; amn->amn_tx_try3_cnt = 0; amn->amn_tx_failure_cnt = 0; } if (rix != amn->amn_rix) { ath_rate_update(sc, ni, rix); } }
/** * The code below assumes that we are dealing with hardware multi rate retry * I have no idea what will happen if you try to use this module with another * type of hardware. Your machine might catch fire or it might work with * horrible performance... */ static void ath_rate_update(struct ath_softc *sc, struct ieee80211_node *ni, int rate) { struct ath_node *an = ATH_NODE(ni); struct amrr_node *amn = ATH_NODE_AMRR(an); const HAL_RATE_TABLE *rt = sc->sc_currates; u_int8_t rix; KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); DPRINTF(sc, "%s: set xmit rate for %s to %dM\n", __func__, ether_sprintf(ni->ni_macaddr), ni->ni_rates.rs_nrates > 0 ? (ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL) / 2 : 0); ni->ni_txrate = rate; /* XXX management/control frames always go at the lowest speed */ an->an_tx_mgtrate = rt->info[0].rateCode; an->an_tx_mgtratesp = an->an_tx_mgtrate | rt->info[0].shortPreamble; /* * Before associating a node has no rate set setup * so we can't calculate any transmit codes to use. * This is ok since we should never be sending anything * but management frames and those always go at the * lowest hardware rate. */ if (ni->ni_rates.rs_nrates > 0) { amn->amn_tx_rix0 = sc->sc_rixmap[ ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL]; amn->amn_tx_rate0 = rt->info[amn->amn_tx_rix0].rateCode; amn->amn_tx_rate0sp = amn->amn_tx_rate0 | rt->info[amn->amn_tx_rix0].shortPreamble; if (sc->sc_mrretry) { amn->amn_tx_try0 = 1; amn->amn_tx_try1 = 1; amn->amn_tx_try2 = 1; amn->amn_tx_try3 = 1; if (--rate >= 0) { rix = sc->sc_rixmap[ ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL]; amn->amn_tx_rate1 = rt->info[rix].rateCode; amn->amn_tx_rate1sp = amn->amn_tx_rate1 | rt->info[rix].shortPreamble; } else { amn->amn_tx_rate1 = amn->amn_tx_rate1sp = 0; } if (--rate >= 0) { rix = sc->sc_rixmap[ ni->ni_rates.rs_rates[rate]&IEEE80211_RATE_VAL]; amn->amn_tx_rate2 = rt->info[rix].rateCode; amn->amn_tx_rate2sp = amn->amn_tx_rate2 | rt->info[rix].shortPreamble; } else { amn->amn_tx_rate2 = amn->amn_tx_rate2sp = 0; } if (rate > 0) { /* NB: only do this if we didn't already do it above */ amn->amn_tx_rate3 = rt->info[0].rateCode; amn->amn_tx_rate3sp = an->an_tx_mgtrate | rt->info[0].shortPreamble; } else { amn->amn_tx_rate3 = amn->amn_tx_rate3sp = 0; } } else { amn->amn_tx_try0 = ATH_TXMAXTRY; /* theorically, these statements are useless because * the code which uses them tests for an_tx_try0 == ATH_TXMAXTRY */ amn->amn_tx_try1 = 0; amn->amn_tx_try2 = 0; amn->amn_tx_try3 = 0; amn->amn_tx_rate1 = amn->amn_tx_rate1sp = 0; amn->amn_tx_rate2 = amn->amn_tx_rate2sp = 0; amn->amn_tx_rate3 = amn->amn_tx_rate3sp = 0; } } node_reset (amn); }