summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2005-11-23 20:23:52 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2005-11-23 20:23:52 +0000
commit0ceaa7af952f1804d03c7f517933ac2959f2a546 (patch)
tree6104f29d8089863b703367dc2f55e3c76851b142
parent5a4092f96da8ee676546eb76cfea0d2a119a021b (diff)
Implement the Adaptive Multi Rate Retry algorithm (AMRR) for BSS mode.
This algorithm is particularly well suited for ural since it does not require per-frame retry statistics.
-rw-r--r--share/man/man4/ral.44
-rw-r--r--sys/dev/usb/if_ral.c187
-rw-r--r--sys/dev/usb/if_ralvar.h16
3 files changed, 200 insertions, 7 deletions
diff --git a/share/man/man4/ral.4 b/share/man/man4/ral.4
index 1cc511358f0..c9be1d6ee51 100644
--- a/share/man/man4/ral.4
+++ b/share/man/man4/ral.4
@@ -1,4 +1,4 @@
-.\" $OpenBSD: ral.4,v 1.43 2005/09/19 20:08:20 damien Exp $
+.\" $OpenBSD: ral.4,v 1.44 2005/11/23 20:23:51 damien Exp $
.\"
.\" Copyright (c) 2005
.\" Damien Bergamini <damien.bergamini@free.fr>
@@ -437,4 +437,4 @@ specification.
.Pp
The
.Nm ural
-driver does not support automatic adaptation of the transmit speed.
+driver supports automatic adaptation of the transmit speed in BSS mode only.
diff --git a/sys/dev/usb/if_ral.c b/sys/dev/usb/if_ral.c
index 270ae7e3a2c..59a648578f6 100644
--- a/sys/dev/usb/if_ral.c
+++ b/sys/dev/usb/if_ral.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_ral.c,v 1.46 2005/11/23 19:56:51 damien Exp $ */
+/* $OpenBSD: if_ral.c,v 1.47 2005/11/23 20:23:48 damien Exp $ */
/*-
* Copyright (c) 2005
@@ -158,6 +158,13 @@ Static void ural_set_txantenna(struct ural_softc *, int);
Static void ural_set_rxantenna(struct ural_softc *, int);
Static int ural_init(struct ifnet *);
Static void ural_stop(struct ifnet *, int);
+Static void ural_amrr_start(struct ural_softc *,
+ struct ieee80211_node *);
+Static void ural_amrr_timeout(void *);
+Static void ural_amrr_update(usbd_xfer_handle, usbd_private_handle,
+ usbd_status status);
+Static void ural_ratectl(struct ural_amrr *,
+ struct ieee80211_node *);
/*
* Supported rates for 802.11a/b/g modes (in 500Kbps unit).
@@ -409,6 +416,7 @@ USB_ATTACH(ural)
usb_init_task(&sc->sc_task, ural_task, sc);
timeout_set(&sc->scan_ch, ural_next_scan, sc);
+ timeout_set(&sc->amrr_ch, ural_amrr_timeout, sc);
/* retrieve RT2570 rev. no */
sc->asic_rev = ural_read(sc, RAL_MAC_CSR0);
@@ -510,6 +518,12 @@ USB_DETACH(ural)
usb_rem_task(sc->sc_udev, &sc->sc_task);
timeout_del(&sc->scan_ch);
+ timeout_del(&sc->amrr_ch);
+
+ if (sc->amrr_xfer != NULL) {
+ usbd_free_xfer(sc->amrr_xfer);
+ sc->amrr_xfer = NULL;
+ }
if (sc->sc_rx_pipeh != NULL) {
usbd_abort_pipe(sc->sc_rx_pipeh);
@@ -776,6 +790,12 @@ ural_task(void *arg)
if (ic->ic_opmode != IEEE80211_M_MONITOR)
ural_enable_tsf_sync(sc);
+
+ /* enable automatic rate adaptation in STA mode */
+ if (ic->ic_opmode == IEEE80211_M_STA &&
+ ic->ic_fixed_rate == -1)
+ ural_amrr_start(sc, ic->ic_bss);
+
break;
}
@@ -789,6 +809,7 @@ ural_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
usb_rem_task(sc->sc_udev, &sc->sc_task);
timeout_del(&sc->scan_ch);
+ timeout_del(&sc->amrr_ch);
/* do it in a process context */
sc->sc_state = nstate;
@@ -1244,7 +1265,6 @@ ural_tx_data(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
usbd_status error;
int xferlen, rate;
- /* XXX this should be reworked! */
if (ic->ic_fixed_rate != -1) {
if (ic->ic_curmode != IEEE80211_MODE_AUTO)
rs = &ic->ic_sup_rates[ic->ic_curmode];
@@ -1982,7 +2002,7 @@ ural_init(struct ifnet *ifp)
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_wepkey *wk;
struct ural_rx_data *data;
- uint16_t sta[11], tmp;
+ uint16_t tmp;
usbd_status error;
int i, ntries;
@@ -2022,7 +2042,7 @@ ural_init(struct ifnet *ifp)
ural_set_chan(sc, ic->ic_bss->ni_chan);
/* clear statistic registers (STA_CSR0 to STA_CSR10) */
- ural_read_multi(sc, RAL_STA_CSR0, sta, sizeof sta);
+ ural_read_multi(sc, RAL_STA_CSR0, sc->sta, sizeof sc->sta);
/* set default sensitivity */
ural_bbp_write(sc, 17, 0x48);
@@ -2043,6 +2063,16 @@ ural_init(struct ifnet *ifp)
}
/*
+ * Allocate xfer for AMRR statistics requests.
+ */
+ sc->amrr_xfer = usbd_alloc_xfer(sc->sc_udev);
+ if (sc->amrr_xfer == NULL) {
+ printf("%s: could not allocate AMRR xfer\n",
+ USBDEVNAME(sc->sc_dev));
+ goto fail;
+ }
+
+ /*
* Open Tx and Rx USB bulk pipes.
*/
error = usbd_open_pipe(sc->sc_iface, sc->sc_tx_no, USBD_EXCLUSIVE_USE,
@@ -2134,6 +2164,11 @@ ural_stop(struct ifnet *ifp, int disable)
ifp->if_timer = 0;
ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+ if (sc->amrr_xfer != NULL) {
+ usbd_free_xfer(sc->amrr_xfer);
+ sc->amrr_xfer = NULL;
+ }
+
if (sc->sc_rx_pipeh != NULL) {
usbd_abort_pipe(sc->sc_rx_pipeh);
usbd_close_pipe(sc->sc_rx_pipeh);
@@ -2150,6 +2185,150 @@ ural_stop(struct ifnet *ifp, int disable)
ural_free_tx_list(sc);
}
+Static void
+ural_amrr_start(struct ural_softc *sc, struct ieee80211_node *ni)
+{
+ struct ural_amrr *amrr = &sc->amrr;
+ int i;
+
+ /* clear statistic registers (STA_CSR0 to STA_CSR10) */
+ ural_read_multi(sc, RAL_STA_CSR0, sc->sta, sizeof sc->sta);
+
+ amrr->success = 0;
+ amrr->recovery = 0;
+ amrr->success_threshold = 0;
+ amrr->txcnt = amrr->retrycnt = 0;
+
+ /* 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;
+
+ timeout_add(&sc->amrr_ch, hz);
+}
+
+Static void
+ural_amrr_timeout(void *arg)
+{
+ struct ural_softc *sc = (struct ural_softc *)arg;
+ usb_device_request_t req;
+ int s;
+
+ s = splusb();
+
+ /*
+ * Asynchronously read statistic registers (cleared by read).
+ */
+ req.bmRequestType = UT_READ_VENDOR_DEVICE;
+ req.bRequest = RAL_READ_MULTI_MAC;
+ USETW(req.wValue, 0);
+ USETW(req.wIndex, RAL_STA_CSR0);
+ USETW(req.wLength, 22);
+
+ usbd_setup_default_xfer(sc->amrr_xfer, sc->sc_udev, sc,
+ USBD_DEFAULT_TIMEOUT, &req, sc->sta, 22, 0, ural_amrr_update);
+ (void)usbd_transfer(sc->amrr_xfer);
+
+ splx(s);
+}
+
+Static void
+ural_amrr_update(usbd_xfer_handle xfer, usbd_private_handle priv,
+ usbd_status status)
+{
+ struct ural_softc *sc = (struct ural_softc *)priv;
+ struct ural_amrr *amrr = &sc->amrr;
+
+ if (status != USBD_NORMAL_COMPLETION)
+ return;
+
+ amrr->retrycnt =
+ sc->sta[7] + /* TX one-retry ok count */
+ sc->sta[8] + /* TX more-retry ok count */
+ sc->sta[8]; /* TX retry-fail count */
+
+ amrr->txcnt =
+ amrr->retrycnt +
+ sc->sta[6]; /* TX no-retry ok count */
+
+ ural_ratectl(amrr, sc->sc_ic.ic_bss);
+
+ timeout_add(&sc->amrr_ch, hz);
+}
+
+/*-
+ * Naive implementation of the Adaptive Multi Rate Retry algorithm:
+ * "IEEE 802.11 Rate Adaptation: A Practical Approach"
+ * Mathieu Lacage, Hossein Manshaei, Thierry Turletti
+ * INRIA Sophia - Projet Planete
+ * http://www-sop.inria.fr/rapports/sophia/RR-5208.html
+ *
+ * This algorithm is particularly well suited for ural since it does not
+ * require per-frame retry statistics. Note however that since h/w does
+ * not provide per-frame stats, we can't do per-node rate adaptation and
+ * thus automatic rate adaptation is only enabled in STA operating mode.
+ */
+
+#define URAL_AMRR_MIN_SUCCESS_THRESHOLD 1
+#define URAL_AMRR_MAX_SUCCESS_THRESHOLD 10
+
+#define is_success(amrr) \
+ ((amrr)->retrycnt < (amrr)->txcnt / 10)
+#define is_failure(amrr) \
+ ((amrr)->retrycnt > (amrr)->txcnt / 3)
+#define is_enough(amrr) \
+ ((amrr)->txcnt > 10)
+#define is_min_rate(ni) \
+ ((ni)->ni_txrate == 0)
+#define is_max_rate(ni) \
+ ((ni)->ni_txrate == (ni)->ni_rates.rs_nrates - 1)
+#define increase_rate(ni) \
+ ((ni)->ni_txrate++)
+#define decrease_rate(ni) \
+ ((ni)->ni_txrate--)
+#define reset_cnt(amrr) \
+ do { (amrr)->txcnt = (amrr)->retrycnt = 0; } while (0)
+Static void
+ural_ratectl(struct ural_amrr *amrr, struct ieee80211_node *ni)
+{
+ int need_change = 0;
+
+ if (is_success(amrr) && is_enough(amrr)) {
+ amrr->success++;
+ if (amrr->success >= amrr->success_threshold &&
+ !is_max_rate(ni)) {
+ amrr->recovery = 1;
+ amrr->success = 0;
+ increase_rate(ni);
+ need_change = 1;
+ } else {
+ amrr->recovery = 0;
+ }
+ } else if (is_failure(amrr)) {
+ amrr->success = 0;
+ if (!is_min_rate(ni)) {
+ if (amrr->recovery) {
+ amrr->success_threshold *= 2;
+ if (amrr->success_threshold >
+ URAL_AMRR_MAX_SUCCESS_THRESHOLD)
+ amrr->success_threshold =
+ URAL_AMRR_MAX_SUCCESS_THRESHOLD;
+ } else {
+ amrr->success_threshold =
+ URAL_AMRR_MIN_SUCCESS_THRESHOLD;
+ }
+ decrease_rate(ni);
+ need_change = 1;
+ }
+ amrr->recovery = 0; /* original paper was incorrect */
+ }
+
+ if (is_enough(amrr) || need_change)
+ reset_cnt(amrr);
+}
+
Static int
ural_activate(device_ptr_t self, enum devact act)
{
diff --git a/sys/dev/usb/if_ralvar.h b/sys/dev/usb/if_ralvar.h
index 9b553b20c41..6c9eb9eefd6 100644
--- a/sys/dev/usb/if_ralvar.h
+++ b/sys/dev/usb/if_ralvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_ralvar.h,v 1.2 2005/05/13 18:42:50 damien Exp $ */
+/* $OpenBSD: if_ralvar.h,v 1.3 2005/11/23 20:23:48 damien Exp $ */
/*-
* Copyright (c) 2005
@@ -67,6 +67,14 @@ struct ural_rx_data {
struct mbuf *m;
};
+struct ural_amrr {
+ int txcnt;
+ int retrycnt;
+ int success;
+ int success_threshold;
+ int recovery;
+};
+
struct ural_softc {
USBBASEDEVICE sc_dev;
struct ieee80211com sc_ic;
@@ -82,20 +90,26 @@ struct ural_softc {
uint32_t asic_rev;
uint8_t rf_rev;
+ usbd_xfer_handle amrr_xfer;
+
usbd_pipe_handle sc_rx_pipeh;
usbd_pipe_handle sc_tx_pipeh;
enum ieee80211_state sc_state;
struct usb_task sc_task;
+ struct ural_amrr amrr;
+
struct ural_rx_data rx_data[RAL_RX_LIST_COUNT];
struct ural_tx_data tx_data[RAL_TX_LIST_COUNT];
int tx_queued;
struct timeout scan_ch;
+ struct timeout amrr_ch;
int sc_tx_timer;
+ uint16_t sta[11];
uint32_t rf_regs[4];
uint8_t txpow[14];