Date: Mon, 5 Aug 2013 23:58:33 +0800 From: Chenchong Qin <qinchenchong@gmail.com> To: Adrian Chadd <adrian@freebsd.org> Cc: freebsd-wireless@freebsd.org Subject: Re: Chenchong's work on net80211_ratectl Message-ID: <CAFnsE3eMwX-GiRzJt8jk4r9mxwSAQkcrDwk%2BnWVG7q6dabeA3A@mail.gmail.com> In-Reply-To: <CAJ-VmokF6hPtg9FoEdeJXLLaZRNhzd=nr_o6nHE%2BjYiQKTg3zQ@mail.gmail.com> References: <CAFnsE3dYdPf5yGTFH683Q1Zh0mc-g%2B_YtCTraNNt28z2vBoSKw@mail.gmail.com> <CAJ-Vmom4sY7jcNwWmJkrDwfWjsok2fk8UEwTi5A=egj1JyerLw@mail.gmail.com> <CAFnsE3cyg=msBfQqqKUMmLABSL=j24VoMBwbBjxQ6b7Dyy7Mqg@mail.gmail.com> <CAJ-Vmo=k8NddAYyAJCkx4eOaA_8XsSxg6uKrdddx%2BgmeT%2BX9KA@mail.gmail.com> <CAFnsE3eaOyRcO3LXSi3L=jbzpyMv5Nt_jRGKt_mmA0WV-EV5vA@mail.gmail.com> <CAJ-VmokdxLhK5x6kO=jJzk-dv61EDK-ZgmndOimoyWWf76HiZA@mail.gmail.com> <CAJ-VmonMjR5iVTMVN9532d%2BPqOXWNUoZvxPtQir5h=yGxU-XdQ@mail.gmail.com> <CAFnsE3d9nG-X2b=z1srKfTtpxC3w5L%2B6Hg3TbOnAQrJN%2Bt19GA@mail.gmail.com> <CAJ-VmokF6hPtg9FoEdeJXLLaZRNhzd=nr_o6nHE%2BjYiQKTg3zQ@mail.gmail.com>
index | next in thread | previous in thread | raw e-mail
[-- Attachment #1 --]
Hi!
Here is my work done these days on porting ath_rate_sample to net80211. It
has not been finished yet. _complete_ and _update_ are to be added.
_complete_ is really a tricky thing. We have to provide rc algos with rc
information
during the frame completion period. Different rc algos may need different
rc
information. What makes things more thornier is that different drivers
provide
different rc information in different ways. So, it seems we need a unified
way to
provide the rc information during completion of a frame.
I'm browsing mac80211 these days to see what Linux do about _complete_.
And,
looking forward to your commets!
Thanks!
Chenchong
On Sat, Aug 3, 2013 at 1:30 AM, Adrian Chadd <adrian@freebsd.org> wrote:
> Well just remember you can always ask me/us questions!
>
> What's your latest diff against -HEAD? Maybe I can start looking at
> including parts of it in the tree.
>
>
>
>
> -adrian
>
> On 2 August 2013 09:17, Chenchong Qin <qinchenchong@gmail.com> wrote:
> > Hi!
> >
> > These days, I'm taking a further look at what Linux done for the
> > _completion_ of a
> > frame. Some updates will be posted here later.
> >
> > And, with ir_rates, we can return/fill an rc array rather than just
> > returning the rix.
> >
> > Thanks!
> >
> > Chenchong
> >
> >
> >
> >
> >
> > On Thu, Aug 1, 2013 at 12:21 AM, Adrian Chadd <adrian@freebsd.org>
> wrote:
> >>
> >> Boo!
> >>
> >> Do you have another update?
> >>
> >>
> >>
> >> -adrian
> >>
> >> On 24 July 2013 06:44, Adrian Chadd <adrian@freebsd.org> wrote:
> >> > On 24 July 2013 06:38, Chenchong Qin <qinchenchong@gmail.com> wrote:
> >> >>
> >> >> My pleasure!
> >> >>
> >> >> It's also against HEAD.
> >> >>
> >> >> Thanks!
> >> >
> >> > Ok. This is looking great!
> >> >
> >> > Next - we need to update the rate control API to now populate an rc
> >> > array rather than just returning the rix.
> >> >
> >> > This is the tricky part - as we're going to have to modify all the
> >> > drivers that use the rate control API to use this.
> >> > Which is fine, as there's only a handful. It's just annoying.
> >> >
> >> > Then we have to provide the rate control information during frame
> >> > _completion_, so the rate control code knows which transmission rates
> >> > succeeded or failed. I'm still not sure what to do about it here.
> >> > Maybe do something like Linux and attach TX rate control and
> >> > completion information as an mbuf tag?
> >> >
> >> > _Then_ we can start doing interesting thing with it. :)
> >> >
> >> >
> >> >
> >> > -adrian
> >
> >
>
[-- Attachment #2 --]
Index: ieee80211_rc_sample.c
===================================================================
--- ieee80211_rc_sample.c (revision 0)
+++ ieee80211_rc_sample.c (revision 255539)
@@ -0,0 +1,926 @@
+/* $FreeBSD: head/sys/dev/ath/ath_rate/sample/sample.c 248573 2013-02-27 04:33:06Z adrian $*/
+
+/*-
+ * Copyright (c) 2013 Chenchong Qin <ccqin@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#include "opt_wlan.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_ht.h>
+#include <net80211/ieee80211_ratectl.h>
+#include <net80211/ieee80211_rc_sample.h>
+#include <net80211/ieee80211_rc_sample_txsched.h>
+
+static void sample_init(struct ieee80211vap *);
+static void sample_deinit(struct ieee80211vap *);
+static void sample_node_init(struct ieee80211_node *);
+static void sample_node_deinit(struct ieee80211_node *);
+static int sample_rate(struct ieee80211_node *, void *, uint32_t);
+static void sample_tx_complete(const struct ieee80211vap *,
+ const struct ieee80211_node *, int,
+ void *, void *);
+static void sample_tx_update(const struct ieee80211vap *vap,
+ const struct ieee80211_node *, void *, void *, void *);
+static void sample_setinterval(const struct ieee80211vap *, int);
+
+/* number of references from net80211 layer */
+static int nrefs = 0;
+
+static const struct ieee80211_ratectl sample = {
+ .ir_name = "sample",
+ .ir_attach = NULL,
+ .ir_detach = NULL,
+ .ir_init = sample_init,
+ .ir_deinit = sample_deinit,
+ .ir_node_init = sample_node_init,
+ .ir_node_deinit = sample_node_deinit,
+ .ir_rate = sample_rate,
+ .ir_rates = NULL,
+ .ir_tx_complete = sample_tx_complete,
+ .ir_tx_update = sample_tx_update,
+ .ir_setinterval = sample_setinterval,
+};
+IEEE80211_RATECTL_MODULE(sample, 1);
+IEEE80211_RATECTL_ALG(sample, IEEE80211_RATECTL_SAMPLE, sample);
+
+static void
+sample_init(struct ieee80211vap *vap)
+{
+ struct ieee80211_sample *sample;
+
+ KASSERT(vap->iv_rs == NULL, ("%s called multiple times", __func__));
+
+ sample = vap->iv_rs = malloc(sizeof(struct ieee80211_sample),
+ M_80211_RATECTL, M_NOWAIT|M_ZERO);
+ if (sample == NULL) {
+ if_printf(vap->iv_ifp, "couldn't alloc ratectl structure\n");
+ return;
+ }
+ sample->sample_smoothing_rate = 75; /* ewma percentage ([0..99]) */
+ sample->sample_smoothing_minpackets = 100 / (100 - sample->sample_smoothing_rate);
+ sample->sample_rate = 10; /* %time to try diff tx rates */
+ sample->sample_max_successive_failures = 3; /* threshold for rate sampling*/
+ sample->sample_stale_failure_timeout = 10 * hz; /* 10 seconds */
+ sample->sample_min_switch = hz; /* 1 second */
+ sample_setinterval(vap, 500 /* ms */); /* actually do nothing */
+ sample_sysctlattach(vap, vap->iv_sysctl, vap->iv_oid);
+}
+
+static void
+sample_deinit(struct ieee80211vap *vap)
+{
+ free(vap->iv_rs, M_80211_RATECTL);
+}
+
+// XXX should be shared by ratectl algos
+static int
+sample_node_is_11n(struct ieee80211_node *ni)
+{
+
+ if (ni->ni_chan == NULL)
+ return (0);
+ if (ni->ni_chan == IEEE80211_CHAN_ANYC)
+ return (0);
+ return (IEEE80211_IS_CHAN_HT(ni->ni_chan));
+}
+
+static const struct txschedule *mrr_schedules[IEEE80211_MODE_MAX+2] = {
+ NULL, /* IEEE80211_MODE_AUTO */
+ series_11a, /* IEEE80211_MODE_11A */
+ series_11g, /* IEEE80211_MODE_11B */
+ series_11g, /* IEEE80211_MODE_11G */
+ NULL, /* IEEE80211_MODE_FH */
+ series_11a, /* IEEE80211_MODE_TURBO_A */
+ series_11g, /* IEEE80211_MODE_TURBO_G */
+ series_11a, /* IEEE80211_MODE_STURBO_A */
+ series_11na, /* IEEE80211_MODE_11NA */
+ series_11ng, /* IEEE80211_MODE_11NG */
+ series_half, /* IEEE80211_MODE_HALF */
+ series_quarter, /* IEEE80211_MODE_QUARTER */
+};
+
+static void
+sample_node_init(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 ieee80211vap *vap = ni->ni_vap;
+ struct ieee80211_sample *sample = vap->iv_rs;
+ struct ieee80211_sample_node *san = NULL;
+ const struct ieee80211_rate_table *rt = ieee80211_get_ratetable(vap->iv_ic->ic_curchan);
+ enum ieee80211_phymode curmode = ieee80211_chan2mode(vap->iv_ic->ic_curchan);
+ int x, y, rix;
+
+ if (ni->ni_rctls == NULL) {
+ ni->ni_rctls = san = malloc(sizeof(struct ieee80211_sample_node),
+ M_80211_RATECTL, M_NOWAIT|M_ZERO);
+ if (san == NULL) {
+ if_printf(vap->iv_ifp, "couldn't alloc per-node ratectl "
+ "structure\n");
+ return;
+ }
+ } else
+ san = ni->ni_rctls;
+ san->san_sample = sample;
+
+ KASSERT(rt != NULL, ("no rate table, mode %u", curmode));
+
+ san->sched = mrr_schedules[curmode];
+ KASSERT(san->sched != NULL, ("no mrr schedule for mode %u", curmode));
+
+ san->static_rix = -1;
+ sample_update_static_rix(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.
+ */
+ san->ratemask = 0;
+
+ /* MCS rates */
+ if (ni->ni_flags & IEEE80211_NODE_HT) {
+ for (x = 0; x < ni->ni_htrates.rs_nrates; x++) {
+ rix = rt->rateCodeToIndex[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));
+ san->ratemask |= (uint64_t) 1<<rix;
+ }
+ }
+
+ /* Legacy rates */
+ for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
+ rix = rt->rateCodeToIndex[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));
+ san->ratemask |= (uint64_t) 1<<rix;
+ }
+
+ for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
+ int size = bin_to_size(y);
+ uint64_t mask;
+
+ san->packets_sent[y] = 0;
+ san->current_sample_rix[y] = -1;
+ san->last_sample_rix[y] = 0;
+ /* XXX start with first valid rate */
+ san->current_rix[y] = ffs(san->ratemask)-1;
+
+ /*
+ * Initialize the statistics buckets; these are
+ * indexed by the rate code index.
+ */
+ for (rix = 0, mask = san->ratemask; mask != 0; rix++, mask >>= 1) {
+ if ((mask & 1) == 0) /* not a valid rate */
+ continue;
+ san->stats[y][rix].successive_failures = 0;
+ san->stats[y][rix].tries = 0;
+ san->stats[y][rix].total_packets = 0;
+ san->stats[y][rix].packets_acked = 0;
+ san->stats[y][rix].last_tx = 0;
+ san->stats[y][rix].ewma_pct = 0;
+
+ san->stats[y][rix].perfect_tx_time =
+ calc_usecs_unicast_packet(size, rix, 0, 0,
+ (ni->ni_chw == 40));
+ san->stats[y][rix].average_tx_time =
+ san->stats[y][rix].perfect_tx_time;
+ }
+ }
+
+ /* set the visible bit-rate */
+ if (san->static_rix != -1)
+ ni->ni_txrate = DOT11RATE(san->static_rix);
+ else
+ ni->ni_txrate = RATE(0);
+#undef RATE
+#undef DOT11RATE
+#undef MCS
+}
+
+static void
+sample_node_deinit(struct ieee80211_node *ni)
+{
+ free(ni->ni_rctls, M_80211_RATECTL);
+}
+
+static int
+dot11rate(const ieee80211_rate_table *rt, int rix)
+{
+ if (rix < 0)
+ return -1;
+ return rt->info[rix].phy == IEEE80211_T_HT ?
+ rt->info[rix].dot11Rate : (rt->info[rix].dot11Rate & IEEE80211_RATE_VAL) / 2;
+}
+
+static const char *
+dot11rate_label(const ieee80211_rate_table *rt, int rix)
+{
+ if (rix < 0)
+ return "";
+ return rt->info[rix].phy == IEEE80211_T_HT ? "MCS" : "Mb ";
+}
+
+/*
+ * Return the rix with the lowest average_tx_time,
+ * or -1 if all the average_tx_times are 0.
+ */
+static __inline int
+pick_best_rate(const struct ieee80211_node *ni, const struct ieee80211_rate_table *rt,
+ int size_bin, int require_acked_before)
+{
+ struct ieee80211_sample_node *san = ni->ni_rctls;
+ int best_rate_rix, best_rate_tt, best_rate_pct;
+ uint64_t mask;
+ int rix, tt, pct;
+
+ best_rate_rix = 0;
+ best_rate_tt = 0;
+ best_rate_pct = 0;
+
+ for (mask = san->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) {
+ if ((mask & 1) == 0) /* not a supported rate */
+ continue;
+
+ /* Don't pick a non-HT rate for a HT node */
+ if ((ni->ni_flags & IEEE80211_NODE_HT) &&
+ (rt->info[rix].phy != IEEE80211_T_HT)) {
+ continue;
+ }
+
+ tt = san->stats[size_bin][rix].average_tx_time;
+ if (tt <= 0 ||
+ (require_acked_before &&
+ !san->stats[size_bin][rix].packets_acked))
+ continue;
+
+ /* Calculate percentage if possible */
+ if (san->stats[size_bin][rix].total_packets > 0) {
+ pct = san->stats[size_bin][rix].ewma_pct;
+ } else {
+ /* XXX for now, assume 95% ok */
+ pct = 95;
+ }
+
+ /* don't use a bit-rate that has been failing */
+ if (san->stats[size_bin][rix].successive_failures > 3)
+ continue;
+
+ /*
+ * For HT, Don't use a bit rate that is much more
+ * lossy than the best.
+ *
+ * XXX this isn't optimal; it's just designed to
+ * eliminate rates that are going to be obviously
+ * worse.
+ */
+ if (ni->ni_flags & IEEE80211_NODE_HT) {
+ if (best_rate_pct > (pct + 50))
+ continue;
+ }
+
+ /*
+ * For non-MCS rates, use the current average txtime for
+ * comparison.
+ */
+ if (! (ni->ni_flags & IEEE80211_NODE_HT)) {
+ if (best_rate_tt == 0 || tt <= best_rate_tt) {
+ best_rate_tt = tt;
+ best_rate_rix = rix;
+ best_rate_pct = pct;
+ }
+ }
+
+ /*
+ * Since 2 stream rates have slightly higher TX times,
+ * allow a little bit of leeway. This should later
+ * be abstracted out and properly handled.
+ */
+ if (ni->ni_flags & IEEE80211_NODE_HT) {
+ if (best_rate_tt == 0 || (tt * 8 <= best_rate_tt * 10)) {
+ best_rate_tt = tt;
+ best_rate_rix = rix;
+ best_rate_pct = pct;
+ }
+ }
+ }
+ return (best_rate_tt ? best_rate_rix : -1);
+}
+
+/*
+ * Pick a good "random" bit-rate to sample other than the current one.
+ */
+static __inline int
+pick_sample_rate(const struct ieee80211_node *ni, const ieee80211_rate_table *rt,
+ int size_bin)
+{
+#define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)
+#define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS)
+ struct ieee80211_sample_node *san = ni->ni_rctls;
+ struct ieee80211_sample *sample = san->san_sample;
+ int current_rix, rix;
+ unsigned current_tt;
+ uint64_t mask;
+
+ current_rix = san->current_rix[size_bin];
+ if (current_rix < 0) {
+ /* no successes yet, send at the lowest bit-rate */
+ /* XXX should return MCS0 if HT */
+ return 0;
+ }
+
+ current_tt = san->stats[size_bin][current_rix].average_tx_time;
+
+ rix = san->last_sample_rix[size_bin]+1; /* next sample rate */
+ mask = san->ratemask &~ ((uint64_t) 1<<current_rix);/* don't sample current rate */
+ while (mask != 0) {
+ if ((mask & ((uint64_t) 1<<rix)) == 0) { /* not a supported rate */
+ nextrate:
+ if (++rix >= rt->rateCount)
+ rix = 0;
+ continue;
+ }
+
+ /*
+ * The following code stops trying to sample
+ * non-MCS rates when speaking to an MCS node.
+ * However, at least for CCK rates in 2.4GHz mode,
+ * the non-MCS rates MAY actually provide better
+ * PER at the very far edge of reception.
+ *
+ * However! Until ath_rate_form_aggr() grows
+ * some logic to not form aggregates if the
+ * selected rate is non-MCS, this won't work.
+ *
+ * So don't disable this code until you've taught
+ * ath_rate_form_aggr() to drop out if any of
+ * the selected rates are non-MCS.
+ */
+#if 1
+ /* if the node is HT and the rate isn't HT, don't bother sample */
+ if ((ni->ni_flags & IEEE80211_NODE_HT) &&
+ (rt->info[rix].phy != IEEE80211_T_HT)) {
+ mask &= ~((uint64_t) 1<<rix);
+ goto nextrate;
+ }
+#endif
+
+ /* this bit-rate is always worse than the current one */
+ if (san->stats[size_bin][rix].perfect_tx_time > current_tt) {
+ mask &= ~((uint64_t) 1<<rix);
+ goto nextrate;
+ }
+
+ /* rarely sample bit-rates that fail a lot */
+ if (san->stats[size_bin][rix].successive_failures > sample->sample_max_successive_failures &&
+ ticks - san->stats[size_bin][rix].last_tx < sample->sample_stale_failure_timeout) {
+ mask &= ~((uint64_t) 1<<rix);
+ goto nextrate;
+ }
+
+ /*
+ * For HT, only sample a few rates on either side of the
+ * current rix; there's quite likely a lot of them.
+ */
+ if (ni->ni_flags & IEEE80211_NODE_HT) {
+ if (rix < (current_rix - 3) ||
+ rix > (current_rix + 3)) {
+ mask &= ~((uint64_t) 1<<rix);
+ goto nextrate;
+ }
+ }
+
+ /* Don't sample more than 2 rates higher for rates > 11M for non-HT rates */
+ if (! (ni->ni_flags & IEEE80211_NODE_HT)) {
+ if (DOT11RATE(rix) > 2*11 && rix > current_rix + 2) {
+ mask &= ~((uint64_t) 1<<rix);
+ goto nextrate;
+ }
+ }
+
+ san->last_sample_rix[size_bin] = rix;
+ return rix;
+ }
+ return current_rix;
+#undef DOT11RATE
+#undef MCS
+}
+
+static int
+sample_get_static_rix(const struct ieee80211_node *ni)
+{
+#define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL)
+#define MCS(_ix) (ni->ni_htrates.rs_rates[_ix] | IEEE80211_RATE_MCS)
+ struct ieee80211vap *vap = ni->ni_vap;
+ const struct ieee80211_rate_table *rt = ieee80211_get_ratetable(vap->iv_ic->ic_curchan);
+ const struct ieee80211_txparam *tp = ni->ni_txparms;
+ int srate;
+
+ /* Check MCS rates */
+ for (srate = ni->ni_htrates.rs_nrates - 1; srate >= 0; srate--) {
+ if (MCS(srate) == tp->ucastrate)
+ return rt->rateCodeToIndex[tp->ucastrate];
+ }
+
+ /* Check legacy rates */
+ for (srate = ni->ni_rates.rs_nrates - 1; srate >= 0; srate--) {
+ if (RATE(srate) == tp->ucastrate)
+ return rt->rateCodeToIndex[tp->ucastrate];
+ }
+ return -1;
+#undef RATE
+#undef MCS
+}
+
+static void
+sample_update_static_rix(struct ieee80211_node *ni)
+{
+ struct ieee80211_sample_node *san = ni->ni_rctls;
+ const struct ieee80211_txparam *tp = ni->ni_txparms;
+
+ 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.
+ */
+ san->static_rix = sample_get_static_rix(ni);
+ } else {
+ san->static_rix = -1;
+ }
+}
+
+/*
+ * Pick a non-HT rate to begin using.
+ */
+static int
+sample_pick_seed_rate_legacy(const struct ieee80211_node *ni, int frameLen)
+{
+#define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct ieee80211_sample_node *san = ni->ni_rctls;
+ const struct ieee80211_rate_table *rt = ieee80211_get_ratetable(vap->iv_ic->ic_curchan);
+
+ const int size_bin = size_to_bin(frameLen);
+ int rix = -1;
+
+ /* no packet has been sent successfully yet */
+ for (rix = rt->rateCount-1; rix > 0; rix--) {
+ if ((san->ratemask & ((uint64_t) 1<<rix)) == 0)
+ continue;
+
+ /* Skip HT rates */
+ if (rt->info[rix].phy == IEEE80211_T_HT)
+ continue;
+
+ /*
+ * Pick the highest rate <= 36 Mbps
+ * that hasn't failed.
+ */
+ if (DOT11RATE(rix) <= 72 &&
+ san->stats[size_bin][rix].successive_failures == 0) {
+ break;
+ }
+ }
+ return rix;
+#undef DOT11RATE
+}
+
+/*
+ * Pick a HT rate to begin using.
+ *
+ * Don't use any non-HT rates; only consider HT rates.
+ */
+static int
+sample_pick_seed_rate_ht(const struct ieee80211_node *ni, int frameLen)
+{
+#define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS)
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct ieee80211_sample_node *san = ni->ni_rctls;
+ const struct ieee80211_rate_table *rt = ieee80211_get_ratetable(vap->iv_ic->ic_curchan);
+
+ const int size_bin = size_to_bin(frameLen);
+ int rix = -1, ht_rix = -1;
+
+ /* no packet has been sent successfully yet */
+ for (rix = rt->rateCount-1; rix > 0; rix--) {
+ /* Skip rates we can't use */
+ if ((san->ratemask & ((uint64_t) 1<<rix)) == 0)
+ continue;
+
+ /* Keep a copy of the last seen HT rate index */
+ if (rt->info[rix].phy == IEEE80211_T_HT)
+ ht_rix = rix;
+
+ /* Skip non-HT rates */
+ if (rt->info[rix].phy != IEEE80211_T_HT)
+ continue;
+
+ /*
+ * Pick a medium-speed rate regardless of stream count
+ * which has not seen any failures. Higher rates may fail;
+ * we'll try them later.
+ */
+ if (((MCS(rix) & 0x7) <= 4) &&
+ san->stats[size_bin][rix].successive_failures == 0) {
+ break;
+ }
+ }
+
+ /*
+ * If all the MCS rates have successive failures, rix should be
+ * > 0; otherwise use the lowest MCS rix (hopefully MCS 0.)
+ */
+ return MAX(rix, ht_rix);
+#undef MCS
+}
+
+static const struct ieee80211_rateset *
+sample_get_rateset(const struct ieee80211_node *ni)
+{
+ const struct ieee80211_rateset *rs = NULL;
+ /* 11n or not? Pick the right rateset */
+ if (sample_node_is_11n(ni)) {
+ /* XXX ew */
+ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
+ "%s: 11n node", __func__);
+ rs = (struct ieee80211_rateset *) &ni->ni_htrates;
+ } else {
+ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
+ "%s: non-11n node", __func__);
+ rs = &ni->ni_rates;
+ }
+ return rs;
+}
+
+static int
+sample_rate(struct ieee80211_node *ni, void *arg __unused, uint32_t iarg __unused)
+{
+#define DOT11RATE(ix) (rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)
+#define MCS(ix) (rt->info[ix].dot11Rate | IEEE80211_RATE_MCS)
+#define RATE(ix) (DOT11RATE(ix) / 2)
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct ieee80211_sample_node *san = ni->ni_rctls;
+ struct ieee80211_sample *sample = san->san_sample;
+ const struct ieee80211_rate_table *rt = ieee80211_get_ratetable(vap->iv_ic->ic_curchan);
+
+ int rix, mrr, best_rix, change_rates;
+ unsigned average_tx_time;
+
+ size_t frameLen = (size_t)iarg;
+ const int size_bin = size_to_bin(frameLen);
+
+ sample_update_static_rix(ni);
+
+ if (san->static_rix != -1) {
+ rix = san->static_rix;
+ goto done;
+ }
+
+ if (vap->iv_rate->ir_capabilities & IEEE80211_RATECTL_CAP_MRR)
+ mrr = 1;
+ if (!(vap->iv_rate->ir_capabilities & IEEE80211_RATECTL_CAP_MRRPROT))
+ mrr = 0;
+
+ best_rix = pick_best_rate(ni, rt, size_bin, !mrr);
+ if (best_rix >= 0) {
+ average_tx_time = san->stats[size_bin][best_rix].average_tx_time;
+ } else {
+ average_tx_time = 0;
+ }
+
+ /*
+ * Limit the time measuring the performance of other tx
+ * rates to sample_rate% of the total transmission time.
+ */
+ if (san->sample_tt[size_bin] < average_tx_time * (san->packets_since_sample[size_bin] *
+ sample->sample_rate/100)) {
+ rix = pick_sample_rate(ni, rt, size_bin);
+ IEEE80211_NOTE(vap, IEEE80211_MSG_RATECTL,
+ &ni, "att %d sample_tt %d size %u sample rate %d %s current rate %d %s",
+ average_tx_time,
+ san->sample_tt[size_bin],
+ bin_to_size(size_bin),
+ dot11rate(rt, rix),
+ dot11rate_label(rt, rix),
+ dot11rate(rt, san->current_rix[size_bin]),
+ dot11rate_label(rt, san->current_rix[size_bin]));
+ if (rix != san->current_rix[size_bin]) {
+ san->current_sample_rix[size_bin] = rix;
+ } else {
+ san->current_sample_rix[size_bin] = -1;
+ }
+ san->packets_since_sample[size_bin] = 0;
+ } else {
+ change_rates = 0;
+ if (!san->packets_sent[size_bin] || best_rix == -1) {
+ /* no packet has been sent successfully yet */
+ change_rates = 1;
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ best_rix = sample_pick_seed_rate_ht(ni, frameLen);
+ else
+ best_rix = sample_pick_seed_rate_legacy(ni, frameLen);
+ } else if (san->packets_sent[size_bin] < 20) {
+ /* let the bit-rate switch quickly during the first few packets */
+ IEEE80211_NOTE(vap,
+ IEEE80211_MSG_RATECTL, &ni,
+ "%s: switching quickly..", __func__);
+ change_rates = 1;
+ } else if (ticks - sample->sample_min_switch > san->ticks_since_switch[size_bin]) {
+ /* min_switch seconds have gone by */
+ IEEE80211_NOTE(vap,
+ IEEE80211_MSG_RATECTL, &ni,
+ "%s: min_switch %d > ticks_since_switch %d..",
+ __func__, ticks - sample->sample_min_switch, san->ticks_since_switch[size_bin]);
+ change_rates = 1;
+ } else if ((! (ni->ni_flags & IEEE80211_NODE_HT)) &&
+ (2*average_tx_time < san->stats[size_bin][san->current_rix[size_bin]].average_tx_time)) {
+ /* the current bit-rate is twice as slow as the best one */
+ IEEE80211_NOTE(vap,
+ IEEE80211_MSG_RATECTL, &ni,
+ "%s: 2x att (= %d) < cur_rix att %d",
+ __func__,
+ 2 * average_tx_time, san->stats[size_bin][san->current_rix[size_bin]].average_tx_time);
+ change_rates = 1;
+ } else if ((ni->ni_flags & IEEE80211_NODE_HT)) {
+ int cur_rix = san->current_rix[size_bin];
+ int cur_att = san->stats[size_bin][cur_rix].average_tx_time;
+ /*
+ * If the node is HT, upgrade it if the MCS rate is
+ * higher and the average tx time is within 20% of
+ * the current rate. It can fail a little.
+ *
+ * This is likely not optimal!
+ */
+#if 0
+ printf("cur rix/att %x/%d, best rix/att %x/%d\n",
+ MCS(cur_rix), cur_att, MCS(best_rix), average_tx_time);
+#endif
+ if ((MCS(best_rix) > MCS(cur_rix)) &&
+ (average_tx_time * 8) <= (cur_att * 10)) {
+ IEEE80211_NOTE(vap,
+ IEEE80211_MSG_RATECTL, &ni,
+ "%s: HT: best_rix 0x%d > cur_rix 0x%x, average_tx_time %d, cur_att %d",
+ __func__,
+ MCS(best_rix), MCS(cur_rix), average_tx_time, cur_att);
+ change_rates = 1;
+ }
+ }
+
+ san->packets_since_sample[size_bin]++;
+
+ if (change_rates) {
+ if (best_rix != san->current_rix[size_bin]) {
+ IEEE80211_NOTE(vap,
+ IEEE80211_MSG_RATECTL,
+ &ni,
+"%s: size %d switch rate %d (%d/%d) -> %d (%d/%d) after %d packets mrr %d",
+ __func__,
+ bin_to_size(size_bin),
+ RATE(san->current_rix[size_bin]),
+ san->stats[size_bin][san->current_rix[size_bin]].average_tx_time,
+ san->stats[size_bin][san->current_rix[size_bin]].perfect_tx_time,
+ RATE(best_rix),
+ san->stats[size_bin][best_rix].average_tx_time,
+ san->stats[size_bin][best_rix].perfect_tx_time,
+ san->packets_since_switch[size_bin],
+ mrr);
+ }
+ san->packets_since_switch[size_bin] = 0;
+ san->current_rix[size_bin] = best_rix;
+ san->ticks_since_switch[size_bin] = ticks;
+ /*
+ * Set the visible txrate for this node.
+ */
+ ni->ni_txrate = dot11rate(rt, best_rix);
+ }
+ rix = san->current_rix[size_bin];
+ san->packets_since_switch[size_bin]++;
+ }
+ // *try0 = mrr ? san->sched[rix].t0 : ATH_TXMAXTRY;
+done:
+
+ /*
+ * This bug totally sucks and should be fixed.
+ *
+ * For now though, let's not panic, so we can start to figure
+ * out how to better reproduce it.
+ */
+ if (rix < 0 || rix >= rt->rateCount) {
+ printf("%s: ERROR: rix %d out of bounds (rateCount=%d)\n",
+ __func__,
+ rix,
+ rt->rateCount);
+ rix = 0; /* XXX just default for now */
+ }
+ KASSERT(rix >= 0 && rix < rt->rateCount, ("rix is %d", rix));
+
+ // *rix0 = rix;
+ // *txrate = rt->info[rix].rateCode
+ // | (shortPreamble ? rt->info[rix].shortPreamble : 0);
+ san->packets_sent[size_bin]++;
+
+ return rix;
+#undef DOT11RATE
+#undef MCS
+#undef RATE
+}
+
+static void
+sample_tx_complete(const struct ieee80211vap *vap,
+ const struct ieee80211_node *ni, int ok,
+ void *arg1, void *arg2 __unused)
+{
+}
+
+static void
+sample_tx_update(const struct ieee80211vap *vap, const struct ieee80211_node *ni,
+ void *arg1, void *arg2, void *arg3)
+{
+}
+
+static void
+sample_setinterval(const struct ieee80211vap *vap, int msecs)
+{
+ struct ieee80211_sample *sample = vap->iv_rs;
+ int t;
+
+ if (msecs < 100)
+ msecs = 100;
+ t = msecs_to_ticks(msecs);
+ /* ieee80211_sample doesn't have the sample_interval field by now */
+ // sample->sample_interval = (t < 1) ? 1 : t;
+}
+
+static void
+sample_stats(void *arg, struct ieee80211_node *ni)
+{
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct ieee80211_sample_node *san = ni->ni_rctls;
+ const struct ieee80211_rate_table *rt = ieee80211_get_ratetable(vap->iv_ic->ic_curchan);
+ uint64_t mask;
+ int rix, y;
+
+ printf("\n[%s] refcnt %d static_rix (%d %s) ratemask 0x%jx\n",
+ ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni),
+ dot11rate(rt, san->static_rix),
+ dot11rate_label(rt, san->static_rix),
+ (uintmax_t)san->ratemask);
+ for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
+ printf("[%4u] cur rix %d (%d %s) since switch: packets %d ticks %u\n",
+ bin_to_size(y), san->current_rix[y],
+ dot11rate(rt, san->current_rix[y]),
+ dot11rate_label(rt, san->current_rix[y]),
+ san->packets_since_switch[y], san->ticks_since_switch[y]);
+ printf("[%4u] last sample (%d %s) cur sample (%d %s) packets sent %d\n",
+ bin_to_size(y),
+ dot11rate(rt, san->last_sample_rix[y]),
+ dot11rate_label(rt, san->last_sample_rix[y]),
+ dot11rate(rt, san->current_sample_rix[y]),
+ dot11rate_label(rt, san->current_sample_rix[y]),
+ san->packets_sent[y]);
+ printf("[%4u] packets since sample %d sample tt %u\n",
+ bin_to_size(y), san->packets_since_sample[y],
+ san->sample_tt[y]);
+ }
+ for (mask = san->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) {
+ if ((mask & 1) == 0)
+ continue;
+ for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
+ if (san->stats[y][rix].total_packets == 0)
+ continue;
+ printf("[%2u %s:%4u] %8ju:%-8ju (%3d%%) (EWMA %3d.%1d%%) T %8ju F %4d avg %5u last %u\n",
+ dot11rate(rt, rix), dot11rate_label(rt, rix),
+ bin_to_size(y),
+ (uintmax_t) san->stats[y][rix].total_packets,
+ (uintmax_t) san->stats[y][rix].packets_acked,
+ (int) ((san->stats[y][rix].packets_acked * 100ULL) /
+ san->stats[y][rix].total_packets),
+ san->stats[y][rix].ewma_pct / 10,
+ san->stats[y][rix].ewma_pct % 10,
+ (uintmax_t) san->stats[y][rix].tries,
+ san->stats[y][rix].successive_failures,
+ san->stats[y][rix].average_tx_time,
+ ticks - san->stats[y][rix].last_tx);
+ }
+ }
+}
+
+static int
+sample_sysctl_stats(SYSCTL_HANDLER_ARGS)
+{
+ struct ieee80211vap *vap = arg1;
+ struct ieee80211com *ic = vap->iv_ifp->if_l2com;
+ int error, v;
+
+ v = 0;
+ error = sysctl_handle_int(oidp, &v, 0, req);
+ if (error || !req->newptr)
+ return error;
+ ieee80211_iterate_nodes(&ic->ic_sta, sample_stats, NULL);
+ return 0;
+}
+
+static int
+sample_sysctl_smoothing_rate(SYSCTL_HANDLER_ARGS)
+{
+ struct ieee80211vap *vap = arg1;
+ struct ieee80211_sample *sample = vap->iv_rs;
+ int rate, error;
+
+ rate = sample->sample_smoothing_rate;
+ error = sysctl_handle_int(oidp, &rate, 0, req);
+ if (error || !req->newptr)
+ return error;
+ if (!(0 <= rate && rate < 100))
+ return EINVAL;
+ sample->sample_smoothing_rate = rate;
+ sample->sample_smoothing_minpackets = 100 / (100 - rate);
+ return 0;
+}
+
+static int
+sample_sysctl_sample_rate(SYSCTL_HANDLER_ARGS)
+{
+ struct ieee80211vap *vap = arg1;
+ struct ieee80211_sample *sample = vap->iv_rs;
+ int rate, error;
+
+ rate = sample->sample_rate;
+ error = sysctl_handle_int(oidp, &rate, 0, req);
+ if (error || !req->newptr)
+ return error;
+ if (!(2 <= rate && rate <= 100))
+ return EINVAL;
+ sample->sample_rate = rate;
+ return 0;
+}
+
+static void
+sample_sysctlattach(struct ieee80211vap *vap,
+ struct sysctl_ctx_list *ctx, struct sysctl_oid *tree)
+{
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "sample_smoothing_rate", CTLTYPE_INT | CTLFLAG_RW, vap, 0,
+ sample_sysctl_smoothing_rate, "I",
+ "sample: smoothing rate for avg tx time (%%)");
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "sample_rate", CTLTYPE_INT | CTLFLAG_RW, vap, 0,
+ sample_sysctl_sample_rate, "I",
+ "sample: percent air time devoted to sampling new rates (%%)");
+ /* XXX max_successive_failures, stale_failure_timeout, min_switch */
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "sample_stats", CTLTYPE_INT | CTLFLAG_RW, vap, 0,
+ sample_sysctl_stats, "I", "sample: print statistics");
+}
Index: ieee80211_rc_sample.h
===================================================================
--- ieee80211_rc_sample.h (revision 0)
+++ ieee80211_rc_sample.h (revision 255539)
@@ -0,0 +1,152 @@
+/* $FreeBSD: head/sys/dev/ath/ath_rate/sample/sample.h 240382 2012-08-15 07:10:10Z adrian $*/
+
+/*-
+ * Copyright (c) 2013 Chenchong Qin <ccqin@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#ifndef _NET80211_IEEE80211_RATECTL_SAMPLE_H_
+#define _NET80211_IEEE80211_RATECTL_SAMPLE_H_
+
+/*
+ * for now, we track performance for three different packet
+ * size buckets
+ */
+#define NUM_PACKET_SIZE_BINS 2
+#define SAMPLE_MAXRATES 64 /* NB: corresponds to hal info[32] */
+
+/*
+ * Rate control settings.
+ */
+struct ieee80211_sample {
+ int sample_smoothing_rate; /* ewma percentage [0..99] */
+ int sample_smoothing_minpackets;
+ int sample_rate; /* %time to try different tx rates */
+ int sample_max_successive_failures;
+ int sample_stale_failure_timeout; /* how long to honor max_successive_failures */
+ int sample_min_switch; /* min time between rate changes */
+ int sample_min_good_pct; /* min good percentage for a rate to be considered */
+};
+
+struct rate_stats {
+ unsigned average_tx_time;
+ int successive_failures;
+ uint64_t tries;
+ uint64_t total_packets; /* pkts total since assoc */
+ uint64_t packets_acked; /* pkts acked since assoc */
+ int ewma_pct; /* EWMA percentage */
+ unsigned perfect_tx_time; /* transmit time for 0 retries */
+ int last_tx;
+};
+
+struct txschedule {
+ uint8_t t0, r0; /* series 0: tries, rate code */
+ uint8_t t1, r1; /* series 1: tries, rate code */
+ uint8_t t2, r2; /* series 2: tries, rate code */
+ uint8_t t3, r3; /* series 3: tries, rate code */
+};
+
+/*
+ * Rate control state for a given node.
+ */
+/* XXX change naming conversion? */
+struct ieee80211_sample_node {
+ struct ieee80211_sample *san_sample;/* backpointer */
+ int static_rix; /* rate index of fixed tx rate */
+ uint64_t ratemask; /* bit mask of valid rate indices */
+ const struct txschedule *sched; /* tx schedule table */
+
+ struct rate_stats stats[NUM_PACKET_SIZE_BINS][SAMPLE_MAXRATES];
+ int last_sample_rix[NUM_PACKET_SIZE_BINS];
+
+ int current_sample_rix[NUM_PACKET_SIZE_BINS];
+ int packets_sent[NUM_PACKET_SIZE_BINS];
+
+ int current_rix[NUM_PACKET_SIZE_BINS];
+ int packets_since_switch[NUM_PACKET_SIZE_BINS];
+ unsigned ticks_since_switch[NUM_PACKET_SIZE_BINS];
+
+ int packets_since_sample[NUM_PACKET_SIZE_BINS];
+ unsigned sample_tt[NUM_PACKET_SIZE_BINS];
+};
+
+#define IS_RATE_DEFINED(san, rix) (((san)->ratemask & (1<<(rix))) != 0)
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+static const int packet_size_bins[NUM_PACKET_SIZE_BINS] = { 250, 1600 };
+
+static inline int
+bin_to_size(int index)
+{
+ return packet_size_bins[index];
+}
+
+static inline int
+size_to_bin(int size)
+{
+#if NUM_PACKET_SIZE_BINS > 1
+ if (size <= packet_size_bins[0])
+ return 0;
+#endif
+#if NUM_PACKET_SIZE_BINS > 2
+ if (size <= packet_size_bins[1])
+ return 1;
+#endif
+#if NUM_PACKET_SIZE_BINS > 3
+ if (size <= packet_size_bins[2])
+ return 2;
+#endif
+#if NUM_PACKET_SIZE_BINS > 4
+#error "add support for more packet sizes"
+#endif
+ return NUM_PACKET_SIZE_BINS-1;
+}
+
+/*
+ * Calculate the transmit duration of a frame.
+ */
+static unsigned calc_usecs_unicast_packet(int length,
+ int rix, int short_retries,
+ int long_retries, int is_ht40)
+{
+ /* XXX not done yet */
+}
+
+#endif /* _NET80211_IEEE80211_RATECTL_SAMPLE_H_ */
Index: ieee80211_rc_sample_txsched.h
===================================================================
--- ieee80211_rc_sample_txsched.h (revision 0)
+++ ieee80211_rc_sample_txsched.h (revision 255539)
@@ -0,0 +1,241 @@
+/* $FreeBSD: head/sys/dev/ath/ath_rate/sample/tx_schedules.h 240384 2012-08-15 07:50:42Z adrian $*/
+
+/*-
+ * Copyright (c) 2005 John Bicket
+ * Copyright (c) 2013 Chenchong Qin <ccqin@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ */
+#ifndef __ATH_RATE_SAMPLE_TXSCHEDULES_H__
+#define __ATH_RATE_SAMPLE_TXSCHEDULES_H__
+
+#include <sys/cdefs.h>
+
+#define A(_r) \
+ (((_r) == 6) ? 0 : (((_r) == 9) ? 1 : (((_r) == 12) ? 2 : \
+ (((_r) == 18) ? 3 : (((_r) == 24) ? 4 : (((_r) == 36) ? 5 : \
+ (((_r) == 48) ? 6 : (((_r) == 54) ? 7 : 0))))))))
+static const struct txschedule series_11a[] = {
+ { 3,A( 6), 3,A( 6), 0,A( 6), 0,A( 6) }, /* 6Mb/s */
+ { 4,A( 9), 3,A( 6), 4,A( 6), 0,A( 6) }, /* 9Mb/s */
+ { 4,A(12), 3,A( 6), 4,A( 6), 0,A( 6) }, /* 12Mb/s */
+ { 4,A(18), 3,A( 12), 4,A( 6), 2,A( 6) }, /* 18Mb/s */
+ { 4,A(24), 3,A( 18), 4,A( 12), 2,A( 6) }, /* 24Mb/s */
+ { 4,A(36), 3,A( 24), 4,A( 18), 2,A( 6) }, /* 36Mb/s */
+ { 4,A(48), 3,A( 36), 4,A( 24), 2,A(12) }, /* 48Mb/s */
+ { 4,A(54), 3,A( 48), 4,A( 36), 2,A(24) } /* 54Mb/s */
+};
+
+#define NA1(_r) \
+ (((_r) == 6.5) ? 8 : (((_r) == 13) ? 9 : (((_r) == 19.5)? 10 : \
+ (((_r) == 26) ? 11 : (((_r) == 39) ? 12 : (((_r) == 52) ? 13 : \
+ (((_r) == 58.5)? 14 : (((_r) == 65) ? 15 : 0))))))))
+#define NA2(_r) \
+ (((_r) == 13) ? 16 : (((_r) == 26) ? 17 : (((_r) == 39) ? 18 : \
+ (((_r) == 52) ? 19 : (((_r) == 78) ? 20 : (((_r) == 104)? 21 : \
+ (((_r) == 117)? 22 : (((_r) == 130)? 23 : 0))))))))
+#define NA3(_r) \
+ (((_r) == 19.5) ? 24 : (((_r) == 39) ? 25 : (((_r) == 58.5) ? 26 : \
+ (((_r) == 78) ? 27 : (((_r) == 117) ? 28 : (((_r) == 156) ? 29 : \
+ (((_r) == 175.5) ? 30 : (((_r) == 195)? 31 : 0))))))))
+static const struct txschedule series_11na[] = {
+ { 3,A( 6), 3,A( 6), 0,A( 6), 0,A( 6) }, /* 6Mb/s */
+ { 4,A( 9), 3,A( 6), 4,A( 6), 0,A( 6) }, /* 9Mb/s */
+ { 4,A(12), 3,A( 6), 4,A( 6), 0,A( 6) }, /* 12Mb/s */
+ { 4,A(18), 3,A( 12), 4,A( 6), 2,A( 6) }, /* 18Mb/s */
+ { 4,A(24), 3,A( 18), 4,A( 12), 2,A( 6) }, /* 24Mb/s */
+ { 4,A(36), 3,A( 24), 4,A( 18), 2,A( 6) }, /* 36Mb/s */
+ { 4,A(48), 3,A( 36), 4,A( 24), 2,A(12) }, /* 48Mb/s */
+ { 4,A(54), 3,A( 48), 4,A( 36), 2,A(24) }, /* 54Mb/s */
+
+ /* 1 stream rates */
+
+ { 3,NA1( 6.5), 3,NA1( 6.5), 0,NA1( 6.5), 0,NA1(6.5) }, /* 6.5Mb/s */
+ { 4,NA1( 13), 3,NA1( 6.5), 4,NA1( 6.5), 0,NA1(6.5) }, /* 13Mb/s */
+ { 4,NA1(19.5), 3,NA1( 6.5), 4,NA1( 6.5), 0,NA1(6.5) }, /*19.5Mb/s */
+ { 4,NA1( 26), 3,NA1(19.5), 4,NA1( 6.5), 2,NA1(6.5) }, /* 26Mb/s */
+ { 4,NA1( 39), 3,NA1( 26), 4,NA1(19.5), 2,NA1(6.5) }, /* 39Mb/s */
+ { 4,NA1( 52), 3,NA1( 39), 4,NA1( 26), 2,NA1(6.5) }, /* 52Mb/s */
+ { 4,NA1(58.5), 3,NA1( 52), 4,NA1( 39), 2,NA1( 13) }, /*58.5Mb/s */
+ { 4,NA1( 65), 3,NA1(58.5), 4,NA1( 52), 2,NA1( 13) }, /* 65Mb/s */
+
+ /* 2 stream rates */
+
+ { 3,NA2( 13), 3,NA2( 13), 0,NA2( 13), 0,NA2( 13) }, /* 13Mb/s */
+ { 4,NA2( 26), 3,NA2( 13), 4,NA2( 13), 0,NA2( 13) }, /* 26Mb/s */
+ { 4,NA2( 39), 3,NA2( 26), 4,NA2( 13), 2,NA2( 13) }, /* 39Mb/s */
+ { 4,NA2( 52), 3,NA2( 39), 4,NA2( 26), 2,NA2( 13) }, /* 52Mb/s */
+ { 4,NA2( 78), 3,NA2( 52), 4,NA2( 39), 2,NA2( 13) }, /* 78Mb/s */
+ { 4,NA2( 104), 3,NA2( 78), 4,NA2( 52), 2,NA2( 13) }, /* 104Mb/s */
+ { 4,NA2( 117), 3,NA2( 104), 4,NA2( 78), 2,NA2( 26) }, /* 117Mb/s */
+ { 4,NA2( 130), 3,NA2( 117), 4,NA2( 104), 2,NA2( 26) }, /* 130Mb/s */
+
+ /* 3 stream rates */
+
+ { 3,NA3(19.5), 3,NA3(19.5), 0,NA3(19.5), 0,NA3(19.5) }, /* 19Mb/s */
+ { 3,NA3( 39), 3,NA3(19.5), 0,NA3(19.5), 0,NA3(19.5) }, /* 39Mb/s */
+ { 3,NA3(58.5), 3,NA3( 39), 0,NA3(19.5), 0,NA3(19.5) }, /* 58Mb/s */
+ { 3,NA3( 78), 3,NA3(58.5), 0,NA3( 39), 0,NA3(19.5) }, /* 78Mb/s */
+ { 3,NA3( 117), 3,NA3( 78), 0,NA3(58.5), 0,NA3(19.5) }, /* 117Mb/s */
+ { 3,NA3( 156), 3,NA3( 117), 0,NA3( 78), 0,NA3(19.5) }, /* 156Mb/s */
+ { 3,NA3(175.5), 3,NA3( 156), 0,NA3( 117), 0,NA3( 39) }, /* 175Mb/s */
+ { 3,NA3( 195), 3,NA3( 195), 0,NA3( 156), 0,NA3(58.5) }, /* 195Mb/s */
+};
+#undef A
+#undef NA3
+#undef NA2
+#undef NA1
+
+#define G(_r) \
+ (((_r) == 1) ? 0 : (((_r) == 2) ? 1 : (((_r) == 5.5) ? 2 : \
+ (((_r) == 11) ? 3 : (((_r) == 6) ? 4 : (((_r) == 9) ? 5 : \
+ (((_r) == 12) ? 6 : (((_r) == 18) ? 7 : (((_r) == 24) ? 8 : \
+ (((_r) == 36) ? 9 : (((_r) == 48) ? 10 : (((_r) == 54) ? 11 : 0))))))))))))
+static const struct txschedule series_11g[] = {
+ { 3,G( 1), 3,G( 1), 0,G( 1), 0,G( 1) }, /* 1Mb/s */
+ { 4,G( 2), 3,G( 1), 4,G( 1), 0,G( 1) }, /* 2Mb/s */
+ { 4,G(5.5),3,G( 2), 4,G( 1), 2,G( 1) }, /* 5.5Mb/s */
+ { 4,G(11), 3,G(5.5), 4,G( 2), 2,G( 1) }, /* 11Mb/s */
+ { 4,G( 6), 3,G(5.5), 4,G( 2), 2,G( 1) }, /* 6Mb/s */
+ { 4,G( 9), 3,G( 6), 4,G(5.5), 2,G( 1) }, /* 9Mb/s */
+ { 4,G(12), 3,G( 11), 4,G(5.5), 2,G( 1) }, /* 12Mb/s */
+ { 4,G(18), 3,G( 12), 4,G( 11), 2,G( 1) }, /* 18Mb/s */
+ { 4,G(24), 3,G( 18), 4,G( 12), 2,G( 1) }, /* 24Mb/s */
+ { 4,G(36), 3,G( 24), 4,G( 18), 2,G( 1) }, /* 36Mb/s */
+ { 4,G(48), 3,G( 36), 4,G( 24), 2,G( 1) }, /* 48Mb/s */
+ { 4,G(54), 3,G( 48), 4,G( 36), 2,G( 1) } /* 54Mb/s */
+};
+
+#define NG1(_r) \
+ (((_r) == 6.5) ? 12 : (((_r) == 13) ? 13 : (((_r) == 19.5)? 14 : \
+ (((_r) == 26) ? 15 : (((_r) == 39) ? 16 : (((_r) == 52) ? 17 : \
+ (((_r) == 58.5)? 18 : (((_r) == 65) ? 19 : 0))))))))
+#define NG2(_r) \
+ (((_r) == 13) ? 20 : (((_r) == 26) ? 21 : (((_r) == 39) ? 22 : \
+ (((_r) == 52) ? 23 : (((_r) == 78) ? 24 : (((_r) == 104) ? 25 : \
+ (((_r) == 117) ? 26 : (((_r) == 130)? 27 : 0))))))))
+#define NG3(_r) \
+ (((_r) == 19.5) ? 28 : (((_r) == 39) ? 29 : (((_r) == 58.5) ? 30 : \
+ (((_r) == 78) ? 31 : (((_r) == 117) ? 32 : (((_r) == 156) ? 33 : \
+ (((_r) == 175.5) ? 34 : (((_r) == 195)? 35 : 0))))))))
+
+static const struct txschedule series_11ng[] = {
+ { 3,G( 1), 3,G( 1), 0,G( 1), 0,G( 1) }, /* 1Mb/s */
+ { 4,G( 2), 3,G( 1), 4,G( 1), 0,G( 1) }, /* 2Mb/s */
+ { 4,G(5.5),3,G( 2), 4,G( 1), 2,G( 1) }, /* 5.5Mb/s */
+ { 4,G(11), 3,G(5.5), 4,G( 2), 2,G( 1) }, /* 11Mb/s */
+ { 4,G( 6), 3,G(5.5), 4,G( 2), 2,G( 1) }, /* 6Mb/s */
+ { 4,G( 9), 3,G( 6), 4,G(5.5), 2,G( 1) }, /* 9Mb/s */
+ { 4,G(12), 3,G( 11), 4,G(5.5), 2,G( 1) }, /* 12Mb/s */
+ { 4,G(18), 3,G( 12), 4,G( 11), 2,G( 1) }, /* 18Mb/s */
+ { 4,G(24), 3,G( 18), 4,G( 12), 2,G( 1) }, /* 24Mb/s */
+ { 4,G(36), 3,G( 24), 4,G( 18), 2,G( 1) }, /* 36Mb/s */
+ { 4,G(48), 3,G( 36), 4,G( 24), 2,G( 1) }, /* 48Mb/s */
+ { 4,G(54), 3,G( 48), 4,G( 36), 2,G( 1) }, /* 54Mb/s */
+
+ /* 1 stream rates */
+
+ { 3,NG1( 6.5), 3,NG1( 6.5), 0,NG1( 6.5), 0,NG1(6.5) }, /* 6.5Mb/s */
+ { 4,NG1( 13), 3,NG1( 6.5), 4,NG1( 6.5), 0,NG1(6.5) }, /* 13Mb/s */
+ { 4,NG1(19.5), 3,NG1( 6.5), 4,NG1( 6.5), 0,NG1(6.5) }, /*19.5Mb/s */
+ { 4,NG1( 26), 3,NG1(19.5), 4,NG1( 6.5), 2,NG1(6.5) }, /* 26Mb/s */
+ { 4,NG1( 39), 3,NG1( 26), 4,NG1(19.5), 2,NG1(6.5) }, /* 39Mb/s */
+ { 4,NG1( 52), 3,NG1( 39), 4,NG1( 26), 2,NG1(6.5) }, /* 52Mb/s */
+ { 4,NG1(58.5), 3,NG1( 52), 4,NG1( 39), 2,NG1( 13) }, /*58.5Mb/s */
+ { 4,NG1( 65), 3,NG1(58.5), 4,NG1( 52), 2,NG1( 13) }, /* 65Mb/s */
+
+ /* 2 stream rates */
+
+ { 3,NG2( 13), 3,NG2( 13), 0,NG2( 13), 0,NG2( 13) }, /* 13Mb/s */
+ { 4,NG2( 26), 3,NG2( 13), 4,NG2( 13), 0,NG2( 13) }, /* 26Mb/s */
+ { 4,NG2( 39), 3,NG2( 26), 4,NG2( 13), 2,NG2( 13) }, /* 39Mb/s */
+ { 4,NG2( 52), 3,NG2( 39), 4,NG2( 26), 2,NG2( 13) }, /* 52Mb/s */
+ { 4,NG2( 78), 3,NG2( 52), 4,NG2( 39), 2,NG2( 13) }, /* 78Mb/s */
+ { 4,NG2( 104), 3,NG2( 78), 4,NG2( 52), 2,NG2( 13) }, /* 104Mb/s */
+ { 4,NG2( 117), 3,NG2( 104), 4,NG2( 78), 2,NG2( 26) }, /* 117Mb/s */
+ { 4,NG2( 130), 3,NG2( 117), 4,NG2( 104), 2,NG2( 26) }, /* 130Mb/s */
+
+ /* 3 stream rates */
+
+ { 3,NG3(19.5), 3,NG3(19.5), 0,NG3(19.5), 0,NG3(19.5) }, /* 19Mb/s */
+ { 3,NG3( 39), 3,NG3(19.5), 0,NG3(19.5), 0,NG3(19.5) }, /* 39Mb/s */
+ { 3,NG3(58.5), 3,NG3( 39), 0,NG3(19.5), 0,NG3(19.5) }, /* 58Mb/s */
+ { 3,NG3( 78), 3,NG3(58.5), 0,NG3( 39), 0,NG3(19.5) }, /* 78Mb/s */
+ { 3,NG3( 117), 3,NG3( 78), 0,NG3(58.5), 0,NG3(19.5) }, /* 117Mb/s */
+ { 3,NG3( 156), 3,NG3( 117), 0,NG3( 78), 0,NG3(19.5) }, /* 156Mb/s */
+ { 3,NG3(175.5), 3,NG3( 156), 0,NG3( 117), 0,NG3( 39) }, /* 175Mb/s */
+ { 3,NG3( 195), 3,NG3( 195), 0,NG3( 156), 0,NG3(58.5) }, /* 195Mb/s */
+
+};
+#undef G
+#undef NG3
+#undef NG2
+#undef NG1
+
+#define H(_r) \
+ (((_r) == 3) ? 0 : (((_r) == 4.5) ? 1 : (((_r) == 6) ? 2 : \
+ (((_r) == 9) ? 3 : (((_r) == 12) ? 4 : (((_r) == 18) ? 5 : \
+ (((_r) == 24) ? 6 : (((_r) == 27) ? 7 : 0))))))))
+static const struct txschedule series_half[] = {
+ { 3,H( 3), 3,H( 3), 0,H( 3), 0,H( 3) }, /* 3Mb/s */
+ { 4,H(4.5),3,H( 3), 4,H( 3), 0,H( 3) }, /* 4.5Mb/s */
+ { 4,H( 6), 3,H( 3), 4,H( 3), 0,H( 3) }, /* 6Mb/s */
+ { 4,H( 9), 3,H( 6), 4,H( 3), 2,H( 3) }, /* 9Mb/s */
+ { 4,H(12), 3,H( 9), 4,H( 6), 2,H( 3) }, /* 12Mb/s */
+ { 4,H(18), 3,H( 12), 4,H( 9), 2,H( 3) }, /* 18Mb/s */
+ { 4,H(24), 3,H( 18), 4,H( 12), 2,H( 6) }, /* 24Mb/s */
+ { 4,H(27), 3,H( 24), 4,H( 18), 2,H(12) } /* 27Mb/s */
+};
+#undef H
+
+#ifdef Q
+#undef Q
+#endif
+#define Q(_r) \
+ (((_r) == 1.5) ? 0 : (((_r) ==2.25) ? 1 : (((_r) == 3) ? 2 : \
+ (((_r) == 4.5) ? 3 : (((_r) == 6) ? 4 : (((_r) == 9) ? 5 : \
+ (((_r) == 12) ? 6 : (((_r) == 13.5)? 7 : 0))))))))
+static const struct txschedule series_quarter[] = {
+ { 3,Q( 1.5),3,Q(1.5), 0,Q(1.5), 0,Q(1.5) }, /* 1.5Mb/s */
+ { 4,Q(2.25),3,Q(1.5), 4,Q(1.5), 0,Q(1.5) }, /*2.25Mb/s */
+ { 4,Q( 3),3,Q(1.5), 4,Q(1.5), 0,Q(1.5) }, /* 3Mb/s */
+ { 4,Q( 4.5),3,Q( 3), 4,Q(1.5), 2,Q(1.5) }, /* 4.5Mb/s */
+ { 4,Q( 6),3,Q(4.5), 4,Q( 3), 2,Q(1.5) }, /* 6Mb/s */
+ { 4,Q( 9),3,Q( 6), 4,Q(4.5), 2,Q(1.5) }, /* 9Mb/s */
+ { 4,Q( 12),3,Q( 9), 4,Q( 6), 2,Q( 3) }, /* 12Mb/s */
+ { 4,Q(13.5),3,Q( 12), 4,Q( 9), 2,Q( 6) } /*13.5Mb/s */
+};
+#undef Q
+
+#endif
Index: ieee80211_ratectl.c
===================================================================
--- ieee80211_ratectl.c (revision 254826)
+++ ieee80211_ratectl.c (revision 255539)
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2010 Rui Paulo <rpaulo@FreeBSD.org>
+ * Copyright (c) 2013 Chenchong Qin <ccqin@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,6 +50,33 @@
MALLOC_DEFINE(M_80211_RATECTL, "80211ratectl", "802.11 rate control");
+int max_4ms_framelen[4][32] = {
+ [MCS_HT20] = {
+ 3212, 6432, 9648, 12864, 19300, 25736, 28952, 32172,
+ 6424, 12852, 19280, 25708, 38568, 51424, 57852, 64280,
+ 9628, 19260, 28896, 38528, 57792, 65532, 65532, 65532,
+ 12828, 25656, 38488, 51320, 65532, 65532, 65532, 65532,
+ },
+ [MCS_HT20_SGI] = {
+ 3572, 7144, 10720, 14296, 21444, 28596, 32172, 35744,
+ 7140, 14284, 21428, 28568, 42856, 57144, 64288, 65532,
+ 10700, 21408, 32112, 42816, 64228, 65532, 65532, 65532,
+ 14256, 28516, 42780, 57040, 65532, 65532, 65532, 65532,
+ },
+ [MCS_HT40] = {
+ 6680, 13360, 20044, 26724, 40092, 53456, 60140, 65532,
+ 13348, 26700, 40052, 53400, 65532, 65532, 65532, 65532,
+ 20004, 40008, 60016, 65532, 65532, 65532, 65532, 65532,
+ 26644, 53292, 65532, 65532, 65532, 65532, 65532, 65532,
+ },
+ [MCS_HT40_SGI] = {
+ 7420, 14844, 22272, 29696, 44544, 59396, 65532, 65532,
+ 14832, 29668, 44504, 59340, 65532, 65532, 65532, 65532,
+ 22232, 44464, 65532, 65532, 65532, 65532, 65532, 65532,
+ 29616, 59232, 65532, 65532, 65532, 65532, 65532, 65532,
+ }
+};
+
void
ieee80211_ratectl_register(int type, const struct ieee80211_ratectl *ratectl)
{
@@ -66,10 +94,11 @@
}
void
-ieee80211_ratectl_init(struct ieee80211vap *vap)
+ieee80211_ratectl_init(struct ieee80211vap *vap, uint32_t capabilities)
{
if (vap->iv_rate == ratectls[IEEE80211_RATECTL_NONE])
ieee80211_ratectl_set(vap, IEEE80211_RATECTL_AMRR);
+ vap->iv_rate.ir_capabilities = capabilities;
vap->iv_rate->ir_init(vap);
}
@@ -90,3 +119,95 @@
}
vap->iv_rate = ratectls[type];
}
+
+void
+ieee80211_ratectl_complete_rcflags(const struct ieee80211_node *ni,
+ struct ieee80211_rc_series *rc, int shortPreamble)
+{
+ const struct ieee80211com *ic = ni->ni_ic;
+ const struct ieee80211vap *vap = ni->ni_vap;
+ const struct ieee80211_rate_table * rt = ic->ic_rt;
+ uint8_t rate;
+ int i;
+
+ /* Make sure that rate control code doesn't mess it up.
+ * If enable rts/cts and is pre-802.11n, blank tries 1, 2, 3
+ */
+
+ if (! (vap->iv_rate->ir_capabilities & IEEE80211_RATECTL_CAP_MRRPROT))
+ {
+ for (i = 1; i < IEEE80211_RATECTL_NUM; i++)
+ {
+ if (rc[0].flags & IEEE80211_RATECTL_RTSCTS_FLAG)
+ rc[i].tries = 0;
+ rc[i].flags &= ~IEEE80211_RATECTL_RTSCTS_FLAG;
+ }
+ }
+
+ for (i = 0; i < IEEE80211_RATECTL_NUM; i++) {
+
+ if (rc[i].tries == 0)
+ continue;
+
+ rate = rt->info[rc[i].rix].rateCode;
+
+ /*
+ * Only enable short preamble for legacy rates
+ */
+ if ((! IS_HT_RATE(rate)) && shortPreamble)
+ rate |= rt->info[rc[i].rix].shortPreamble;
+
+ /*
+ * Save this, used by the TX and completion code
+ */
+ rc[i].ratecode = rate;
+
+ /* Only enable shortgi, 2040, dual-stream if HT is set */
+ if (IS_HT_RATE(rate)) {
+ rc[i].flags |= IEEE80211_RATECTL_HT_FLAG;
+
+ /*
+ * XXX TODO: LDPC
+ */
+
+ /*
+ * Dual / Triple stream rate?
+ */
+ if (HT_RC_2_STREAMS(rate) == 2)
+ rc[i].flags |= IEEE80211_RATECTL_DS_FLAG;
+ else if (HT_RC_2_STREAMS(rate) == 3)
+ rc[i].flags |= IEEE80211_RATECTL_TS_FLAG;
+ }
+
+ /*
+ * Calculate the maximum TX power cap for the current
+ * node.
+ * Rate control algo can't control TX power by now.
+ */
+ rc[i].tx_power_cap = ieee80211_get_node_txpower(ni);
+
+ /*
+ * Calculate the maximum 4ms frame length based
+ * on the MCS rate, SGI and channel width flags.
+ */
+ if ((rc[i].flags & IEEE80211_RATECTL_HT_FLAG) &&
+ (HT_RC_2_MCS(rate) < 32)) {
+ int j;
+ if (rc[i].flags & IEEE80211_RATECTL_CW40_FLAG) {
+ if (rc[i].flags & IEEE80211_RATECTL_SGI_FLAG)
+ j = MCS_HT40_SGI;
+ else
+ j = MCS_HT40;
+ } else {
+ if (rc[i].flags & IEEE80211_RATECTL_SGI_FLAG)
+ j = MCS_HT20_SGI;
+ else
+ j = MCS_HT20;
+ }
+ rc[i].max4msframelen =
+ max_4ms_framelen[j][HT_RC_2_MCS(rate)];
+ } else
+ rc[i].max4msframelen = 0;
+ }
+}
+
Index: ieee80211_ratectl.h
===================================================================
--- ieee80211_ratectl.h (revision 254826)
+++ ieee80211_ratectl.h (revision 255539)
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2010 Rui Paulo <rpaulo@FreeBSD.org>
+ * Copyright (c) 2013 Chenchong Qin <ccqin@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,6 +25,8 @@
*
* $FreeBSD$
*/
+#ifndef _NET80211_IEEE80211_RATECTL_H_
+#define _NET80211_IEEE80211_RATECTL_H_
enum ieee80211_ratealgs {
IEEE80211_RATECTL_AMRR = 0,
@@ -34,11 +37,56 @@
IEEE80211_RATECTL_MAX
};
+enum {
+ MCS_HT20,
+ MCS_HT20_SGI,
+ MCS_HT40,
+ MCS_HT40_SGI,
+};
+
#define IEEE80211_RATECTL_TX_SUCCESS 1
#define IEEE80211_RATECTL_TX_FAILURE 0
+#define IEEE80211_RATECTL_TRUE 1
+#define IEEE80211_RATECTL_FALSE 0
+
+#define IEEE80211_RATECTL_NUM 4
+
+#define IEEE80211_RATECTL_DS_FLAG 0x01 /* dual-stream rate */
+#define IEEE80211_RATECTL_CW40_FLAG 0x02 /* use HT40 */
+#define IEEE80211_RATECTL_SGI_FLAG 0x04 /* use short-GI */
+#define IEEE80211_RATECTL_HT_FLAG 0x08 /* use HT */
+#define IEEE80211_RATECTL_RTSCTS_FLAG 0x10 /* enable RTS/CTS protection */
+#define IEEE80211_RATECTL_STBC_FLAG 0x20 /* enable STBC */
+#define IEEE80211_RATECTL_TS_FLAG 0x40 /* triple-stream rate */
+
+/* Hardware CAPs chip offered to rate control code */
+#define IEEE80211_RATECTL_CAP_MRR 0x01 /* support MRR */
+#define IEEE80211_RATECTL_CAP_MRRPROT 0x02 /* support MRR + protect */
+#define IEEE80211_RATECTL_CAP_MULTXCHAIN 0x04 /* has more than 1 txchain */
+
+#define IS_VAP_HT(vap) ((vap)->iv_htcaps & IEEE80211_HTC_HT)
+
+#define IS_HT_RATE(_rate) ((_rate) & 0x80)
+#define HT_RC_2_MCS(_rc) ((_rc) & 0x7f)
+#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1)
+
+
+extern int max_4ms_framelen[4][32];
+
+struct ieee80211_rc_series {
+ uint8_t rix; /* ratetable index, not rate code */
+ uint8_t ratecode; /* hardware rate code */
+ uint8_t tries;
+ uint8_t tx_power_cap;
+ uint16_t flags;
+ uint16_t max4msframelen;
+};
+
struct ieee80211_ratectl {
const char *ir_name;
+ uint32_t ir_capabilities; /* hardware capabilities offered to rc */
+
int (*ir_attach)(const struct ieee80211vap *);
void (*ir_detach)(const struct ieee80211vap *);
void (*ir_init)(struct ieee80211vap *);
@@ -46,6 +94,8 @@
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_tx_complete)(const struct ieee80211vap *,
const struct ieee80211_node *, int,
void *, void *);
@@ -57,8 +107,10 @@
void ieee80211_ratectl_register(int, const struct ieee80211_ratectl *);
void ieee80211_ratectl_unregister(int);
-void ieee80211_ratectl_init(struct ieee80211vap *);
+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)
MALLOC_DECLARE(M_80211_RATECTL);
@@ -93,6 +145,17 @@
}
static void __inline
+ieee80211_ratectl_rates(struct ieee80211_node *ni, struct ieee80211_rc_series *rc,
+ int shortPreamble, size_t frameLen)
+{
+ const struct ieee80211vap *vap = ni->ni_vap;
+
+ vap->iv_rate->ir_rates(ni, rc, shortPreamble, frameLen);
+
+ ieee80211_ratectl_complete_rcflags(ni, rc, shortPreamble);
+}
+
+static void __inline
ieee80211_ratectl_tx_complete(const struct ieee80211vap *vap,
const struct ieee80211_node *ni, int status, void *arg1, void *arg2)
{
@@ -115,3 +178,40 @@
return;
vap->iv_rate->ir_setinterval(vap, msecs);
}
+
+static int __inline
+ieee80211_ratectl_hascap_cw40(const struct ieee80211vap *vap,
+ const struct ieee80211_node *ni)
+{
+ return IS_VAP_HT(vap) && (ni->ni_chw == 40);
+}
+
+static int __inline
+ieee80211_ratectl_hascap_shortgi(const struct ieee80211vap *vap,
+ const struct ieee80211_node *ni)
+{
+ if (! IS_VAP_HT(vap))
+ return IEEE80211_RATECTL_FALSE;
+
+ if (ni->ni_chw == 40 &&
+ vap->iv_htcaps & IEEE80211_HTCAP_SHORTGI40 &&
+ ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40)
+ return IEEE80211_RATECTL_TRUE;
+
+ if (ni->ni_chw == 20 &&
+ vap->iv_htcaps & IEEE80211_HTCAP_SHORTGI20 &&
+ ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20)
+ return IEEE80211_RATECTL_TRUE;
+}
+
+
+static int __inline
+ieee80211_ratectl_hascap_stbc(const struct ieee80211vap *vap,
+ const struct ieee80211_node *ni)
+{
+ return IS_VAP_HT(vap) && (vap->iv_htcaps & IEEE80211_HTCAP_TXSTBC) &&
+ (ni->ni_htcap & IEEE80211_HTCAP_RXSTBC_1STREAM) &&
+ (vap->iv_rate->ir_capabilities & IEEE80211_RATECTL_CAP_MULTXCHAIN);
+}
+
+#endif
help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAFnsE3eMwX-GiRzJt8jk4r9mxwSAQkcrDwk%2BnWVG7q6dabeA3A>
