- More reverse engineer: acx111 does support multi-rate retry!
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Fri, 1 Sep 2006 15:13:15 +0000 (15:13 +0000)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Fri, 1 Sep 2006 15:13:15 +0000 (15:13 +0000)
  Collaborated-with: Darron Broad <darron@kewl.org>
- 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
sys/dev/netif/acx/acx100.c
sys/dev/netif/acx/acx111.c
sys/dev/netif/acx/acxcmd.h
sys/dev/netif/acx/if_acx.c
sys/dev/netif/acx/if_acxvar.h

index 4b4455b..28f1f1c 100644 (file)
@@ -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 <bsd.kmod.mk>
index fcfd8d2..ed8cb26 100644 (file)
@@ -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 <sys/param.h>
@@ -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);
+}
index 146a19c..71a929d 100644 (file)
@@ -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 <sys/param.h>
@@ -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)
 /*
 #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);
+}
index 7b29e65..f65f3e1 100644 (file)
@@ -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;
 
index eaafb23..5d0b9fb 100644 (file)
@@ -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
index 856a965..8dc4565 100644 (file)
@@ -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))
 
 
 #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);