Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 13 Aug 2013 09:28:00 GMT
From:      ccqin@FreeBSD.org
To:        svn-soc-all@FreeBSD.org
Subject:   socsvn commit: r255872 - soc2013/ccqin/head/sys/net80211
Message-ID:  <201308130928.r7D9S0a4058732@socsvn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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_ */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201308130928.r7D9S0a4058732>