From owner-svn-soc-all@FreeBSD.ORG Tue Aug 13 09:28:00 2013 Return-Path: Delivered-To: svn-soc-all@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTP id 7E8CCFE for ; Tue, 13 Aug 2013 09:28:00 +0000 (UTC) (envelope-from ccqin@FreeBSD.org) Received: from socsvn.freebsd.org (socsvn.freebsd.org [IPv6:2001:1900:2254:206a::50:2]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 69B9827E5 for ; Tue, 13 Aug 2013 09:28:00 +0000 (UTC) Received: from socsvn.freebsd.org ([127.0.1.124]) by socsvn.freebsd.org (8.14.7/8.14.7) with ESMTP id r7D9S0sc058737 for ; Tue, 13 Aug 2013 09:28:00 GMT (envelope-from ccqin@FreeBSD.org) Received: (from www@localhost) by socsvn.freebsd.org (8.14.7/8.14.6/Submit) id r7D9S0a4058732 for svn-soc-all@FreeBSD.org; Tue, 13 Aug 2013 09:28:00 GMT (envelope-from ccqin@FreeBSD.org) Date: Tue, 13 Aug 2013 09:28:00 GMT Message-Id: <201308130928.r7D9S0a4058732@socsvn.freebsd.org> X-Authentication-Warning: socsvn.freebsd.org: www set sender to ccqin@FreeBSD.org using -f From: ccqin@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r255872 - soc2013/ccqin/head/sys/net80211 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-soc-all@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: SVN commit messages for the entire Summer of Code repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 13 Aug 2013 09:28:00 -0000 Author: ccqin Date: Tue Aug 13 09:28:00 2013 New Revision: 255872 URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=255872 Log: Add ieee80211_rc_info to ratectl api and finish __complete__ of ieee80211_rc_sample. *) add ieee80211_rc_info to ieee80211_ratectl. then we can conveniently provide more tx info to ratectl algo. *) update ir_rates, ieee80211_ratectl_rates and ieee80211_ratectl_complete_rcflags. *) done __complete__ stuff of ieee80211_rc_sample. Modified: soc2013/ccqin/head/sys/net80211/ieee80211_ratectl.c soc2013/ccqin/head/sys/net80211/ieee80211_ratectl.h soc2013/ccqin/head/sys/net80211/ieee80211_rc_sample.c soc2013/ccqin/head/sys/net80211/ieee80211_rc_sample.h Modified: soc2013/ccqin/head/sys/net80211/ieee80211_ratectl.c ============================================================================== --- soc2013/ccqin/head/sys/net80211/ieee80211_ratectl.c Tue Aug 13 08:12:57 2013 (r255871) +++ soc2013/ccqin/head/sys/net80211/ieee80211_ratectl.c Tue Aug 13 09:28:00 2013 (r255872) @@ -122,11 +122,13 @@ void ieee80211_ratectl_complete_rcflags(const struct ieee80211_node *ni, - struct ieee80211_rc_series *rc, int shortPreamble) + struct ieee80211_rc_info *rc_info) { const struct ieee80211com *ic = ni->ni_ic; const struct ieee80211vap *vap = ni->ni_vap; const struct ieee80211_rate_table * rt = ic->ic_rt; + struct ieee80211_rc_series *rc = rc_info->ri_rc; + int shortPreamble = rc_info->ri_shortPreamble; uint8_t rate; int i; Modified: soc2013/ccqin/head/sys/net80211/ieee80211_ratectl.h ============================================================================== --- soc2013/ccqin/head/sys/net80211/ieee80211_ratectl.h Tue Aug 13 08:12:57 2013 (r255871) +++ soc2013/ccqin/head/sys/net80211/ieee80211_ratectl.h Tue Aug 13 09:28:00 2013 (r255872) @@ -83,6 +83,24 @@ uint16_t max4msframelen; }; +/* */ +struct ieee80211_rc_info { + struct ieee80211_rc_series ri_rc[IEEE80211_RATECTL_NUM]; + int ri_framelen; + int ri_shortPreamble; + + /* TX info */ + int ri_success; /* TX success or not */ + int ri_okcnt; /* TX ok with or without retry */ + int ri_failcnt; /* TX retry-fail count */ + int ri_txcnt; /* TX count */ + int ri_retrycnt; /* TX retry count */ + int ri_shortretry; + int ri_longretry; + int ri_finaltsi; + int ri_txrate; /* hw tx rate */ +}; + struct ieee80211_ratectl { const char *ir_name; uint32_t ir_capabilities; /* hardware capabilities offered to rc */ @@ -94,8 +112,7 @@ void (*ir_node_init)(struct ieee80211_node *); void (*ir_node_deinit)(struct ieee80211_node *); int (*ir_rate)(struct ieee80211_node *, void *, uint32_t); - void (*ir_rates)(struct ieee80211_node *, struct ieee80211_rc_series *, - int, size_t); + void (*ir_rates)(struct ieee80211_node *, struct ieee80211_rc_info *); void (*ir_tx_complete)(const struct ieee80211vap *, const struct ieee80211_node *, int, void *, void *); @@ -110,7 +127,7 @@ void ieee80211_ratectl_init(struct ieee80211vap *, uint32_t); void ieee80211_ratectl_set(struct ieee80211vap *, int); void ieee80211_ratectl_complete_rcflags(const struct ieee80211_node *, - struct ieee80211_rc_series *, int) + struct ieee80211_rc_info*) MALLOC_DECLARE(M_80211_RATECTL); @@ -145,14 +162,12 @@ } static void __inline -ieee80211_ratectl_rates(struct ieee80211_node *ni, struct ieee80211_rc_series *rc, - int shortPreamble, size_t frameLen) +ieee80211_ratectl_rates(struct ieee80211_node *ni, struct ieee80211_rc_info *rc_info) { const struct ieee80211vap *vap = ni->ni_vap; - vap->iv_rate->ir_rates(ni, rc, shortPreamble, frameLen); - - ieee80211_ratectl_complete_rcflags(ni, rc, shortPreamble); + vap->iv_rate->ir_rates(ni, rc_info); + ieee80211_ratectl_complete_rcflags(ni, rc_info); } static void __inline Modified: soc2013/ccqin/head/sys/net80211/ieee80211_rc_sample.c ============================================================================== --- soc2013/ccqin/head/sys/net80211/ieee80211_rc_sample.c Tue Aug 13 08:12:57 2013 (r255871) +++ soc2013/ccqin/head/sys/net80211/ieee80211_rc_sample.c Tue Aug 13 09:28:00 2013 (r255872) @@ -73,7 +73,7 @@ .ir_node_init = sample_node_init, .ir_node_deinit = sample_node_deinit, .ir_rate = sample_rate, - .ir_rates = NULL, + .ir_rates = sample_rates, .ir_tx_complete = sample_tx_complete, .ir_tx_update = sample_tx_update, .ir_setinterval = sample_setinterval, @@ -230,7 +230,7 @@ san->stats[y][rix].ewma_pct = 0; san->stats[y][rix].perfect_tx_time = - calc_usecs_unicast_packet(size, rix, 0, 0, + calc_usecs_unicast_packet(vap, size, rix, 0, 0, (ni->ni_chw == 40)); san->stats[y][rix].average_tx_time = san->stats[y][rix].perfect_tx_time; @@ -778,16 +778,252 @@ } static void +sample_rates(struct ieee80211_node *ni, struct ieee80211_rc_info *rc_info) +{ + struct ieee80211_sample_node *san = ni->ni_rctls; + uint8_t rix0 = sample_rate(ni, NULL, 0); + const struct txschedule *sched = &san->sched[rix0]; + struct ieee80211_rc_series *rc = rc_info->ri_rc; + + KASSERT(rix0 == sched->r0, ("rix0 (%x) != sched->r0 (%x)!\n", + rix0, sched->r0)); + /* XXX */ + rc[0].flags = rc[1].flags = rc[2].flags = rc[3].flags = 0; + + rc[0].rix = sched->r0; + rc[1].rix = sched->r1; + rc[2].rix = sched->r2; + rc[3].rix = sched->r3; + + rc[0].tries = sched->t0; + rc[1].tries = sched->t1; + rc[2].tries = sched->t2; + rc[3].tries = sched->t3; +} + +static void +update_stats(const struct ieee80211vap *vap, + const struct ieee80211_node *ni, + 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 nframes, int nbad) +{ + struct ieee80211_sample_node *san = ni->ni_rctls; + struct ieee80211_sample *sample = san->san_sample; + + const int size_bin = size_to_bin(frame_size); + const int size = bin_to_size(size_bin); + + int is_ht40 = ieee80211_ratectl_hascap_cw40(vap, ni); + int tt, tries_so_far; + int pct; + + if (!IS_RATE_DEFINED(san, rix0)) + return; + tt = calc_usecs_unicast_packet(vap, size, rix0, short_tries, + MIN(tries0, tries) - 1, is_ht40); + tries_so_far = tries0; + + if (tries1 && tries_so_far < tries) { + if (!IS_RATE_DEFINED(san, rix1)) + return; + tt += calc_usecs_unicast_packet(vap, 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(san, rix2)) + return; + tt += calc_usecs_unicast_packet(vap, 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(san, rix3)) + return; + tt += calc_usecs_unicast_packet(vap, size, rix3, short_tries, + MIN(tries3 + tries_so_far, tries) - tries_so_far - 1, is_ht40); + } + + if (san->stats[size_bin][rix0].total_packets < sample->sanple_smoothing_minpackets) { + /* just average the first few packets */ + int avg_tx = san->stats[size_bin][rix0].average_tx_time; + int packets = san->stats[size_bin][rix0].total_packets; + san->stats[size_bin][rix0].average_tx_time = (tt+(avg_tx*packets))/(packets+nframes); + } else { + /* use a ewma */ + san->stats[size_bin][rix0].average_tx_time = + ((san->stats[size_bin][rix0].average_tx_time * sample->sanple_smoothing_rate) + + (tt * (100 - sample->sanple_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) { + san->stats[size_bin][rix0].successive_failures += nbad; + + } else { + san->stats[size_bin][rix0].packets_acked += (nframes - nbad); + san->stats[size_bin][rix0].successive_failures = 0; + } + san->stats[size_bin][rix0].tries += tries; + san->stats[size_bin][rix0].last_tx = ticks; + san->stats[size_bin][rix0].total_packets += nframes; + + /* update EWMA for this rix */ + + /* Calculate percentage based on current rate */ + if (nframes == 0) + nframes = nbad = 1; + pct = ((nframes - nbad) * 1000) / nframes; + + if (san->stats[size_bin][rix0].total_packets < + sample->sanple_smoothing_minpackets) { + /* just average the first few packets */ + int a_pct = (san->stats[size_bin][rix0].packets_acked * 1000) / + (san->stats[size_bin][rix0].total_packets); + san->stats[size_bin][rix0].ewma_pct = a_pct; + } else { + /* use a ewma */ + san->stats[size_bin][rix0].ewma_pct = + ((san->stats[size_bin][rix0].ewma_pct * sample->sanple_smoothing_rate) + + (pct * (100 - sample->sanple_smoothing_rate))) / 100; + } + + if (rix0 == san->current_sample_rix[size_bin]) { + san->sample_tt[size_bin] = tt; + san->current_sample_rix[size_bin] = -1; + } +} + +static void sample_tx_complete(const struct ieee80211vap *vap, const struct ieee80211_node *ni, int ok, - void *arg1, void *arg2 __unused) + void *arg1, void *arg2) { + struct ieee80211_sample_node *san = ni->ni_rctls; + const struct ieee80211_rate_table *rt = ieee80211_get_ratetable(vap->iv_ic->ic_curchan); + + /* XXX need to change arg2 to pointer of ieee80211_rc_info */ + struct ieee80211_rc_info *rc_info = (struct ieee80211_rc_info*)arg2; + + int final_rix, short_tries, long_tries; + int nframes, nbad; + int frame_size, mrr; + + final_rix = rt->rateCodeToIndex[rc_info->ri_txrate]; + short_tries = rc_info->ri_shortretry; + /* XXX why plus 1 here? */ + long_tries = rc_info->ri_longretry + 1; + + nframes = rc_info->ri_txcnt; + nbad = rc_info->ri_failcnt; + + frame_size = rc_info->ri_framelen; + mrr = 0; + + if (nframes == 0) { + return; + } + + if (frame_size == 0) /* NB: should not happen */ + frame_size = 1500; + + if (san->ratemask == 0) { + return; + } + + if (vap->iv_rate->ir_capabilities & IEEE80211_RATECTL_CAP_MRR) + mrr = 1; + /* XXX check HT protmode too */ + if (mrr && !(vap->iv_rate->ir_capabilities & IEEE80211_RATECTL_CAP_MRRPROT)) + mrr = 0; + + if (!mrr || rc_info->ri_finaltsi == 0) { + if (!IS_RATE_DEFINED(san, final_rix)) { + return; + } + /* + * Only one rate was used; optimize work. + */ + update_stats(vap, ni, frame_size, + final_rix, long_tries, + 0, 0, + 0, 0, + 0, 0, + short_tries, long_tries, + nframes, nbad); + + } else { + int finalTSIdx = rc_info->ri_finaltsi; + int i; + + /* + * 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(vap, ni, 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, + nframes, nbad); + long_tries -= rc[0].tries; + } + + if (rc[1].tries && finalTSIdx > 0) { + update_stats(vap, ni, 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, + nframes, nbad); + long_tries -= rc[1].tries; + } + + if (rc[2].tries && finalTSIdx > 1) { + update_stats(vap, ni, frame_size, + rc[2].rix, rc[2].tries, + rc[3].rix, rc[3].tries, + 0, 0, + 0, 0, + short_tries, long_tries, + nframes, nbad); + long_tries -= rc[2].tries; + } + + if (rc[3].tries && finalTSIdx > 2) { + update_stats(vap, ni, frame_size, + rc[3].rix, rc[3].tries, + 0, 0, + 0, 0, + 0, 0, + short_tries, long_tries, + nframes, nbad); + } + } } static void sample_tx_update(const struct ieee80211vap *vap, const struct ieee80211_node *ni, void *arg1, void *arg2, void *arg3) { + /* nothing here. */ } static void Modified: soc2013/ccqin/head/sys/net80211/ieee80211_rc_sample.h ============================================================================== --- soc2013/ccqin/head/sys/net80211/ieee80211_rc_sample.h Tue Aug 13 08:12:57 2013 (r255871) +++ soc2013/ccqin/head/sys/net80211/ieee80211_rc_sample.h Tue Aug 13 09:28:00 2013 (r255872) @@ -139,14 +139,145 @@ return NUM_PACKET_SIZE_BINS-1; } +static uint32_t sample_pkt_txtime(const struct ieee80211_rate_table *rt, + uint32_t frameLen, uint16_t rateix, int isht40, int isShortPreamble) +{ + uint8_t rc; + int numStreams; + + rc = rt->info[rateix].rateCode; + + /* Legacy rate? Return the old way */ + if (! IS_HT_RATE(rc)) + return ieee80211_compute_duration(rt, frameLen, rateix, isShortPreamble); + + /* 11n frame - extract out the number of spatial streams */ + numStreams = HT_RC_2_STREAMS(rc); + KASSERT(numStreams > 0 && numStreams <= 4, + ("number of spatial streams needs to be 1..3: MCS rate 0x%x!", + rateix)); + + return ieee80211_compute_duration_ht(frameLen, rc, numStreams, isht40, isShortPreamble); +} + +#define WIFI_CW_MIN 31 +#define WIFI_CW_MAX 1023 + /* * Calculate the transmit duration of a frame. */ -static unsigned calc_usecs_unicast_packet(int length, +static unsigned calc_usecs_unicast_packet(const struct ieee80211vap *vap, + int length, int rix, int short_retries, int long_retries, int is_ht40) { - /* XXX not done yet */ + const struct ieee80211_rate_table *rt = ieee80211_get_ratetable(vap->iv_ic->ic_curchan); + struct ieee80211com *ic = vap->iv_ic; + int curmode = ieee80211_chan2mode(vap->iv_ic->ic_curchan); + + unsigned t_slot, t_difs, t_sifs; + int rts, cts; + int tt, x, cw, cix; + + int tt = 0; + int x = 0; + int cw = WIFI_CW_MIN; + + KASSERT(rt != NULL, ("no rate table, mode %u", curmode)); + + if (rix >= rt->rateCount) { + printf("bogus rix %d, max %u, mode %u\n", + rix, rt->rateCount, curmode); + return 0; + } + cix = rt->info[rix].controlRate; + /* + * XXX getting mac/phy level timings should be fixed for turbo + * rates, and there is probably a way to get this from the + * hal... + */ + switch (rt->info[rix].phy) { + case IEEE80211_T_OFDM: + t_slot = 9; + t_sifs = 16; + t_difs = 28; + /* fall through */ + case IEEE80211_T_TURBO: + t_slot = 9; + t_sifs = 8; + t_difs = 28; + break; + case IEEE80211_T_HT: + t_slot = 9; + t_sifs = 8; + t_difs = 28; + break; + case IEEE80211_T_DS: + /* fall through to default */ + default: + /* pg 205 ieee.802.11.pdf */ + t_slot = 20; + t_difs = 50; + t_sifs = 10; + } + + rts = cts = 0; + + if ((ic->ic_flags & IEEE80211_F_USEPROT) && + rt->info[rix].phy == IEEE80211_T_OFDM) { + if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) + rts = 1; + else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) + cts = 1; + + int protrix; + if (curmode == IEEE80211_MODE_11G) + protrix = rt->rateCodeToIndex[2*2]; + else + protrix = rt->rateCodeToIndex[2*1]; + if (0xff == protrix) + protrix = 0; + + cix = rt->info[protrix].controlRate; + } + + if (0 /*length > ic->ic_rtsthreshold */) { + rts = 1; + } + + if (rts || cts) { + int ctsrate; + int ctsduration = 0; + + /* NB: this is intentionally not a runtime check */ + KASSERT(cix < rt->rateCount, + ("bogus cix %d, max %u, mode %u\n", cix, rt->rateCount, + curmode)); + + ctsrate = rt->info[cix].rateCode | rt->info[cix].shortPreamble; + if (rts) /* SIFS + CTS */ + ctsduration += rt->info[cix].spAckDuration; + + /* XXX assumes short preamble */ + ctsduration += sample_pkt_txtime(rt, length, rix, is_ht40, 0); + + if (cts) /* SIFS + ACK */ + ctsduration += rt->info[cix].spAckDuration; + + tt += (short_retries + 1) * ctsduration; + } + tt += t_difs; + + /* XXX assumes short preamble */ + tt += (long_retries+1)*sample_pkt_txtime(rt, length, rix, is_ht40, 0); + + tt += (long_retries+1)*(t_sifs + rt->info[rix].spAckDuration); + + for (x = 0; x <= short_retries + long_retries; x++) { + cw = MIN(WIFI_CW_MAX, (cw + 1) * 2); + tt += (t_slot * cw/2); + } + return tt; } #endif /* _NET80211_IEEE80211_RATECTL_SAMPLE_H_ */