summaryrefslogtreecommitdiff
path: root/sys/dev/ic/acx.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ic/acx.c')
-rw-r--r--sys/dev/ic/acx.c273
1 files changed, 79 insertions, 194 deletions
diff --git a/sys/dev/ic/acx.c b/sys/dev/ic/acx.c
index 92721cd8af3..12eb1f4edac 100644
--- a/sys/dev/ic/acx.c
+++ b/sys/dev/ic/acx.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: acx.c,v 1.46 2006/08/15 21:16:08 mglocker Exp $ */
+/* $OpenBSD: acx.c,v 1.47 2006/08/19 23:17:12 mglocker Exp $ */
/*
* Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org>
@@ -123,6 +123,7 @@
#endif
#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_amrr.h>
#include <net80211/ieee80211_radiotap.h>
#include <dev/pci/pcireg.h>
@@ -189,9 +190,6 @@ int acx_load_base_firmware(struct acx_softc *, const char *);
struct ieee80211_node
*acx_node_alloc(struct ieee80211com *);
-void acx_node_init(struct acx_softc *, struct acx_node *);
-void acx_node_update(struct acx_softc *, struct acx_node *,
- uint8_t, uint8_t);
int acx_newstate(struct ieee80211com *, enum ieee80211_state, int);
void acx_init_cmd_reg(struct acx_softc *);
@@ -200,6 +198,10 @@ int acx_enable_txchan(struct acx_softc *, uint8_t);
int acx_enable_rxchan(struct acx_softc *, uint8_t);
int acx_init_radio(struct acx_softc *, uint32_t, uint32_t);
+void acx_iter_func(void *, struct ieee80211_node *);
+void acx_amrr_timeout(void *);
+void acx_newassoc(struct ieee80211com *, struct ieee80211_node *, int);
+
const struct ieee80211_rateset acx_rates_11b =
{ 4, { 2, 4, 11, 22 } };
const struct ieee80211_rateset acx_rates_11g =
@@ -293,6 +295,10 @@ acx_attach(struct acx_softc *sc)
ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
+ /* set supported .11b and .11g rates */
+ ic->ic_sup_rates[IEEE80211_MODE_11B] = acx_rates_11b;
+ ic->ic_sup_rates[IEEE80211_MODE_11G] = acx_rates_11g;
+
/* Set channels */
for (i = 1; i <= 14; ++i) {
ic->ic_channels[i].ic_freq =
@@ -324,6 +330,7 @@ acx_attach(struct acx_softc *sc)
/* Override node alloc */
ic->ic_node_alloc = acx_node_alloc;
+ ic->ic_newassoc = acx_newassoc;
/* Override newstate */
sc->sc_newstate = ic->ic_newstate;
@@ -335,9 +342,11 @@ acx_attach(struct acx_softc *sc)
ieee80211_media_init(ifp, ieee80211_media_change,
ieee80211_media_status);
- sc->sc_txrate_upd_intvl_min = 10; /* 10 seconds */
- sc->sc_txrate_upd_intvl_max = 300; /* 5 minutes */
- sc->sc_txrate_sample_thresh = 30; /* 30 packets */
+ /* AMRR rate control */
+ sc->amrr.amrr_min_success_threshold = 1;
+ sc->amrr.amrr_max_success_threshold = 15;
+ timeout_set(&sc->amrr_ch, acx_amrr_timeout, sc);
+
sc->sc_long_retry_limit = 4;
sc->sc_short_retry_limit = 7;
sc->sc_msdu_lifetime = 4096;
@@ -882,22 +891,16 @@ acx_start(struct ifnet *ifp)
IF_DEQUEUE(&ic->ic_mgtq, m);
if (m != NULL) {
-
ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
m->m_pkthdr.rcvif = NULL;
-#if 0
/*
- * Since mgmt data are transmitted at fixed rate
- * they will not be used to do rate control.
+ * mgmt frames are sent at the lowest available
+ * bit-rate.
*/
- if (ni != NULL)
- ieee80211_free_node(ni);
-#endif
- rate = 4; /* XXX 2Mb/s for mgmt packet */
+ rate = ni->ni_rates.rs_rates[0];
} else if (!IFQ_IS_EMPTY(&ifp->if_snd)) {
struct ether_header *eh;
- struct acx_node *node;
if (ic->ic_state != IEEE80211_S_RUN) {
DPRINTF(("%s: data packet dropped due to "
@@ -943,24 +946,12 @@ acx_start(struct ifnet *ifp)
bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT);
#endif
- node = (struct acx_node *)ni;
- if (node->nd_txrate < 0) {
- acx_node_init(sc, node);
-#if 0
- if (ic->ic_opmode == IEEE80211_M_IBSS) {
- /* XXX
- * Add extra reference here,
- * so that some node (bss_dup)
- * will not be freed just after
- * they are allocated, which
- * make TX rate control impossible
- */
- ieee80211_ref_node(ni);
- }
-#endif
- }
-
- rate = node->nd_rates.rs_rates[node->nd_txrate];
+ if (ic->ic_fixed_rate != -1) {
+ rate = ic->ic_sup_rates[ic->ic_curmode].
+ rs_rates[ic->ic_fixed_rate];
+ } else
+ rate = ni->ni_rates.rs_rates[ni->ni_txrate];
+ rate &= IEEE80211_RATE_VAL;
} else
break;
@@ -1139,7 +1130,6 @@ acx_txeof(struct acx_softc *sc)
ic = &sc->sc_ic;
ni = (struct ieee80211_node *)buf->tb_node;
- acx_node_update(sc, buf->tb_node, buf->tb_rate, error);
ieee80211_release_node(ic, ni);
buf->tb_node = NULL;
}
@@ -1647,169 +1637,16 @@ acx_load_firmware(struct acx_softc *sc, uint32_t offset, const uint8_t *data,
struct ieee80211_node *
acx_node_alloc(struct ieee80211com *ic)
{
- struct acx_node *node;
+ struct acx_node *wn;
- node = malloc(sizeof(struct acx_node), M_DEVBUF, M_NOWAIT);
- if (node == NULL)
+ wn = malloc(sizeof(struct acx_node), M_DEVBUF, M_NOWAIT);
+ if (wn == NULL)
return (NULL);
- bzero(node, (sizeof(struct acx_node)));
- node->nd_txrate = -1;
-
- return ((struct ieee80211_node *)node);
-}
-
-void
-acx_node_init(struct acx_softc *sc, struct acx_node *node)
-{
- struct ieee80211_rateset *nd_rset, *ic_rset, *cp_rset;
- struct ieee80211com *ic;
- int i, j, c;
-
- ic = &sc->sc_ic;
-
- nd_rset = &node->nd_node.ni_rates;
- ic_rset = &ic->ic_sup_rates[sc->chip_phymode];
- cp_rset = &node->nd_rates;
- c = 0;
-
-#define IEEERATE(rate) ((rate) & IEEE80211_RATE_VAL)
- for (i = 0; i < nd_rset->rs_nrates; ++i) {
- uint8_t nd_rate = IEEERATE(nd_rset->rs_rates[i]);
-
- for (j = 0; j < ic_rset->rs_nrates; ++j) {
- if (nd_rate == IEEERATE(ic_rset->rs_rates[j])) {
- cp_rset->rs_rates[c++] = nd_rate;
- if (node->nd_txrate < 0) {
- /* XXX slow start?? */
- node->nd_txrate = 0;
- node->nd_node.ni_txrate = i;
- }
- break;
- }
- }
- }
- if (node->nd_node.ni_txrate < 0)
- panic("no compat rates");
- DPRINTF(("%s: node rate %d\n",
- sc->sc_dev.dv_xname,
- IEEERATE(nd_rset->rs_rates[node->nd_node.ni_txrate])));
-#undef IEEERATE
-
- cp_rset->rs_nrates = c;
+ bzero(wn, sizeof(struct acx_node));
+ //node->nd_txrate = -1;
- node->nd_txrate_upd_intvl = sc->sc_txrate_upd_intvl_min;
- node->nd_txrate_upd_time = time_second;
- node->nd_txrate_sample = 0;
-}
-
-void
-acx_node_update(struct acx_softc *sc, struct acx_node *node, uint8_t rate,
- uint8_t error)
-{
- struct ieee80211_rateset *nd_rset, *cp_rset;
- int i, time_diff;
-
- nd_rset = &node->nd_node.ni_rates;
- cp_rset = &node->nd_rates;
-
- time_diff = time_second - node->nd_txrate_upd_time;
-
- if (error == DESC_ERR_MSDU_TIMEOUT ||
- error == DESC_ERR_EXCESSIVE_RETRY) {
- uint8_t cur_rate;
-
- /* Reset packet sample counter */
- node->nd_txrate_sample = 0;
-
- if (rate > cp_rset->rs_rates[node->nd_txrate]) {
- /*
- * This rate has already caused troubles,
- * so don't count it in here.
- */
- return;
- }
-
- /* Double TX rate updating interval */
- node->nd_txrate_upd_intvl *= 2;
- if (node->nd_txrate_upd_intvl <=
- sc->sc_txrate_upd_intvl_min) {
- node->nd_txrate_upd_intvl =
- sc->sc_txrate_upd_intvl_min;
- } else if (node->nd_txrate_upd_intvl >
- sc->sc_txrate_upd_intvl_max) {
- node->nd_txrate_upd_intvl =
- sc->sc_txrate_upd_intvl_max;
- }
-
- if (node->nd_txrate == 0)
- return;
-
- node->nd_txrate_upd_time += time_diff;
-
- /* TX rate down */
- node->nd_txrate--;
- cur_rate = cp_rset->rs_rates[node->nd_txrate + 1];
- while (cp_rset->rs_rates[node->nd_txrate] > cur_rate) {
- if (node->nd_txrate - 1 > 0)
- node->nd_txrate--;
- else
- break;
- }
- DPRINTF(("%s: rate down %s %d -> %d\n",
- sc->sc_dev.dv_xname,
- ether_sprintf(node->nd_node.ni_macaddr),
- cp_rset->rs_rates[node->nd_txrate + 1],
- cp_rset->rs_rates[node->nd_txrate]));
- } else if (node->nd_txrate + 1 < node->nd_rates.rs_nrates) {
- uint8_t cur_rate;
-
- node->nd_txrate_sample++;
-
- if (node->nd_txrate_sample <= sc->sc_txrate_sample_thresh ||
- time_diff <= node->nd_txrate_upd_intvl)
- return;
-
- /* Reset packet sample counter */
- node->nd_txrate_sample = 0;
-
- /* Half TX rate updating interval */
- node->nd_txrate_upd_intvl /= 2;
- if (node->nd_txrate_upd_intvl < sc->sc_txrate_upd_intvl_min) {
- node->nd_txrate_upd_intvl = sc->sc_txrate_upd_intvl_min;
- } else if (node->nd_txrate_upd_intvl >
- sc->sc_txrate_upd_intvl_max) {
- node->nd_txrate_upd_intvl = sc->sc_txrate_upd_intvl_max;
- }
-
- node->nd_txrate_upd_time += time_diff;
-
- /* TX Rate up */
- node->nd_txrate++;
- cur_rate = cp_rset->rs_rates[node->nd_txrate - 1];
- while (cp_rset->rs_rates[node->nd_txrate] < cur_rate) {
- if (node->nd_txrate + 1 < cp_rset->rs_nrates)
- node->nd_txrate++;
- else
- break;
- }
- DPRINTF(("%s: rate up %s %d -> %d\n",
- sc->sc_dev.dv_xname,
- ether_sprintf(node->nd_node.ni_macaddr),
- cur_rate, cp_rset->rs_rates[node->nd_txrate]));
- } else
- return;
-
-#define IEEERATE(rate) ((rate) & IEEE80211_RATE_VAL)
- /* XXX Update ieee80211_node's TX rate index */
- for (i = 0; i < nd_rset->rs_nrates; ++i) {
- if (IEEERATE(nd_rset->rs_rates[i]) ==
- cp_rset->rs_rates[node->nd_txrate]) {
- node->nd_node.ni_txrate = i;
- break;
- }
- }
-#undef IEEERATE
+ return ((struct ieee80211_node *)wn);
}
int
@@ -1819,6 +1656,8 @@ acx_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
struct ifnet *ifp = &ic->ic_if;
int error = 0;
+ timeout_del(&sc->amrr_ch);
+
switch (nstate) {
case IEEE80211_S_INIT:
break;
@@ -1925,6 +1764,14 @@ acx_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
DPRINTF(("%s: join IBSS\n", sc->sc_dev.dv_xname));
error = 0;
}
+
+ /* fake a join to init the tx rate */
+ if (ic->ic_opmode == IEEE80211_M_STA)
+ acx_newassoc(ic, ic->ic_bss, 1);
+
+ /* start automatic rate control timer */
+ if (ic->ic_fixed_rate == -1)
+ timeout_add(&sc->amrr_ch, hz / 2);
break;
default:
break;
@@ -2768,3 +2615,41 @@ acx_get_maxrssi(int radio)
default: return ACX_RADIO_RSSI_UNKN;
}
}
+
+void
+acx_iter_func(void *arg, struct ieee80211_node *ni)
+{
+ struct acx_softc *sc = arg;
+ struct acx_node *wn = (struct acx_node *)ni;
+
+ ieee80211_amrr_choose(&sc->amrr, ni, &wn->amn);
+}
+
+void
+acx_amrr_timeout(void *arg)
+{
+ struct acx_softc *sc = arg;
+ struct ieee80211com *ic = &sc->sc_ic;
+
+ if (ic->ic_opmode == IEEE80211_M_STA)
+ acx_iter_func(sc, ic->ic_bss);
+ else
+ ieee80211_iterate_nodes(ic, acx_iter_func, sc);
+
+ timeout_add(&sc->amrr_ch, hz / 2);
+}
+
+void
+acx_newassoc(struct ieee80211com *ic, struct ieee80211_node *ni, int isnew)
+{
+ struct acx_softc *sc = ic->ic_if.if_softc;
+ int i;
+
+ ieee80211_amrr_node_init(&sc->amrr, &((struct acx_node *)ni)->amn);
+
+ /* set rate to some reasonable initial value */
+ for (i = ni->ni_rates.rs_nrates - 1;
+ i > 0 && (ni->ni_rates.rs_rates[i] & IEEE80211_RATE_VAL) > 72;
+ i--);
+ ni->ni_txrate = i;
+}