summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/conf/files1
-rw-r--r--sys/dev/ath/ath_rate/sample/sample.c608
-rw-r--r--sys/dev/ath/ath_rate/sample/sample.h136
-rw-r--r--sys/i386/conf/NOTES1
-rw-r--r--sys/modules/Makefile1
-rw-r--r--sys/modules/ath_rate_sample/Makefile48
6 files changed, 795 insertions, 0 deletions
diff --git a/sys/conf/files b/sys/conf/files
index f482021..3c46179 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -401,6 +401,7 @@ dev/ata/atapi-fd.c optional atapifd
dev/ata/atapi-tape.c optional atapist
dev/ath/ath_rate/amrr/amrr.c optional ath_rate_amrr
dev/ath/ath_rate/onoe/onoe.c optional ath_rate_onoe
+dev/ath/ath_rate/sample/sample.c optional ath_rate_sample
dev/ath/if_ath.c optional ath
dev/ath/if_ath_pci.c optional ath pci
dev/awi/am79c930.c optional awi
diff --git a/sys/dev/ath/ath_rate/sample/sample.c b/sys/dev/ath/ath_rate/sample/sample.c
new file mode 100644
index 0000000..3bcec99
--- /dev/null
+++ b/sys/dev/ath/ath_rate/sample/sample.c
@@ -0,0 +1,608 @@
+/*-
+ * Copyright (c) 2005 John Bicket
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * John Bicket's SampleRate control algorithm.
+ */
+#include "opt_inet.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/module.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/errno.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h> /* XXX for ether_sprintf */
+
+#include <net80211/ieee80211_var.h>
+
+#include <net/bpf.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include <dev/ath/if_athvar.h>
+#include <dev/ath/ath_rate/sample/sample.h>
+#include <contrib/dev/ath/ah_desc.h>
+
+#define SAMPLE_DEBUG
+#ifdef SAMPLE_DEBUG
+enum {
+ ATH_DEBUG_RATE = 0x00000010, /* rate control */
+};
+#define DPRINTF(sc, _fmt, ...) do { \
+ if (sc->sc_debug & ATH_DEBUG_RATE) \
+ printf(_fmt, __VA_ARGS__); \
+} while (0)
+#else
+#define DPRINTF(sc, _fmt, ...)
+#endif
+
+/*
+ * This file is an implementation of the SampleRate algorithm
+ * in "Bit-rate Selection in Wireless Networks"
+ * (http://www.pdos.lcs.mit.edu/papers/jbicket-ms.ps)
+ *
+ * SampleRate chooses the bit-rate it predicts will provide the most
+ * throughput based on estimates of the expected per-packet
+ * transmission time for each bit-rate. SampleRate periodically sends
+ * packets at bit-rates other than the current one to estimate when
+ * another bit-rate will provide better performance. SampleRate
+ * switches to another bit-rate when its estimated per-packet
+ * transmission time becomes smaller than the current bit-rate's.
+ * SampleRate reduces the number of bit-rates it must sample by
+ * eliminating those that could not perform better than the one
+ * currently being used. SampleRate also stops probing at a bit-rate
+ * if it experiences several successive losses.
+ *
+ * The difference between the algorithm in the thesis and the one in this
+ * file is that the one in this file uses a ewma instead of a window.
+ *
+ */
+
+static void ath_rate_ctl_start(struct ath_softc *, struct ieee80211_node *);
+
+static __inline int size_to_bin(int size)
+{
+ int x = 0;
+ for (x = 0; x < NUM_PACKET_SIZE_BINS; x++) {
+ if (size < packet_size_bins[x]) {
+ return x;
+ }
+ }
+ return NUM_PACKET_SIZE_BINS-1;
+}
+static __inline int bin_to_size(int index) {
+ return packet_size_bins[index];
+}
+
+/*
+ * Setup rate codes for management/control frames. We force
+ * all such frames to the lowest rate.
+ */
+static void
+ath_rate_setmgtrates(struct ath_softc *sc, struct ath_node *an)
+{
+ const HAL_RATE_TABLE *rt = sc->sc_currates;
+
+ /* setup rates for management frames */
+ /* XXX management/control frames always go at lowest speed */
+ an->an_tx_mgtrate = rt->info[0].rateCode;
+ an->an_tx_mgtratesp = an->an_tx_mgtrate
+ | rt->info[0].shortPreamble;
+}
+
+void
+ath_rate_node_init(struct ath_softc *sc, struct ath_node *an)
+{
+ DPRINTF(sc, "%s:\n", __func__);
+ /* NB: assumed to be zero'd by caller */
+ ath_rate_setmgtrates(sc, an);
+}
+
+void
+ath_rate_node_cleanup(struct ath_softc *sc, struct ath_node *an)
+{
+ DPRINTF(sc, "%s:\n", __func__);
+}
+
+
+/*
+ * returns the ndx with the lowest average_tx_time,
+ * or -1 if all the average_tx_times are 0.
+ */
+static __inline int best_rate_ndx(struct sample_node *sn, int size_bin)
+{
+ int x = 0;
+ int best_rate_ndx = 0;
+ int best_rate_tt = 0;
+ for (x = 0; x < sn->num_rates; x++) {
+ int tt = sn->stats[size_bin][x].average_tx_time;
+ if (tt > 0) {
+ if (!best_rate_tt || best_rate_tt > tt) {
+ best_rate_tt = tt;
+ best_rate_ndx = x;
+ }
+ }
+ }
+ return (best_rate_tt) ? best_rate_ndx : -1;
+}
+
+/*
+ * pick a ndx s.t. the perfect_tx_time
+ * is less than the best bit-rate's average_tx_time
+ * and the ndx has not had four successive failures.
+ */
+static __inline int pick_sample_ndx(struct sample_node *sn, int size_bin)
+{
+ int x = 0;
+ int best_ndx = best_rate_ndx(sn, size_bin);
+ int best_tt = 0;
+ int num_eligible = 0;
+
+ if (best_ndx < 0) {
+ /* no successes yet, send at the lowest bit-rate */
+ return 0;
+ }
+
+ best_tt = sn->stats[size_bin][best_ndx].average_tx_time;
+ sn->sample_num[size_bin]++;
+
+ /*
+ * first, find the number of bit-rates we could potentially
+ * sample. we assume this list doesn't change a lot, so
+ * we will just cycle through them.
+ */
+ for (x = 0; x < sn->num_rates; x++) {
+ if (x != best_ndx &&
+ sn->stats[size_bin][x].perfect_tx_time < best_tt &&
+ sn->stats[size_bin][x].successive_failures < 4) {
+ num_eligible++;
+ }
+ }
+
+ if (num_eligible > 0) {
+ int pick = sn->sample_num[size_bin] % num_eligible;
+ for (x = 0; x < sn->num_rates; x++) {
+ if (x != best_ndx &&
+ sn->stats[size_bin][x].perfect_tx_time < best_tt &&
+ sn->stats[size_bin][x].successive_failures < 4) {
+ if (pick == 0) {
+ return x;
+ }
+ pick--;
+ }
+ }
+ }
+ return best_ndx;
+}
+
+void
+ath_rate_findrate(struct ath_softc *sc, struct ath_node *an,
+ HAL_BOOL shortPreamble, size_t frameLen,
+ u_int8_t *rix, int *try0, u_int8_t *txrate)
+{
+ struct sample_node *sn = ATH_NODE_SAMPLE(an);
+ struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
+ int x;
+ int ndx = 0;
+ int size_bin = size_to_bin(frameLen);
+ int best_ndx = best_rate_ndx(sn, size_bin);
+
+ if (sn->static_rate_ndx != -1) {
+ *try0 = 4;
+ *rix = sn->rates[sn->static_rate_ndx].rix;
+ *txrate = sn->rates[sn->static_rate_ndx].rateCode;
+ return;
+ }
+
+ *try0 = 2;
+
+ best_ndx = best_rate_ndx(sn, size_bin);
+ if (!sn->packets_sent[size_bin] ||
+ sn->packets_sent[size_bin] % ssc->ath_sample_rate > 0) {
+ /*
+ * for most packets, send the packet at the bit-rate with
+ * the lowest estimated transmission time.
+ */
+ if (best_ndx != -1) {
+ ndx = best_ndx;
+ } else {
+ /*
+ * no packet has succeeded, try the highest bitrate
+ * that hasn't failed.
+ */
+ for (ndx = sn->num_rates-1; ndx >= 0; ndx--) {
+ if (sn->stats[size_bin][ndx].successive_failures == 0) {
+ break;
+ }
+ }
+ }
+ if (size_bin == 0) {
+ /* update the visible txrate for this node */
+ an->an_node.ni_txrate = ndx;
+ }
+ } else {
+ /*
+ * before we pick a bit-rate to "sample", clear any
+ * stale stuff out.
+ */
+ for (x = 0; x < sn->num_rates; x++) {
+ if (ticks - sn->stats[size_bin][x].last_tx > ((hz * 10000)/1000)) {
+ sn->stats[size_bin][x].average_tx_time = sn->stats[size_bin][x].perfect_tx_time;
+ sn->stats[size_bin][x].successive_failures = 0;
+ sn->stats[size_bin][x].tries = 0;
+ sn->stats[size_bin][x].total_packets = 0;
+ sn->stats[size_bin][x].packets_acked = 0;
+ }
+ }
+
+ /* send the packet at a different bit-rate */
+ ndx = pick_sample_ndx(sn, size_bin);
+ }
+
+
+ *rix = sn->rates[ndx].rix;
+ if (shortPreamble) {
+ *txrate = sn->rates[ndx].shortPreambleRateCode;
+ } else {
+
+ *txrate = sn->rates[ndx].rateCode;
+ }
+
+ sn->packets_sent[size_bin]++;
+}
+
+void
+ath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an,
+ struct ath_desc *ds, HAL_BOOL shortPreamble, u_int8_t rix)
+{
+ struct sample_node *sn = ATH_NODE_SAMPLE(an);
+ int rateCode = -1;
+ int frame_size;
+ int size_bin;
+ int best_ndx;
+
+ frame_size = ds->ds_ctl0 & 0x0fff; /* low-order 12 bits of ds_ctl0 */
+ if (frame_size == 0)
+ frame_size = 1500;
+ size_bin = size_to_bin(frame_size);
+ best_ndx = best_rate_ndx(sn, size_bin);
+
+ if (best_ndx == -1 || !sn->stats[size_bin][best_ndx].packets_acked) {
+ /*
+ * no packet has succeeded, so also try twice at the lowest bitate.
+ */
+ if (shortPreamble) {
+ rateCode = sn->rates[0].shortPreambleRateCode;
+ } else {
+ rateCode = sn->rates[0].rateCode;
+ }
+ } else if (sn->rates[best_ndx].rix != rix) {
+ /*
+ * we're trying a different bit-rate, and it could be lossy,
+ * so if it fails try at the best bit-rate.
+ */
+ if (shortPreamble) {
+ rateCode = sn->rates[MAX(0,best_ndx-1)].shortPreambleRateCode;
+ } else {
+ rateCode = sn->rates[MAX(0,best_ndx-1)].rateCode;
+ }
+ }
+ if (rateCode != -1) {
+ ath_hal_setupxtxdesc(sc->sc_ah, ds
+ , rateCode, 1 /* series 1 */
+ , rateCode, 1 /* series 2 */
+ , rateCode, 1 /* series 3 */
+ );
+ }
+
+}
+
+void
+ath_rate_tx_complete(struct ath_softc *sc,
+ struct ath_node *an, const struct ath_desc *ds)
+{
+ struct sample_node *sn = ATH_NODE_SAMPLE(an);
+ struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
+ int rate = sc->sc_hwmap[ds->ds_txstat.ts_rate &~ HAL_TXSTAT_ALTRATE].ieeerate;
+ int retries = ds->ds_txstat.ts_longretry;
+ int initial_rate_failed = ((ds->ds_txstat.ts_rate & HAL_TXSTAT_ALTRATE)
+ || ds->ds_txstat.ts_status != 0 ||
+ retries > 3);
+ int tt = 0;
+ int rix = -1;
+ int x = 0;
+ int frame_size; /* low-order 12 bits of ds_ctl0 */
+ int size_bin;
+ int size;
+
+ if (!sn->num_rates) {
+ DPRINTF(sc, "%s: no rates yet\n", __func__);
+ return;
+ }
+ for (x = 0; x < sn->num_rates; x++) {
+ if (sn->rates[x].rate == rate) {
+ rix = x;
+ break;
+ }
+ }
+
+ if (rix < 0 || rix > sn->num_rates) {
+ /* maybe a management packet */
+ return;
+ }
+
+ frame_size = ds->ds_ctl0 & 0x0fff; /* low-order 12 bits of ds_ctl0 */
+ if (frame_size == 0)
+ frame_size = 1500;
+ size_bin = size_to_bin(frame_size);
+ size = bin_to_size(size_bin);
+ tt = calc_usecs_unicast_packet(sc, size, sn->rates[rix].rix,
+ retries);
+
+ DPRINTF(sc, "%s: rate %d rix %d frame_size %d (%d) retries %d status %d tt %d avg_tt %d perfect_tt %d ts-rate %d\n",
+ __func__, rate, rix, frame_size, size, retries, initial_rate_failed, tt,
+ sn->stats[size_bin][rix].average_tx_time,
+ sn->stats[size_bin][rix].perfect_tx_time,
+ ds->ds_txstat.ts_rate);
+
+ if (sn->stats[size_bin][rix].total_packets < 7) {
+ /* just average the first few packets */
+ int avg_tx = sn->stats[size_bin][rix].average_tx_time;
+ int packets = sn->stats[size_bin][rix].total_packets;
+ sn->stats[size_bin][rix].average_tx_time = (tt+(avg_tx*packets))/(packets+1);
+ } else {
+ /* use a ewma */
+ sn->stats[size_bin][rix].average_tx_time =
+ ((sn->stats[size_bin][rix].average_tx_time * ssc->ath_smoothing_rate) +
+ (tt * (100 - ssc->ath_smoothing_rate))) / 100;
+ }
+
+ if (initial_rate_failed) {
+ /*
+ * this packet failed - count this as a failure
+ * for larger packets also, since we assume
+ * if a small packet fails at a lower bit-rate
+ * then a larger one will also.
+ */
+ int y;
+ for (y = size_bin; y < NUM_PACKET_SIZE_BINS; y++) {
+ sn->stats[y][rix].successive_failures++;
+ sn->stats[y][rix].last_tx = ticks;
+ }
+ } else {
+ sn->stats[size_bin][rix].packets_acked++;
+ sn->stats[size_bin][rix].successive_failures = 0;
+ }
+ sn->stats[size_bin][rix].tries += (1+retries);
+ sn->stats[size_bin][rix].last_tx = ticks;
+ sn->stats[size_bin][rix].total_packets++;
+}
+
+void
+ath_rate_newassoc(struct ath_softc *sc, struct ath_node *an, int isnew)
+{
+ DPRINTF(sc, "%s:\n", __func__);
+ if (isnew)
+ ath_rate_ctl_start(sc, &an->an_node);
+}
+
+static void
+ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni)
+{
+ struct ath_node *an = ATH_NODE(ni);
+ struct sample_node *sn = ATH_NODE_SAMPLE(an);
+ int x = 0;
+ int y = 0;
+
+ for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
+ int size = bin_to_size(y);
+ sn->packets_sent[y] = 0;
+ sn->sample_num[y] = 0;
+
+ for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
+ sn->stats[y][x].successive_failures = 0;
+ sn->stats[y][x].tries = 0;
+ sn->stats[y][x].total_packets = 0;
+ sn->stats[y][x].packets_acked = 0;
+ sn->stats[y][x].last_tx = 0;
+ sn->stats[y][x].perfect_tx_time = calc_usecs_unicast_packet(sc, size,
+ sn->rates[x].rix,
+ 0);
+ sn->stats[y][x].average_tx_time = sn->stats[y][x].perfect_tx_time;
+
+
+ DPRINTF(sc, "%s: %d rate %d rix %d rateCode %d perfect_tx_time %d \n", __func__,
+ x, sn->rates[x].rate,
+ sn->rates[x].rix, sn->rates[x].rateCode,
+ sn->stats[0][x].perfect_tx_time);
+ }
+
+ }
+
+ /* set the visible bit-rate to the lowest one available */
+ ni->ni_txrate = 0;
+
+}
+
+/*
+ * Initialize the tables for a node.
+ */
+static void
+ath_rate_ctl_start(struct ath_softc *sc, struct ieee80211_node *ni)
+{
+#define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL)
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ath_node *an = ATH_NODE(ni);
+ struct sample_node *sn = ATH_NODE_SAMPLE(an);
+ const HAL_RATE_TABLE *rt = sc->sc_currates;
+
+ int x;
+ int srate;
+
+ DPRINTF(sc, "%s:\n", __func__);
+ KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
+ KASSERT(ni->ni_rates.rs_nrates > 0, ("no rates"));
+ sn->static_rate_ndx = -1;
+ if (ic->ic_fixed_rate != -1) {
+ /*
+ * A fixed rate is to be used; ic_fixed_rate is an
+ * index into the supported rate set. Convert this
+ * to the index into the negotiated rate set for
+ * the node. We know the rate is there because the
+ * rate set is checked when the station associates.
+ */
+ const struct ieee80211_rateset *rs =
+ &ic->ic_sup_rates[ic->ic_curmode];
+ int r = rs->rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
+ /* NB: the rate set is assumed sorted */
+ srate = ni->ni_rates.rs_nrates - 1;
+ for (; srate >= 0 && RATE(srate) != r; srate--)
+ ;
+ KASSERT(srate >= 0,
+ ("fixed rate %d not in rate set", ic->ic_fixed_rate));
+ sn->static_rate_ndx = srate;
+
+ }
+ sn->num_rates = ni->ni_rates.rs_nrates;
+ for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
+ sn->rates[x].rate = ni->ni_rates.rs_rates[x] & IEEE80211_RATE_VAL;
+ sn->rates[x].rix = sc->sc_rixmap[sn->rates[x].rate];
+ sn->rates[x].rateCode = rt->info[sn->rates[x].rix].rateCode;
+ sn->rates[x].shortPreambleRateCode =
+ rt->info[sn->rates[x].rix].rateCode |
+ rt->info[sn->rates[x].rix].shortPreamble;
+ }
+ ath_rate_ctl_reset(sc, ni);
+
+#undef RATE
+}
+
+/*
+ * Reset the rate control state for each 802.11 state transition.
+ */
+void
+ath_rate_newstate(struct ath_softc *sc, enum ieee80211_state state)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+
+ if (state == IEEE80211_S_RUN)
+ ath_rate_newassoc(sc, ATH_NODE(ic->ic_bss), 1);
+}
+
+static void
+ath_rate_sysctlattach(struct ath_softc *sc, struct sample_softc *osc)
+{
+ struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
+ struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
+
+ /* XXX bounds check [0..100] */
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "smoothing_rate", CTLFLAG_RW, &osc->ath_smoothing_rate, 0,
+ "rate control: retry threshold to credit rate raise (%%)");
+ /* XXX bounds check [2..100] */
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "sample_rate", CTLFLAG_RW, &osc->ath_sample_rate,0,
+ "rate control: # good periods before raising rate");
+}
+
+struct ath_ratectrl *
+ath_rate_attach(struct ath_softc *sc)
+{
+ struct sample_softc *osc;
+
+ DPRINTF(sc, "%s:\n", __func__);
+ osc = malloc(sizeof(struct sample_softc), M_DEVBUF, M_NOWAIT|M_ZERO);
+ if (osc == NULL)
+ return NULL;
+ osc->arc.arc_space = sizeof(struct sample_node);
+ osc->ath_smoothing_rate = 95; /* ewma percentage (out of 100) */
+ osc->ath_sample_rate = 10; /* send a different bit-rate 1/X packets */
+ ath_rate_sysctlattach(sc, osc);
+ return &osc->arc;
+}
+
+void
+ath_rate_detach(struct ath_ratectrl *arc)
+{
+ struct sample_softc *osc = (struct sample_softc *) arc;
+
+ free(osc, M_DEVBUF);
+}
+
+/*
+ * Module glue.
+ */
+static int
+sample_modevent(module_t mod, int type, void *unused)
+{
+ switch (type) {
+ case MOD_LOAD:
+ if (bootverbose)
+ printf("ath_rate: <SampleRate bit-rate selection algorithm>\n");
+ return 0;
+ case MOD_UNLOAD:
+ return 0;
+ }
+ return EINVAL;
+}
+
+static moduledata_t sample_mod = {
+ "ath_rate",
+ sample_modevent,
+ 0
+};
+DECLARE_MODULE(ath_rate, sample_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
+MODULE_VERSION(ath_rate, 1);
+MODULE_DEPEND(ath_rate, wlan, 1, 1, 1);
diff --git a/sys/dev/ath/ath_rate/sample/sample.h b/sys/dev/ath/ath_rate/sample/sample.h
new file mode 100644
index 0000000..3c6c5e4
--- /dev/null
+++ b/sys/dev/ath/ath_rate/sample/sample.h
@@ -0,0 +1,136 @@
+/*-
+ * Copyright (c) 2005 John Bicket
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Defintions for the Atheros Wireless LAN controller driver.
+ */
+#ifndef _DEV_ATH_RATE_SAMPLE_H
+#define _DEV_ATH_RATE_SAMPLE_H
+
+/* per-device state */
+struct sample_softc {
+ struct ath_ratectrl arc; /* base state */
+ int ath_smoothing_rate; /* ewma percentage (out of 100) */
+ int ath_sample_rate; /* send a different bit-rate 1/X packets */
+};
+#define ATH_SOFTC_SAMPLE(sc) ((struct sample_softc *)sc->sc_rc)
+
+struct rate_info {
+ int rate;
+ int rix;
+ int rateCode;
+ int shortPreambleRateCode;
+};
+
+
+struct rate_stats {
+ int average_tx_time;
+ int successive_failures;
+ int tries;
+ int total_packets;
+ int packets_acked;
+ int perfect_tx_time; /* transmit time for 0 retries */
+ int last_tx;
+};
+
+/*
+ * for now, we track performance for three different packet
+ * size buckets
+ */
+#define NUM_PACKET_SIZE_BINS 3
+static int packet_size_bins[NUM_PACKET_SIZE_BINS] = {250, 1600, 3000};
+
+/* per-node state */
+struct sample_node {
+ int static_rate_ndx;
+ int num_rates;
+
+ struct rate_info rates[IEEE80211_RATE_MAXSIZE];
+
+ struct rate_stats stats[NUM_PACKET_SIZE_BINS][IEEE80211_RATE_MAXSIZE];
+ int sample_num[NUM_PACKET_SIZE_BINS];
+ int packets_sent[NUM_PACKET_SIZE_BINS];
+
+};
+#define ATH_NODE_SAMPLE(an) ((struct sample_node *)&an[1])
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+#define WIFI_CW_MIN 31
+#define WIFI_CW_MAX 1023
+
+/*
+ * Calculate the transmit duration of a frame.
+ */
+static unsigned calc_usecs_unicast_packet(struct ath_softc *sc,
+ int length,
+ int rix, int retries) {
+ const HAL_RATE_TABLE *rt = sc->sc_currates;
+
+
+ /* pg 205 ieee.802.11.pdf */
+ unsigned t_slot = 20;
+ unsigned t_difs = 50;
+ unsigned t_sifs = 10;
+ int tt = 0;
+ int x = 0;
+ int cw = WIFI_CW_MIN;
+ int cix = rt->info[rix].controlRate;
+ KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
+
+ if (rt->info[rix].phy == IEEE80211_T_OFDM) {
+ t_slot = 9;
+ t_sifs = 9;
+ t_difs = 28;
+ }
+ tt += t_difs;
+ tt += (retries+1)*(t_sifs + rt->info[cix].spAckDuration);
+ tt += (retries+1)*ath_hal_computetxtime(sc->sc_ah, rt, length,
+ rix, AH_TRUE);
+ for (x = 0; x <= retries; x++) {
+ cw = MIN(WIFI_CW_MAX, (cw + 1) * 2);
+ tt += (t_slot * cw/2);
+ }
+ return tt;
+}
+#endif /* _DEV_ATH_RATE_SAMPLE_H */
diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES
index d5fc156..6dddd96 100644
--- a/sys/i386/conf/NOTES
+++ b/sys/i386/conf/NOTES
@@ -585,6 +585,7 @@ device ath
device ath_hal # Atheros HAL (includes binary component)
device ath_rate_onoe # Onoe rate control for ath driver
#device ath_rate_amrr # AMRR rate control for ath driver
+#device ath_rate_sample # SampleRate rate control for the ath driver
#device wlan # 802.11 layer
#
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index 9ed67d7..2dbc06d 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -27,6 +27,7 @@ SUBDIR= ${_3dfx} \
${_ath_hal} \
ath_rate_amrr \
ath_rate_onoe \
+ ath_rate_sample \
aue \
${_auxio} \
${_awi} \
diff --git a/sys/modules/ath_rate_sample/Makefile b/sys/modules/ath_rate_sample/Makefile
new file mode 100644
index 0000000..1ce6ea3
--- /dev/null
+++ b/sys/modules/ath_rate_sample/Makefile
@@ -0,0 +1,48 @@
+#
+# Copyright (c) 2004 Sam Leffler, Errno Consulting
+# 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.
+#
+# $FreeBSD$
+#
+
+.PATH: ${.CURDIR}/../../dev/ath/ath_rate/sample
+
+KMOD= ath_rate
+SRCS= sample.c
+SRCS+= opt_bdg.h device_if.h bus_if.h pci_if.h opt_inet.h
+
+HAL= ${.CURDIR}/../../contrib/dev/ath
+CFLAGS+= -I. -I${HAL}/freebsd -I${HAL}
+
+.include <bsd.kmod.mk>
OpenPOWER on IntegriCloud