socsvn commit: r255872 - soc2013/ccqin/head/sys/net80211
ccqin at FreeBSD.org
ccqin at FreeBSD.org
Tue Aug 13 09:28:00 UTC 2013
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_ */
More information about the svn-soc-all
mailing list