From owner-p4-projects@FreeBSD.ORG Fri Mar 14 05:24:13 2008 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id E50E61065673; Fri, 14 Mar 2008 05:24:12 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 89846106566C for ; Fri, 14 Mar 2008 05:24:12 +0000 (UTC) (envelope-from sam@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 75A2F8FC12 for ; Fri, 14 Mar 2008 05:24:12 +0000 (UTC) (envelope-from sam@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id m2E5OCeD096714 for ; Fri, 14 Mar 2008 05:24:12 GMT (envelope-from sam@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.1/8.14.1/Submit) id m2E5OCwY096712 for perforce@freebsd.org; Fri, 14 Mar 2008 05:24:12 GMT (envelope-from sam@freebsd.org) Date: Fri, 14 Mar 2008 05:24:12 GMT Message-Id: <200803140524.m2E5OCwY096712@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to sam@freebsd.org using -f From: Sam Leffler To: Perforce Change Reviews Cc: Subject: PERFORCE change 137686 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 14 Mar 2008 05:24:13 -0000 http://perforce.freebsd.org/chv.cgi?CH=137686 Change 137686 by sam@sam_ebb on 2008/03/14 05:24:04 Major overhaul: o consolidate various driver-specific hacks by refining the api's; drivers can accumulate stats on each tx done or through periodic polling (e.g. ural which collects stats through cmds) and effect rate selection according to a sampling interval o do the initial tx rate selection in ieee80211_amrr_node_init (probably need to refine for 11b rate sets to start 5.5 instead of 11) o de-obfuscate some of the code o eliminate dependence on ni_txrate for tracking the current rate index since it's now for reporting current tx rate o handle ni_txrate updates o automatically add sysctl knobs to net.wlan.X o fix rate downshifting so it requires "is_enough" frames; otherwise this can happen if 1 frame is sent successfully with a retransmit (algorithm is stil utter crap but this at least eliminates one of the major causes of rapid rate oscillation) Affected files ... .. //depot/projects/vap/sys/net80211/ieee80211_amrr.c#7 edit .. //depot/projects/vap/sys/net80211/ieee80211_amrr.h#5 edit Differences ... ==== //depot/projects/vap/sys/net80211/ieee80211_amrr.c#7 (text+ko) ==== @@ -53,68 +53,87 @@ ((amn)->amn_retrycnt > (amn)->amn_txcnt / 3) #define is_enough(amn) \ ((amn)->amn_txcnt > 10) -#define is_min_rate(ni) \ - ((ni)->ni_txrate == 0) -#define is_max_rate(ni) \ - ((ni)->ni_txrate == (ni)->ni_rates.rs_nrates - 1) -#define increase_rate(ni) \ - ((ni)->ni_txrate++) -#define decrease_rate(ni) \ - ((ni)->ni_txrate--) -#define reset_cnt(amn) \ - do { (amn)->amn_txcnt = (amn)->amn_retrycnt = 0; } while (0) + +static void amrr_sysctlattach(struct ieee80211_amrr *amrr, + struct sysctl_ctx_list *ctx, struct sysctl_oid *tree); /* number of references from net80211 layer */ static int nrefs = 0; void +ieee80211_amrr_setinterval(struct ieee80211_amrr *amrr, int msecs) +{ + int t; + + if (msecs < 100) + msecs = 100; + t = msecs_to_ticks(msecs); + amrr->amrr_interval = (t < 1) ? 1 : t; +} + +void ieee80211_amrr_init(struct ieee80211_amrr *amrr, - struct ieee80211vap *vap, int amin, int amax) + struct ieee80211vap *vap, int amin, int amax, int interval) { /* XXX bounds check? */ amrr->amrr_min_success_threshold = amin; amrr->amrr_max_success_threshold = amax; - amrr->amrr_vap = vap; + ieee80211_amrr_setinterval(amrr, interval); + + amrr_sysctlattach(amrr, vap->iv_sysctl, vap->iv_oid); +} + +void +ieee80211_amrr_cleanup(struct ieee80211_amrr *amrr) +{ } void ieee80211_amrr_node_init(struct ieee80211_amrr *amrr, - struct ieee80211_amrr_node *amn) + struct ieee80211_amrr_node *amn, struct ieee80211_node *ni) { + const struct ieee80211_rateset *rs = &ni->ni_rates; + + amn->amn_amrr = amrr; amn->amn_success = 0; amn->amn_recovery = 0; amn->amn_txcnt = amn->amn_retrycnt = 0; amn->amn_success_threshold = amrr->amrr_min_success_threshold; + + /* pick initial rate */ + for (amn->amn_rix = rs->rs_nrates - 1; + amn->amn_rix > 0 && (rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL) > 72; + amn->amn_rix--) + ; + ni->ni_txrate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL; + amn->amn_ticks = ticks; } -/* - * Update ni->ni_txrate. - */ -void -ieee80211_amrr_choose(struct ieee80211_amrr *amrr, struct ieee80211_node *ni, - struct ieee80211_amrr_node *amn) +static int +amrr_update(struct ieee80211_amrr *amrr, struct ieee80211_amrr_node *amn, + struct ieee80211_node *ni) { - int need_change = 0; + int rix = amn->amn_rix; + + KASSERT(is_enough(amn), ("txcnt %d", amn->amn_txcnt)); - if (is_success(amn) && is_enough(amn)) { + if (is_success(amn)) { amn->amn_success++; if (amn->amn_success >= amn->amn_success_threshold && - !is_max_rate(ni)) { + rix + 1 < ni->ni_rates.rs_nrates) { amn->amn_recovery = 1; amn->amn_success = 0; - increase_rate(ni); - IEEE80211_DPRINTF(amrr->amrr_vap, IEEE80211_MSG_RATECTL, + rix++; + IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_RATECTL, "AMRR increasing rate %d (txcnt=%d retrycnt=%d)\n", - ni->ni_rates.rs_rates[ni->ni_txrate] & - IEEE80211_RATE_VAL, + ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL, amn->amn_txcnt, amn->amn_retrycnt); - need_change = 1; } else { amn->amn_recovery = 0; } } else if (is_failure(amn)) { amn->amn_success = 0; - if (!is_min_rate(ni)) { + if (rix > 0) { if (amn->amn_recovery) { amn->amn_success_threshold *= 2; if (amn->amn_success_threshold > @@ -125,19 +144,76 @@ amn->amn_success_threshold = amrr->amrr_min_success_threshold; } - decrease_rate(ni); - IEEE80211_DPRINTF(amrr->amrr_vap, IEEE80211_MSG_RATECTL, + rix--; + IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_RATECTL, "AMRR decreasing rate %d (txcnt=%d retrycnt=%d)\n", - ni->ni_rates.rs_rates[ni->ni_txrate] & - IEEE80211_RATE_VAL, + ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL, amn->amn_txcnt, amn->amn_retrycnt); - need_change = 1; } amn->amn_recovery = 0; } - if (is_enough(amn) || need_change) - reset_cnt(amn); + /* reset counters */ + amn->amn_txcnt = 0; + amn->amn_retrycnt = 0; + + return rix; +} + +/* + * Return the rate index to use in sending a data frame. + * Update our internal state if it's been long enough. + * If the rate changes we also update ni_txrate to match. + */ +int +ieee80211_amrr_choose(struct ieee80211_node *ni, + struct ieee80211_amrr_node *amn) +{ + struct ieee80211_amrr *amrr = amn->amn_amrr; + int rix; + + if (is_enough(amn) && ticks - amn->amn_ticks > amrr->amrr_interval) { + rix = amrr_update(amrr, amn, ni); + if (rix != amn->amn_rix) { + /* update public rate */ + ni->ni_txrate = + ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL; + amn->amn_rix = rix; + } + } else + rix = amn->amn_rix; + return rix; +} + +static int +amrr_sysctl_interval(SYSCTL_HANDLER_ARGS) +{ + struct ieee80211_amrr *amrr = arg1; + int msecs = ticks_to_msecs(amrr->amrr_interval); + int error; + + error = sysctl_handle_int(oidp, &msecs, 0, req); + if (error || !req->newptr) + return error; + ieee80211_amrr_setinterval(amrr, msecs); + return 0; +} + +static void +amrr_sysctlattach(struct ieee80211_amrr *amrr, + struct sysctl_ctx_list *ctx, struct sysctl_oid *tree) +{ + + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "amrr_rate_interval", CTLTYPE_INT | CTLFLAG_RW, amrr, + 0, amrr_sysctl_interval, "I", "amrr operation interval (ms)"); + /* XXX bounds check values */ + SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "amrr_max_sucess_threshold", CTLFLAG_RW, + &amrr->amrr_max_success_threshold, 0, ""); + SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "amrr_min_sucess_threshold", CTLFLAG_RW, + &amrr->amrr_min_success_threshold, 0, ""); } /* ==== //depot/projects/vap/sys/net80211/ieee80211_amrr.h#5 (text+ko) ==== @@ -37,7 +37,7 @@ struct ieee80211_amrr { u_int amrr_min_success_threshold; u_int amrr_max_success_threshold; - struct ieee80211vap *amrr_vap; + int amrr_interval; /* update interval (ticks) */ }; #define IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD 1 @@ -47,18 +47,55 @@ * Rate control state for a given node. */ struct ieee80211_amrr_node { + struct ieee80211_amrr *amn_amrr;/* backpointer */ + int amn_rix; /* current rate index */ + int amn_ticks; /* time of last update */ + /* statistics */ + u_int amn_txcnt; u_int amn_success; + u_int amn_success_threshold; u_int amn_recovery; - u_int amn_success_threshold; - u_int amn_txcnt; u_int amn_retrycnt; }; -void ieee80211_amrr_init(struct ieee80211_amrr *, - struct ieee80211vap *, int, int); +void ieee80211_amrr_init(struct ieee80211_amrr *, struct ieee80211vap *, + int, int, int); +void ieee80211_amrr_cleanup(struct ieee80211_amrr *); +void ieee80211_amrr_setinterval(struct ieee80211_amrr *, int); void ieee80211_amrr_node_init(struct ieee80211_amrr *, + struct ieee80211_amrr_node *, struct ieee80211_node *); +int ieee80211_amrr_choose(struct ieee80211_node *, struct ieee80211_amrr_node *); -void ieee80211_amrr_choose(struct ieee80211_amrr *, struct ieee80211_node *, - struct ieee80211_amrr_node *); + +#define IEEE80211_AMRR_SUCCESS 1 +#define IEEE80211_AMRR_FAILURE 0 + +/* + * Update statistics with tx complete status. Ok is non-zero + * if the packet is known to be ACK'd. Retries has the number + * retransmissions (i.e. xmit attempts - 1). + */ +static __inline void +ieee80211_amrr_tx_complete(struct ieee80211_amrr_node *amn, + int ok, int retries) +{ + amn->amn_txcnt++; + if (ok) + amn->amn_success++; + amn->amn_retrycnt += retries; +} +/* + * Set tx count/retry statistics explicitly. Intended for + * drivers that poll the device for statistics maintained + * in the device. + */ +static __inline void +ieee80211_amrr_tx_update(struct ieee80211_amrr_node *amn, + int txcnt, int success, int retrycnt) +{ + amn->amn_txcnt = txcnt; + amn->amn_success = success; + amn->amn_retrycnt = retrycnt; +} #endif /* _NET80211_IEEE80211_AMRR_H_ */