From 7427ac33bde94f6ad570b31acf9f8523a20db8c5 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Fri, 1 Sep 2006 15:13:15 +0000 Subject: [PATCH] - More reverse engineer: acx111 does support multi-rate retry! Collaborated-with: Darron Broad - Utilize the new TX rate control algorithm framework in 802.11 layer. - Support Onoe TX rate control algorithm for acx100. - Support Onoe TX rate control algorithm and AMRR TX rate control algorithm for acx111. Use AMRR for acx111 by default. - Use ieee80211_beacon_alloc() in acx_set_{probe_resp,beacon}_tmplt(), this corrects IBSS mode support and makes HOSTAP mode support possible. - Add support for HOSTAP mode. --- sys/dev/netif/acx/Makefile | 4 +- sys/dev/netif/acx/acx100.c | 50 ++- sys/dev/netif/acx/acx111.c | 265 +++++++++++++++- sys/dev/netif/acx/acxcmd.h | 6 +- sys/dev/netif/acx/if_acx.c | 557 +++++----------------------------- sys/dev/netif/acx/if_acxvar.h | 39 ++- 6 files changed, 393 insertions(+), 528 deletions(-) diff --git a/sys/dev/netif/acx/Makefile b/sys/dev/netif/acx/Makefile index 4b4455b7c3..28f1f1c13c 100644 --- a/sys/dev/netif/acx/Makefile +++ b/sys/dev/netif/acx/Makefile @@ -1,7 +1,9 @@ -# $DragonFly: src/sys/dev/netif/acx/Makefile,v 1.1 2006/04/01 02:55:36 sephe Exp $ +# $DragonFly: src/sys/dev/netif/acx/Makefile,v 1.2 2006/09/01 15:13:15 sephe Exp $ KMOD = if_acx SRCS = if_acx.c acxcmd.c acx100.c acx111.c SRCS += device_if.h bus_if.h pci_if.h +KMODDEPS= wlan wlan_ratectl_onoe wlan_ratectl_amrr + .include diff --git a/sys/dev/netif/acx/acx100.c b/sys/dev/netif/acx/acx100.c index fcfd8d2179..ed8cb2667c 100644 --- a/sys/dev/netif/acx/acx100.c +++ b/sys/dev/netif/acx/acx100.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/dev/netif/acx/acx100.c,v 1.3 2006/06/17 10:31:59 sephe Exp $ + * $DragonFly: src/sys/dev/netif/acx/acx100.c,v 1.4 2006/09/01 15:13:15 sephe Exp $ */ #include @@ -257,7 +257,10 @@ static int acx100_write_config(struct acx_softc *, struct acx_config *); static int acx100_set_txpower(struct acx_softc *); static void acx100_set_fw_txdesc_rate(struct acx_softc *, - struct acx_txbuf *, int); + struct acx_txbuf *, + struct ieee80211_node *, int); +static void acx100_tx_complete(struct acx_softc *, struct acx_txbuf *, + int, int); static void acx100_set_bss_join_param(struct acx_softc *, void *, int); static int acx100_set_wepkey(struct acx_softc *, struct ieee80211_key *, @@ -269,6 +272,7 @@ void acx100_set_param(device_t dev) { struct acx_softc *sc = device_get_softc(dev); + struct ieee80211com *ic = &sc->sc_ic; sc->chip_mem1_rid = PCIR_BAR(1); sc->chip_mem2_rid = PCIR_BAR(2); @@ -282,17 +286,23 @@ acx100_set_param(device_t dev) sc->chip_fw_txdesc_ctrl = DESC_CTRL_AUTODMA | DESC_CTRL_RECLAIM | DESC_CTRL_FIRST_FRAG; + sc->chip_short_retry_limit = 7; sc->chip_phymode = IEEE80211_MODE_11B; sc->chip_chan_flags = IEEE80211_CHAN_B; - sc->sc_ic.ic_phytype = IEEE80211_T_DS; - sc->sc_ic.ic_sup_rates[IEEE80211_MODE_11B] = acx_rates_11b; + + ic->ic_phytype = IEEE80211_T_DS; + ic->ic_sup_rates[IEEE80211_MODE_11B] = acx_rates_11b; + + ic->ic_ratectl.rc_st_ratectl_cap = IEEE80211_RATECTL_CAP_ONOE; + ic->ic_ratectl.rc_st_ratectl = IEEE80211_RATECTL_ONOE; sc->chip_init = acx100_init; sc->chip_set_wepkey = acx100_set_wepkey; sc->chip_read_config = acx100_read_config; sc->chip_write_config = acx100_write_config; sc->chip_set_fw_txdesc_rate = acx100_set_fw_txdesc_rate; + sc->chip_tx_complete = acx100_tx_complete; sc->chip_set_bss_join_param = acx100_set_bss_join_param; sc->chip_proc_wep_rxbuf = acx100_proc_wep_rxbuf; } @@ -681,8 +691,20 @@ acx100_set_txpower(struct acx_softc *sc) static void acx100_set_fw_txdesc_rate(struct acx_softc *sc, struct acx_txbuf *tx_buf, - int rate) + struct ieee80211_node *ni, int data_len) { + int rate; + + tx_buf->tb_rateidx_len = 1; + if (ni == NULL) { + rate = 2; /* 1Mbit/s */ + tx_buf->tb_rateidx[0] = 0; + } else { + ieee80211_ratectl_findrate(ni, data_len, + tx_buf->tb_rateidx, 1); + rate = IEEE80211_RS_RATE(&ni->ni_rates, + tx_buf->tb_rateidx[0]); + } FW_TXDESC_SETFIELD_1(sc, tx_buf, f_tx_rate100, ACX100_RATE(rate)); } @@ -748,3 +770,21 @@ acx100_proc_wep_rxbuf(struct acx_softc *sc, struct mbuf *m, int *len) #undef IEEEWEP_EXLEN #undef IEEEWEP_IVLEN } + +static void +acx100_tx_complete(struct acx_softc *sc, struct acx_txbuf *tx_buf, + int frame_len, int is_fail) +{ + int long_retries, short_retries; + struct ieee80211_ratectl_res rc_res; + + long_retries = FW_TXDESC_GETFIELD_1(sc, tx_buf, f_tx_rts_nretry); + short_retries = FW_TXDESC_GETFIELD_1(sc, tx_buf, f_tx_data_nretry); + + rc_res.rc_res_rateidx = tx_buf->tb_rateidx[0]; + rc_res.rc_res_tries = short_retries + 1; + + ieee80211_ratectl_tx_complete(tx_buf->tb_node, frame_len, + &rc_res, 1, short_retries, long_retries, + is_fail); +} diff --git a/sys/dev/netif/acx/acx111.c b/sys/dev/netif/acx/acx111.c index 146a19c3c6..71a929d149 100644 --- a/sys/dev/netif/acx/acx111.c +++ b/sys/dev/netif/acx/acx111.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/dev/netif/acx/acx111.c,v 1.3 2006/06/17 10:31:59 sephe Exp $ + * $DragonFly: src/sys/dev/netif/acx/acx111.c,v 1.4 2006/09/01 15:13:15 sephe Exp $ */ #include @@ -60,6 +60,7 @@ #define ACX111_CONF_MEM 0x0003 #define ACX111_CONF_MEMINFO 0x0005 +#define ACX111_CONF_RT0_NRETRY 0x0006 #define ACX111_INTR_ENABLE (ACXRV_INTR_TX_FINI | ACXRV_INTR_RX_FINI) /* @@ -101,6 +102,9 @@ #define ACX111_TXPOWER_VAL 2 #endif +#define ACX111_ONOE_RATEIDX_MAX 4 +#define ACX111_AMRR_RATEIDX_MAX IEEE80211_AMRR_RATEIDX_MAX + /* * NOTE: * Following structs' fields are little endian @@ -137,6 +141,33 @@ struct acx111_conf_mem { uint8_t fw_txring_attr; /* see ACX111_TXRING_ATTR_ */ } __packed; +/* + * ACX111 does support limited multi-rate retry, following rules apply to + * at least firmware rev1.2.x.x: + * 1) Rate field in firmware descriptor is a bitmask, which indicates + * set of rates to be used to send the packet. + * 2) "acx111_conf_rt0_nretry" configures the number of retries for + * 1st rate. + * 3) Except for the last rate and 1st rate, rest of the rates in the + * rate set are tried only once. + * 4) Last rate will be tried until "short retry limit" + "long retry limit" + * reaches. + * + * e.g. + * a) 54Mbit/s, 48Mbit/s and 1Mbit/s are in the rate set. + * b) Number of retries for the 1st rate (i.e. 54Mbit/s) is set to 3. + * c) Short retry limit is set to 7 + * + * For the above configuration: + * A) 4 tries will be spent at 54Mbit/s. + * B) 1 try will be spent at 48Mbit/s, if A) fails. + * C) 3 tries will be spent at 1Mbit/s, if A) and B) fail. + */ +struct acx111_conf_rt0_nretry { + struct acx_conf confcom; + uint8_t rt0_nretry; /* number of retry for 1st rate */ +} __packed; + #define ACX111_STA_MAX 32 #define ACX111_RX_MEMBLK_PERCENT 10 /* 50% */ #define ACX111_XFER_PERCENT 15 /* 75% */ @@ -190,6 +221,7 @@ struct acx111_wepkey { #define ACX111_CONF_FUNC(sg, name) _ACX_CONF_FUNC(sg, name, 111) #define ACX_CONF_mem ACX111_CONF_MEM #define ACX_CONF_meminfo ACX111_CONF_MEMINFO +#define ACX_CONF_rt0_nretry ACX111_CONF_RT0_NRETRY #define ACX_CONF_txpower ACX_CONF_TXPOWER #define ACX_CONF_option ACX_CONF_OPTION ACX111_CONF_FUNC(set, mem); @@ -197,6 +229,7 @@ ACX111_CONF_FUNC(get, meminfo); ACX111_CONF_FUNC(set, txpower); ACX111_CONF_FUNC(get, option); ACX111_CONF_FUNC(set, option); +ACX111_CONF_FUNC(set, rt0_nretry); static const uint16_t acx111_reg[ACXREG_MAX] = { ACXREG(SOFT_RESET, 0x0000), @@ -254,20 +287,44 @@ static uint16_t acx111_rate_map[109] = { ACX111_RATE(108) }; +static const int +acx111_onoe_tries[IEEE80211_RATEIDX_MAX] = { 4, 1, 1, 3, 0 }; + +static const int +acx111_amrr_tries[IEEE80211_RATEIDX_MAX] = { 2, 1, 1, 3, 0 }; + static int acx111_init(struct acx_softc *); static int acx111_init_memory(struct acx_softc *); static void acx111_init_fw_txring(struct acx_softc *, uint32_t); static int acx111_write_config(struct acx_softc *, struct acx_config *); -static void acx111_set_fw_txdesc_rate(struct acx_softc *, - struct acx_txbuf *, int); static void acx111_set_bss_join_param(struct acx_softc *, void *, int); +static void acx111_ratectl_change(struct ieee80211com *, u_int, u_int); + +static void _acx111_set_fw_txdesc_rate(struct acx_softc *, + struct acx_txbuf *, + struct ieee80211_node *, int, int); +static void acx111_set_fw_txdesc_rate_onoe(struct acx_softc *, + struct acx_txbuf *, + struct ieee80211_node *, int); +static void acx111_set_fw_txdesc_rate_amrr(struct acx_softc *, + struct acx_txbuf *, + struct ieee80211_node *, int); + +static void _acx111_tx_complete(struct acx_softc *, struct acx_txbuf *, + int, int, const int[]); +static void acx111_tx_complete_onoe(struct acx_softc *, struct acx_txbuf *, + int, int); +static void acx111_tx_complete_amrr(struct acx_softc *, struct acx_txbuf *, + int, int); + void acx111_set_param(device_t dev) { struct acx_softc *sc = device_get_softc(dev); + struct ieee80211com *ic = &sc->sc_ic; sc->chip_mem1_rid = PCIR_BAR(0); sc->chip_mem2_rid = PCIR_BAR(1); @@ -282,14 +339,19 @@ acx111_set_param(device_t dev) IEEE80211_CHAN_OFDM | IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; - sc->sc_ic.ic_caps = IEEE80211_C_WPA; - sc->sc_ic.ic_phytype = IEEE80211_T_OFDM; - sc->sc_ic.ic_sup_rates[IEEE80211_MODE_11B] = acx_rates_11b; - sc->sc_ic.ic_sup_rates[IEEE80211_MODE_11G] = acx_rates_11g; + + ic->ic_caps = IEEE80211_C_WPA /* | IEEE80211_C_SHSLOT */; + ic->ic_phytype = IEEE80211_T_OFDM; + ic->ic_sup_rates[IEEE80211_MODE_11B] = acx_rates_11b; + ic->ic_sup_rates[IEEE80211_MODE_11G] = acx_rates_11g; + + ic->ic_ratectl.rc_st_ratectl_cap = IEEE80211_RATECTL_CAP_ONOE | + IEEE80211_RATECTL_CAP_AMRR; + ic->ic_ratectl.rc_st_ratectl = IEEE80211_RATECTL_AMRR; + ic->ic_ratectl.rc_st_change = acx111_ratectl_change; sc->chip_init = acx111_init; sc->chip_write_config = acx111_write_config; - sc->chip_set_fw_txdesc_rate = acx111_set_fw_txdesc_rate; sc->chip_set_bss_join_param = acx111_set_bss_join_param; } @@ -397,6 +459,7 @@ acx111_write_config(struct acx_softc *sc, struct acx_config *conf) { struct acx111_conf_txpower tx_power; struct acx111_conf_option opt; + struct acx111_conf_rt0_nretry rt0_nretry; uint32_t dataflow; /* Set TX power */ @@ -424,21 +487,74 @@ acx111_write_config(struct acx_softc *sc, struct acx_config *conf) if_printf(&sc->sc_ic.ic_if, "%s can't set option\n", __func__); return ENXIO; } + + /* + * Set number of retries for 0th rate + */ + rt0_nretry.rt0_nretry = sc->chip_rate_fallback; + if (acx111_set_rt0_nretry_conf(sc, &rt0_nretry) != 0) { + if_printf(&sc->sc_ic.ic_if, "%s can't set rate0 nretry\n", + __func__); + return ENXIO; + } return 0; } static void -acx111_set_fw_txdesc_rate(struct acx_softc *sc, struct acx_txbuf *tx_buf, - int rate0) +_acx111_set_fw_txdesc_rate(struct acx_softc *sc, struct acx_txbuf *tx_buf, + struct ieee80211_node *ni, int data_len, + int rateidx_max) { uint16_t rate; - rate = acx111_rate_map[rate0]; - KASSERT(rate != 0, ("no rate map for %d\n", rate0)); - + KKASSERT(rateidx_max <= IEEE80211_RATEIDX_MAX); + + if (ni == NULL) { + rate = ACX111_RATE_2; /* 1Mbit/s */ + tx_buf->tb_rateidx_len = 1; + tx_buf->tb_rateidx[0] = 0; + } else { + struct ieee80211_rateset *rs = &ni->ni_rates; + int *rateidx = tx_buf->tb_rateidx; + int i, n; + + n = ieee80211_ratectl_findrate(ni, data_len, rateidx, + rateidx_max); + + rate = 0; + for (i = 0; i < n; ++i) { + rate |= acx111_rate_map[ + IEEE80211_RS_RATE(rs, rateidx[i])]; + } + if (rate == 0) { + if_printf(&sc->sc_ic.ic_if, + "WARNING no rate, set to 1Mbit/s\n"); + rate = ACX111_RATE_2; + tx_buf->tb_rateidx_len = 1; + tx_buf->tb_rateidx[0] = 0; + } else { + tx_buf->tb_rateidx_len = n; + } + } FW_TXDESC_SETFIELD_2(sc, tx_buf, u.r2.rate111, rate); } +static void +acx111_set_fw_txdesc_rate_onoe(struct acx_softc *sc, struct acx_txbuf *tx_buf, + struct ieee80211_node *ni, int data_len) +{ + _acx111_set_fw_txdesc_rate(sc, tx_buf, ni, data_len, + ACX111_ONOE_RATEIDX_MAX); +} + +static void +acx111_set_fw_txdesc_rate_amrr(struct acx_softc *sc, struct acx_txbuf *tx_buf, + struct ieee80211_node *ni, int data_len) +{ + _acx111_set_fw_txdesc_rate(sc, tx_buf, ni, data_len, + ACX111_AMRR_RATEIDX_MAX); +} + static void acx111_set_bss_join_param(struct acx_softc *sc, void *param, int dtim_intvl) { @@ -447,3 +563,126 @@ acx111_set_bss_join_param(struct acx_softc *sc, void *param, int dtim_intvl) bj->basic_rates = htole16(ACX111_RATE_ALL); bj->dtim_intvl = dtim_intvl; } + +static void +acx111_ratectl_change(struct ieee80211com *ic, u_int orc, u_int nrc) +{ + struct ifnet *ifp = &ic->ic_if; + struct acx_softc *sc = ifp->if_softc; + const int *tries; + int i; + + switch (nrc) { + case IEEE80211_RATECTL_ONOE: + tries = acx111_onoe_tries; + sc->chip_set_fw_txdesc_rate = acx111_set_fw_txdesc_rate_onoe; + sc->chip_tx_complete = acx111_tx_complete_onoe; + break; + + case IEEE80211_RATECTL_AMRR: + tries = acx111_amrr_tries; + sc->chip_set_fw_txdesc_rate = acx111_set_fw_txdesc_rate_amrr; + sc->chip_tx_complete = acx111_tx_complete_amrr; + break; + + case IEEE80211_RATECTL_NONE: + /* This could only happen during detaching */ + return; + + default: + panic("unknown rate control algo %u\n", nrc); + break; + } + + sc->chip_rate_fallback = tries[0] - 1; + + sc->chip_short_retry_limit = 0; + for (i = 0; i < IEEE80211_RATEIDX_MAX; ++i) + sc->chip_short_retry_limit += tries[i]; + sc->chip_short_retry_limit--; + + if ((ifp->if_flags & (IFF_RUNNING | IFF_UP)) == + (IFF_RUNNING | IFF_UP)) { + struct acx_conf_nretry_short sretry; + struct acx111_conf_rt0_nretry rt0_nretry; + + /* + * Set number of short retries + */ + sretry.nretry = sc->chip_short_retry_limit; + if (acx_set_nretry_short_conf(sc, &sretry) != 0) { + if_printf(ifp, "%s can't set short retry limit\n", + __func__); + } + DPRINTF((ifp, "%s set sretry %d\n", __func__, + sc->chip_short_retry_limit)); + + /* + * Set number of retries for 0th rate + */ + rt0_nretry.rt0_nretry = sc->chip_rate_fallback; + if (acx111_set_rt0_nretry_conf(sc, &rt0_nretry) != 0) { + if_printf(ifp, "%s can't set rate0 nretry\n", + __func__); + } + DPRINTF((ifp, "%s set rate 0 nretry %d\n", __func__, + sc->chip_rate_fallback)); + } +} + +static void +_acx111_tx_complete(struct acx_softc *sc, struct acx_txbuf *tx_buf, + int frame_len, int is_fail, const int tries_arr[]) +{ + struct ieee80211_ratectl_res rc_res[IEEE80211_RATEIDX_MAX]; + int long_retries, short_retries, n, tries, prev_tries; + + KKASSERT(tx_buf->tb_rateidx_len <= IEEE80211_RATEIDX_MAX); + + long_retries = FW_TXDESC_GETFIELD_1(sc, tx_buf, f_tx_rts_nretry); + short_retries = FW_TXDESC_GETFIELD_1(sc, tx_buf, f_tx_data_nretry); + +#if 0 + DPRINTF((&sc->sc_ic.ic_if, "s%d l%d rateidx_len %d\n", + short_retries, long_retries, tx_buf->tb_rateidx_len)); +#endif + + prev_tries = tries = 0; + for (n = 0; n < tx_buf->tb_rateidx_len; ++n) { + rc_res[n].rc_res_tries = tries_arr[n]; + rc_res[n].rc_res_rateidx = tx_buf->tb_rateidx[n]; + if (!is_fail) { + if (short_retries + 1 <= tries) + break; + prev_tries = tries; + tries += tries_arr[n]; + } + } + KKASSERT(n != 0); + + if (!is_fail && short_retries + 1 <= tries) { + rc_res[n - 1].rc_res_tries = short_retries + 1 - prev_tries; +#if 0 + DPRINTF((&sc->sc_ic.ic_if, "n %d, last tries%d\n", + n, rc_res[n - 1].rc_res_tries)); +#endif + } + ieee80211_ratectl_tx_complete(tx_buf->tb_node, frame_len, rc_res, n, + short_retries, long_retries, is_fail); +} + +static void +acx111_tx_complete_onoe(struct acx_softc *sc, struct acx_txbuf *tx_buf, + int frame_len, int is_fail) +{ + _acx111_tx_complete(sc, tx_buf, frame_len, is_fail, + acx111_onoe_tries); +} + +static void +acx111_tx_complete_amrr(struct acx_softc *sc, struct acx_txbuf *tx_buf, + int frame_len, int is_fail) +{ + _acx111_tx_complete(sc, tx_buf, frame_len, is_fail, + acx111_amrr_tries); +} diff --git a/sys/dev/netif/acx/acxcmd.h b/sys/dev/netif/acx/acxcmd.h index 7b29e653bb..f65f3e16b8 100644 --- a/sys/dev/netif/acx/acxcmd.h +++ b/sys/dev/netif/acx/acxcmd.h @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/dev/netif/acx/acxcmd.h,v 1.1 2006/04/01 02:55:36 sephe Exp $ + * $DragonFly: src/sys/dev/netif/acx/acxcmd.h,v 1.2 2006/09/01 15:13:15 sephe Exp $ */ #ifndef _ACXCMD_H @@ -209,7 +209,7 @@ struct acx_tmplt_probe_resp { uint16_t cap; uint8_t var[1]; } __packed u_data; - uint8_t u_mem[0x54]; + uint8_t u_mem[0x100]; } data; } __packed; @@ -228,7 +228,7 @@ struct acx_tmplt_beacon { uint16_t cap; uint8_t var[1]; } __packed u_data; - uint8_t u_mem[0x54]; + uint8_t u_mem[0x100]; } data; } __packed; diff --git a/sys/dev/netif/acx/if_acx.c b/sys/dev/netif/acx/if_acx.c index eaafb23813..5d0b9fbb49 100644 --- a/sys/dev/netif/acx/if_acx.c +++ b/sys/dev/netif/acx/if_acx.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/dev/netif/acx/if_acx.c,v 1.4 2006/08/04 14:04:16 sephe Exp $ + * $DragonFly: src/sys/dev/netif/acx/if_acx.c,v 1.5 2006/09/01 15:13:15 sephe Exp $ */ /* @@ -165,16 +165,16 @@ static int acx_init_tx_ring(struct acx_softc *); static int acx_init_rx_ring(struct acx_softc *); static int acx_newbuf(struct acx_softc *, struct acx_rxbuf *, int); static int acx_encap(struct acx_softc *, struct acx_txbuf *, - struct mbuf *, struct ieee80211_node *, int); + struct mbuf *, struct ieee80211_node *); static int acx_reset(struct acx_softc *); static int acx_set_null_tmplt(struct acx_softc *); static int acx_set_probe_req_tmplt(struct acx_softc *, const char *, int); -static int acx_set_probe_resp_tmplt(struct acx_softc *, const char *, int, - int); -static int acx_set_beacon_tmplt(struct acx_softc *, const char *, int, - int); +static int acx_set_probe_resp_tmplt(struct acx_softc *, + struct ieee80211_node *); +static int acx_set_beacon_tmplt(struct acx_softc *, + struct ieee80211_node *); static int acx_read_eeprom(struct acx_softc *, uint32_t, uint8_t *); static int acx_read_phyreg(struct acx_softc *, uint32_t, uint8_t *); @@ -188,17 +188,8 @@ static int acx_load_radio_firmware(struct acx_softc *, const uint8_t *, static int acx_load_base_firmware(struct acx_softc *, const uint8_t *, uint32_t); -static struct ieee80211_node *acx_node_alloc(struct ieee80211_node_table *); -static void acx_node_init(struct acx_softc *, struct acx_node *); -static void acx_node_update(struct acx_softc *, struct acx_node *, - uint8_t, uint8_t); static int acx_newstate(struct ieee80211com *, enum ieee80211_state, int); -static int acx_sysctl_txrate_upd_intvl_min(SYSCTL_HANDLER_ARGS); -static int acx_sysctl_txrate_upd_intvl_max(SYSCTL_HANDLER_ARGS); -static int acx_sysctl_txrate_sample_thresh(SYSCTL_HANDLER_ARGS); -static int acx_sysctl_long_retry_limit(SYSCTL_HANDLER_ARGS); -static int acx_sysctl_short_retry_limit(SYSCTL_HANDLER_ARGS); static int acx_sysctl_msdu_lifetime(SYSCTL_HANDLER_ARGS); const struct ieee80211_rateset acx_rates_11b = @@ -412,11 +403,13 @@ acx_attach(device_t dev) ic->ic_opmode = IEEE80211_M_STA; ic->ic_state = IEEE80211_S_INIT; + ic->ic_bintval = acx_beacon_intvl; /* * NOTE: Don't overwrite ic_caps set by chip specific code */ ic->ic_caps |= IEEE80211_C_WEP | /* WEP */ + IEEE80211_C_HOSTAP | /* Host AP modes */ IEEE80211_C_IBSS | /* IBSS modes */ IEEE80211_C_SHPREAMBLE; /* Short preamble */ @@ -428,20 +421,13 @@ acx_attach(device_t dev) ieee80211_ifattach(ic); - /* Override node alloc */ - ic->ic_node_alloc = acx_node_alloc; - /* Override newstate */ sc->sc_newstate = ic->ic_newstate; ic->ic_newstate = acx_newstate; ieee80211_media_init(ic, 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 */ sc->sc_long_retry_limit = 4; - sc->sc_short_retry_limit = 7; sc->sc_msdu_lifetime = 4096; sysctl_ctx_init(&sc->sc_sysctl_ctx); @@ -456,39 +442,6 @@ acx_attach(device_t dev) goto fail1; } - SYSCTL_ADD_PROC(&sc->sc_sysctl_ctx, - SYSCTL_CHILDREN(sc->sc_sysctl_tree), - OID_AUTO, "txrate_upd_intvl_min", - CTLTYPE_INT | CTLFLAG_RW, - sc, 0, acx_sysctl_txrate_upd_intvl_min, "I", - "min seconds to wait before raising TX rate"); - SYSCTL_ADD_PROC(&sc->sc_sysctl_ctx, - SYSCTL_CHILDREN(sc->sc_sysctl_tree), - OID_AUTO, "txrate_upd_intvl_max", - CTLTYPE_INT | CTLFLAG_RW, - sc, 0, acx_sysctl_txrate_upd_intvl_max, "I", - "max seconds to wait before raising TX rate"); - SYSCTL_ADD_PROC(&sc->sc_sysctl_ctx, - SYSCTL_CHILDREN(sc->sc_sysctl_tree), - OID_AUTO, "txrate_sample_threshold", - CTLTYPE_INT | CTLFLAG_RW, - sc, 0, acx_sysctl_txrate_sample_thresh, "I", - "number of packets to be sampled " - "before raising TX rate"); - - SYSCTL_ADD_PROC(&sc->sc_sysctl_ctx, - SYSCTL_CHILDREN(sc->sc_sysctl_tree), - OID_AUTO, "long_retry_limit", - CTLTYPE_INT | CTLFLAG_RW, - sc, 0, acx_sysctl_long_retry_limit, "I", - "max number of retries for RTS packets"); - SYSCTL_ADD_PROC(&sc->sc_sysctl_ctx, - SYSCTL_CHILDREN(sc->sc_sysctl_tree), - OID_AUTO, "short_retry_limit", - CTLTYPE_INT | CTLFLAG_RW, - sc, 0, acx_sysctl_short_retry_limit, "I", - "max number of retries for non-RTS packets"); - SYSCTL_ADD_PROC(&sc->sc_sysctl_ctx, SYSCTL_CHILDREN(sc->sc_sysctl_tree), OID_AUTO, "msdu_lifetime", @@ -786,7 +739,6 @@ acx_stop(struct acx_softc *sc) /* Free TX mbuf */ for (i = 0; i < ACX_TX_DESC_CNT; ++i) { struct acx_txbuf *buf; - struct ieee80211_node *ni; buf = &bd->tx_buf[i]; @@ -797,9 +749,8 @@ acx_stop(struct acx_softc *sc) buf->tb_mbuf = NULL; } - ni = (struct ieee80211_node *)buf->tb_node; - if (ni != NULL) - ieee80211_free_node(ni); + if (buf->tb_node != NULL) + ieee80211_free_node(buf->tb_node); buf->tb_node = NULL; } @@ -968,7 +919,8 @@ acx_write_config(struct acx_softc *sc, struct acx_config *conf) int error; /* Set number of long/short retry */ - sretry.nretry = sc->sc_short_retry_limit; + KKASSERT(sc->chip_short_retry_limit > 0); + sretry.nretry = sc->chip_short_retry_limit; if (acx_set_nretry_short_conf(sc, &sretry) != 0) { if_printf(&sc->sc_ic.ic_if, "can't set short retry limit\n"); return ENXIO; @@ -1130,7 +1082,7 @@ acx_start(struct ifnet *ifp) struct ieee80211_frame *f; struct ieee80211_node *ni = NULL; struct mbuf *m; - int rate; + int mgmt_pkt = 0; if (!IF_QEMPTY(&ic->ic_mgtq)) { IF_DEQUEUE(&ic->ic_mgtq, m); @@ -1138,18 +1090,9 @@ acx_start(struct ifnet *ifp) 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. - */ - if (ni != NULL) - ieee80211_free_node(ni); -#endif - rate = 4; /* XXX 2Mb/s for mgmt packet */ + mgmt_pkt = 1; } else if (!ifq_is_empty(&ifp->if_snd)) { struct ether_header *eh; - struct acx_node *node; if (ic->ic_state != IEEE80211_S_RUN) { if_printf(ifp, "data packet dropped due to " @@ -1187,25 +1130,6 @@ acx_start(struct ifnet *ifp) continue; } - 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]; - BPF_MTAP(ifp, m); } else { break; @@ -1225,7 +1149,16 @@ acx_start(struct ifnet *ifp) if (ic->ic_rawbpf != NULL) bpf_mtap(ic->ic_rawbpf, m); - if (acx_encap(sc, buf, m, ni, rate) != 0) { + /* + * Since mgmt data are transmitted at fixed rate + * they will not be used to do rate control. + */ + if (mgmt_pkt && ni != NULL) { + ieee80211_free_node(ni); + ni = NULL; + } + + if (acx_encap(sc, buf, m, ni) != 0) { /* * NOTE: `m' will be freed in acx_encap() * if we reach here. @@ -1327,6 +1260,7 @@ acx_txeof(struct acx_softc *sc) for (buf = &bd->tx_buf[idx]; buf->tb_mbuf != NULL; buf = &bd->tx_buf[idx]) { uint8_t ctrl, error; + int frame_len; ctrl = FW_TXDESC_GETFIELD_1(sc, buf, f_tx_ctrl); if ((ctrl & (DESC_CTRL_HOSTOWN | DESC_CTRL_ACXDONE)) != @@ -1334,6 +1268,7 @@ acx_txeof(struct acx_softc *sc) break; bus_dmamap_unload(bd->mbuf_dma_tag, buf->tb_mbuf_dmamap); + frame_len = buf->tb_mbuf->m_pkthdr.len; m_freem(buf->tb_mbuf); buf->tb_mbuf = NULL; @@ -1346,14 +1281,8 @@ acx_txeof(struct acx_softc *sc) } if (buf->tb_node != NULL) { - struct ieee80211com *ic; - struct ieee80211_node *ni; - - ic = &sc->sc_ic; - ni = (struct ieee80211_node *)buf->tb_node; - - acx_node_update(sc, buf->tb_node, buf->tb_rate, error); - ieee80211_free_node(ni); + sc->chip_tx_complete(sc, buf, frame_len, error); + ieee80211_free_node(buf->tb_node); buf->tb_node = NULL; } @@ -1859,177 +1788,16 @@ acx_load_firmware(struct acx_softc *sc, uint32_t offset, const uint8_t *data, return 0; } -static struct ieee80211_node * -acx_node_alloc(struct ieee80211_node_table *nt __unused) -{ - struct acx_node *node; - - node = malloc(sizeof(struct acx_node), M_80211_NODE, M_NOWAIT | M_ZERO); - node->nd_txrate = -1; - return (struct ieee80211_node *)node; -} - -static 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; - } - } - } - KASSERT(node->nd_node.ni_txrate >= 0, ("no compat rates")); - DPRINTF((&ic->ic_if, "node rate %d\n", - IEEERATE(nd_rset->rs_rates[node->nd_node.ni_txrate]))); -#undef IEEERATE - - cp_rset->rs_nrates = c; - - node->nd_txrate_upd_intvl = sc->sc_txrate_upd_intvl_min; - node->nd_txrate_upd_time = time_second; - node->nd_txrate_sample = 0; -} - -static 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 toubles, - * 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((&sc->sc_ic.ic_if, "rate down %6D %d -> %d\n", - 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((&sc->sc_ic.ic_if, "rate up %6D %d -> %d\n", - 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 -} - static int acx_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) { struct acx_softc *sc = ic->ic_if.if_softc; - int error = 0; + int error = 0, mode = 0; ASSERT_SERIALIZED(ic->ic_if.if_serializer); + ieee80211_ratectl_newstate(ic, nstate); + switch (nstate) { case IEEE80211_S_SCAN: if (ic->ic_state != IEEE80211_S_INIT) { @@ -2076,7 +1844,8 @@ acx_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) } break; case IEEE80211_S_RUN: - if (ic->ic_opmode == IEEE80211_M_IBSS) { + if (ic->ic_opmode == IEEE80211_M_IBSS || + ic->ic_opmode == IEEE80211_M_HOSTAP) { struct ieee80211_node *ni; uint8_t chan; @@ -2099,23 +1868,25 @@ acx_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) goto back; } - if (acx_set_beacon_tmplt(sc, ni->ni_essid, - ni->ni_esslen, chan) != 0) { + if (acx_set_beacon_tmplt(sc, ni) != 0) { if_printf(&ic->ic_if, "set bescon template failed\n"); goto back; } - if (acx_set_probe_resp_tmplt(sc, ni->ni_essid, - ni->ni_esslen, - chan) != 0) { + if (acx_set_probe_resp_tmplt(sc, ni) != 0) { if_printf(&ic->ic_if, "set probe response " "template failed\n"); goto back; } - if (acx_join_bss(sc, ACX_MODE_ADHOC, ni) != 0) { - if_printf(&ic->ic_if, "join IBSS failed\n"); + if (ic->ic_opmode == IEEE80211_M_IBSS) + mode = ACX_MODE_ADHOC; + else + mode = ACX_MODE_AP; + + if (acx_join_bss(sc, mode, ni) != 0) { + if_printf(&ic->ic_if, "acx_join_ibss failed\n"); goto back; } @@ -2470,11 +2241,10 @@ acx_newbuf(struct acx_softc *sc, struct acx_rxbuf *rb, int wait) static int acx_encap(struct acx_softc *sc, struct acx_txbuf *txbuf, struct mbuf *m, - struct ieee80211_node *ni, int rate) + struct ieee80211_node *ni) { struct acx_buf_data *bd = &sc->sc_buf_data; struct acx_ring_data *rd = &sc->sc_ring_data; - struct acx_node *node = (struct acx_node *)ni; uint32_t paddr; uint8_t ctrl; int error; @@ -2529,8 +2299,7 @@ acx_encap(struct acx_softc *sc, struct acx_txbuf *txbuf, struct mbuf *m, BUS_DMASYNC_PREWRITE); txbuf->tb_mbuf = m; - txbuf->tb_node = node; - txbuf->tb_rate = rate; + txbuf->tb_node = ni; /* * TX buffers are accessed in following way: @@ -2575,7 +2344,7 @@ acx_encap(struct acx_softc *sc, struct acx_txbuf *txbuf, struct mbuf *m, FW_TXDESC_SETFIELD_1(sc, txbuf, f_tx_data_nretry, 0); FW_TXDESC_SETFIELD_1(sc, txbuf, f_tx_rts_nretry, 0); FW_TXDESC_SETFIELD_1(sc, txbuf, f_tx_rts_ok, 0); - sc->chip_set_fw_txdesc_rate(sc, txbuf, rate); + sc->chip_set_fw_txdesc_rate(sc, txbuf, ni, m->m_pkthdr.len); txbuf->tb_desc1->h_ctrl = 0; txbuf->tb_desc2->h_ctrl = 0; @@ -2637,233 +2406,49 @@ acx_set_probe_req_tmplt(struct acx_softc *sc, const char *ssid, int ssid_len) } static int -acx_set_probe_resp_tmplt(struct acx_softc *sc, const char *ssid, int ssid_len, - int chan) +acx_set_probe_resp_tmplt(struct acx_softc *sc, struct ieee80211_node *ni) { + struct ieee80211com *ic = &sc->sc_ic; struct acx_tmplt_probe_resp resp; - struct ieee80211_frame *f; - struct ieee80211com *ic; - uint8_t *v; - int vlen; - - ic = &sc->sc_ic; + struct ieee80211_beacon_offsets bo; + struct mbuf *m; + int len; bzero(&resp, sizeof(resp)); - f = &resp.data.u_data.f; - f->i_fc[0] = IEEE80211_FC0_SUBTYPE_PROBE_RESP | IEEE80211_FC0_TYPE_MGT; - IEEE80211_ADDR_COPY(f->i_addr1, etherbroadcastaddr); - IEEE80211_ADDR_COPY(f->i_addr2, IF_LLADDR(&ic->ic_if)); - IEEE80211_ADDR_COPY(f->i_addr3, IF_LLADDR(&ic->ic_if)); - - resp.data.u_data.beacon_intvl = htole16(acx_beacon_intvl); - resp.data.u_data.cap = htole16(IEEE80211_CAPINFO_IBSS); - - v = resp.data.u_data.var; - v = ieee80211_add_ssid(v, ssid, ssid_len); - v = ieee80211_add_rates(v, &ic->ic_sup_rates[sc->chip_phymode]); - - *v++ = IEEE80211_ELEMID_DSPARMS; - *v++ = 1; - *v++ = chan; - - /* This should after IBSS or TIM, but acx always keeps them last */ - v = ieee80211_add_xrates(v, &ic->ic_sup_rates[sc->chip_phymode]); - - if (ic->ic_opmode == IEEE80211_M_IBSS) { - *v++ = IEEE80211_ELEMID_IBSSPARMS; - *v++ = 2; - } + bzero(&bo, sizeof(bo)); + m = ieee80211_beacon_alloc(ic, ni, &bo); + DPRINTF((&ic->ic_if, "%s alloc beacon size %d\n", __func__, + m->m_pkthdr.len)); - vlen = v - resp.data.u_data.var; + m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)&resp.data); + len = m->m_pkthdr.len + sizeof(resp.size); + m_freem(m); - return _acx_set_probe_resp_tmplt(sc, &resp, - ACX_TMPLT_PROBE_RESP_SIZ(vlen)); + return _acx_set_probe_resp_tmplt(sc, &resp, len); } -/* XXX C&P of acx_set_probe_resp_tmplt() */ static int -acx_set_beacon_tmplt(struct acx_softc *sc, const char *ssid, int ssid_len, - int chan) +acx_set_beacon_tmplt(struct acx_softc *sc, struct ieee80211_node *ni) { + struct ieee80211com *ic = &sc->sc_ic; struct acx_tmplt_beacon beacon; - struct ieee80211_frame *f; - struct ieee80211com *ic; - uint8_t *v; - int vlen; - - ic = &sc->sc_ic; + struct ieee80211_beacon_offsets bo; + struct mbuf *m; + int len; bzero(&beacon, sizeof(beacon)); - f = &beacon.data.u_data.f; - f->i_fc[0] = IEEE80211_FC0_SUBTYPE_BEACON | IEEE80211_FC0_TYPE_MGT; - IEEE80211_ADDR_COPY(f->i_addr1, etherbroadcastaddr); - IEEE80211_ADDR_COPY(f->i_addr2, IF_LLADDR(&ic->ic_if)); - IEEE80211_ADDR_COPY(f->i_addr3, IF_LLADDR(&ic->ic_if)); - - beacon.data.u_data.beacon_intvl = htole16(acx_beacon_intvl); - beacon.data.u_data.cap = htole16(IEEE80211_CAPINFO_IBSS); + bzero(&bo, sizeof(bo)); + m = ieee80211_beacon_alloc(ic, ni, &bo); + DPRINTF((&ic->ic_if, "%s alloc beacon size %d\n", __func__, + m->m_pkthdr.len)); - v = beacon.data.u_data.var; - v = ieee80211_add_ssid(v, ssid, ssid_len); - v = ieee80211_add_rates(v, &ic->ic_sup_rates[sc->chip_phymode]); - - *v++ = IEEE80211_ELEMID_DSPARMS; - *v++ = 1; - *v++ = chan; - - /* This should after IBSS or TIM, but acx always keeps them last */ - v = ieee80211_add_xrates(v, &ic->ic_sup_rates[sc->chip_phymode]); - - if (ic->ic_opmode == IEEE80211_M_IBSS) { - *v++ = IEEE80211_ELEMID_IBSSPARMS; - *v++ = 2; - } - - vlen = v - beacon.data.u_data.var; - - return _acx_set_beacon_tmplt(sc, &beacon, ACX_TMPLT_BEACON_SIZ(vlen)); -} - -static int -acx_sysctl_txrate_upd_intvl_min(SYSCTL_HANDLER_ARGS) -{ - struct acx_softc *sc = arg1; - struct ifnet *ifp = &sc->sc_ic.ic_if; - int error = 0, v; - - lwkt_serialize_enter(ifp->if_serializer); + m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)&beacon.data); + len = m->m_pkthdr.len + sizeof(beacon.size); + m_freem(m); - v = sc->sc_txrate_upd_intvl_min; - error = sysctl_handle_int(oidp, &v, 0, req); - if (error || req->newptr == NULL) - goto back; - if (v <= 0 || v > sc->sc_txrate_upd_intvl_max) { - error = EINVAL; - goto back; - } - - sc->sc_txrate_upd_intvl_min = v; -back: - lwkt_serialize_exit(ifp->if_serializer); - return error; -} - -static int -acx_sysctl_txrate_upd_intvl_max(SYSCTL_HANDLER_ARGS) -{ - struct acx_softc *sc = arg1; - struct ifnet *ifp = &sc->sc_ic.ic_if; - int error = 0, v; - - lwkt_serialize_enter(ifp->if_serializer); - - v = sc->sc_txrate_upd_intvl_max; - error = sysctl_handle_int(oidp, &v, 0, req); - if (error || req->newptr == NULL) - goto back; - if (v <= 0 || v < sc->sc_txrate_upd_intvl_min) { - error = EINVAL; - goto back; - } - - sc->sc_txrate_upd_intvl_max = v; -back: - lwkt_serialize_exit(ifp->if_serializer); - return error; -} - -static int -acx_sysctl_txrate_sample_thresh(SYSCTL_HANDLER_ARGS) -{ - struct acx_softc *sc = arg1; - struct ifnet *ifp = &sc->sc_ic.ic_if; - int error = 0, v; - - lwkt_serialize_enter(ifp->if_serializer); - - v = sc->sc_txrate_sample_thresh; - error = sysctl_handle_int(oidp, &v, 0, req); - if (error || req->newptr == NULL) - goto back; - if (v <= 0) { - error = EINVAL; - goto back; - } - - sc->sc_txrate_sample_thresh = v; -back: - lwkt_serialize_exit(ifp->if_serializer); - return error; -} - -static int -acx_sysctl_long_retry_limit(SYSCTL_HANDLER_ARGS) -{ - struct acx_softc *sc = arg1; - struct ifnet *ifp = &sc->sc_ic.ic_if; - int error = 0, v; - - lwkt_serialize_enter(ifp->if_serializer); - - v = sc->sc_long_retry_limit; - error = sysctl_handle_int(oidp, &v, 0, req); - if (error || req->newptr == NULL) - goto back; - if (v <= 0) { - error = EINVAL; - goto back; - } - - if (sc->sc_flags & ACX_FLAG_FW_LOADED) { - struct acx_conf_nretry_long lretry; - - lretry.nretry = v; - if (acx_set_nretry_long_conf(sc, &lretry) != 0) { - if_printf(ifp, "can't set long retry limit\n"); - error = ENXIO; - goto back; - } - } - sc->sc_long_retry_limit = v; -back: - lwkt_serialize_exit(ifp->if_serializer); - return error; -} - -static int -acx_sysctl_short_retry_limit(SYSCTL_HANDLER_ARGS) -{ - struct acx_softc *sc = arg1; - struct ifnet *ifp = &sc->sc_ic.ic_if; - int error = 0, v; - - lwkt_serialize_enter(ifp->if_serializer); - - v = sc->sc_short_retry_limit; - error = sysctl_handle_int(oidp, &v, 0, req); - if (error || req->newptr == NULL) - goto back; - if (v <= 0) { - error = EINVAL; - goto back; - } - - if (sc->sc_flags & ACX_FLAG_FW_LOADED) { - struct acx_conf_nretry_short sretry; - - sretry.nretry = v; - if (acx_set_nretry_short_conf(sc, &sretry) != 0) { - if_printf(ifp, "can't set short retry limit\n"); - error = ENXIO; - goto back; - } - } - sc->sc_short_retry_limit = v; -back: - lwkt_serialize_exit(ifp->if_serializer); - return error; + return _acx_set_beacon_tmplt(sc, &beacon, len); } static int diff --git a/sys/dev/netif/acx/if_acxvar.h b/sys/dev/netif/acx/if_acxvar.h index 856a9654a7..8dc4565471 100644 --- a/sys/dev/netif/acx/if_acxvar.h +++ b/sys/dev/netif/acx/if_acxvar.h @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/dev/netif/acx/if_acxvar.h,v 1.4 2006/08/04 14:04:16 sephe Exp $ + * $DragonFly: src/sys/dev/netif/acx/if_acxvar.h,v 1.5 2006/09/01 15:13:15 sephe Exp $ */ #ifndef _IF_ACXVAR_H @@ -78,6 +78,8 @@ #define DESC_READ_1(sc, off) \ bus_space_read_1((sc)->sc_mem2_bt, (sc)->sc_mem2_bh, (off)) +#define DESC_READ_2(sc, off) \ + bus_space_read_2((sc)->sc_mem2_bt, (sc)->sc_mem2_bh, (off)) #define DESC_READ_4(sc, off) \ bus_space_read_4((sc)->sc_mem2_bt, (sc)->sc_mem2_bh, (off)) @@ -108,6 +110,8 @@ #define FW_TXDESC_GETFIELD_1(sc, mb, field) \ FW_TXDESC_GETFIELD(sc, mb, field, 1) +#define FW_TXDESC_GETFIELD_2(sc, mb, field) \ + le16toh(FW_TXDESC_GETFIELD(sc, mb, field, 2)) #define FW_TXDESC_GETFIELD_4(sc, mb, field) \ le32toh(FW_TXDESC_GETFIELD(sc, mb, field, 4)) @@ -254,8 +258,10 @@ struct acx_txbuf { /* * Used by tx rate updating */ - struct acx_node *tb_node; /* remote node */ - int tb_rate; /* current tx rate */ + struct ieee80211_node *tb_node; /* remote node */ + + int tb_rateidx_len; + int tb_rateidx[IEEE80211_RATEIDX_MAX]; }; struct acx_rxbuf { @@ -278,17 +284,6 @@ struct acx_buf_data { int tx_used_count; }; -struct acx_node { - struct ieee80211_node nd_node; /* MUST be first */ - - struct ieee80211_rateset nd_rates; /* shared rates */ - int nd_txrate; /* index into nd_rates[] */ - - int nd_txrate_upd_intvl; /* tx rate upd interval */ - int nd_txrate_upd_time; /* tx rate upd timestamp */ - int nd_txrate_sample; /* num of samples for specific rate */ -}; - struct acx_firmware { uint8_t *base_fw; int base_fw_len; @@ -387,14 +382,13 @@ struct acx_softc { struct sysctl_ctx_list sc_sysctl_ctx; struct sysctl_oid *sc_sysctl_tree; + int sc_long_retry_limit; + int chip_short_retry_limit; + int chip_rate_fallback; + /* * Per interface sysctl variables */ - int sc_txrate_upd_intvl_min; - int sc_txrate_upd_intvl_max; - int sc_txrate_sample_thresh; - int sc_long_retry_limit; - int sc_short_retry_limit; int sc_msdu_lifetime; int (*sc_newstate) @@ -415,7 +409,12 @@ struct acx_softc { (struct acx_softc *, struct acx_config *); void (*chip_set_fw_txdesc_rate) /* non-NULL */ - (struct acx_softc *, struct acx_txbuf *, int); + (struct acx_softc *, struct acx_txbuf *, + struct ieee80211_node *, int); + + void (*chip_tx_complete) /* non-NULL */ + (struct acx_softc *, struct acx_txbuf *, + int, int); void (*chip_set_bss_join_param) /* non-NULL */ (struct acx_softc *, void *, int); -- 2.41.0