wl1251: implement acx_ac_cfg to configure hardware queues
authorKalle Valo <kalle.valo@nokia.com>
Mon, 30 Nov 2009 08:18:19 +0000 (10:18 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 21 Dec 2009 23:55:55 +0000 (18:55 -0500)
Needed for WMM.

Signed-off-by: Kalle Valo <kalle.valo@nokia.com>
Reviewed-by: Janne Ylalehto <janne.ylalehto@nokia.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/wl12xx/wl1251_acx.c
drivers/net/wireless/wl12xx/wl1251_acx.h
drivers/net/wireless/wl12xx/wl1251_init.c
drivers/net/wireless/wl12xx/wl1251_init.h
drivers/net/wireless/wl12xx/wl1251_main.c
drivers/net/wireless/wl12xx/wl1251_tx.h

index acfa086dbfc5787d673b6e75ac2883dada80fc63..b409c75499dd347ce45ad951f55a12929e208678 100644 (file)
@@ -976,3 +976,36 @@ out:
        kfree(acx);
        return ret;
 }
+
+int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max,
+                     u8 aifs, u16 txop)
+{
+       struct wl1251_acx_ac_cfg *acx;
+       int ret = 0;
+
+       wl1251_debug(DEBUG_ACX, "acx ac cfg %d cw_ming %d cw_max %d "
+                    "aifs %d txop %d", ac, cw_min, cw_max, aifs, txop);
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       acx->ac = ac;
+       acx->cw_min = cw_min;
+       acx->cw_max = cw_max;
+       acx->aifsn = aifs;
+       acx->txop_limit = txop;
+
+       ret = wl1251_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1251_warning("acx ac cfg failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
index 652371432cd81c109bc8ac48d3066c8eed81101b..56793245b2876b426735fb000ba09a04b0ecc89d 100644 (file)
@@ -1166,6 +1166,36 @@ struct wl1251_acx_wr_tbtt_and_dtim {
        u8  padding;
 } __attribute__ ((packed));
 
+struct wl1251_acx_ac_cfg {
+       struct acx_header header;
+
+       /*
+        * Access Category - The TX queue's access category
+        * (refer to AccessCategory_enum)
+        */
+       u8 ac;
+
+       /*
+        * The contention window minimum size (in slots) for
+        * the access class.
+        */
+       u8 cw_min;
+
+       /*
+        * The contention window maximum size (in slots) for
+        * the access class.
+        */
+       u16 cw_max;
+
+       /* The AIF value (in slots) for the access class. */
+       u8 aifsn;
+
+       u8 reserved;
+
+       /* The TX Op Limit (in microseconds) for the access class. */
+       u16 txop_limit;
+} __attribute__ ((packed));
+
 /*************************************************************************
 
     Host Interrupt Register (WiLink -> Host)
@@ -1322,5 +1352,7 @@ int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime);
 int wl1251_acx_rate_policies(struct wl1251 *wl);
 int wl1251_acx_mem_cfg(struct wl1251 *wl);
 int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim);
+int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max,
+                     u8 aifs, u16 txop);
 
 #endif /* __WL1251_ACX_H__ */
index 5cb573383eeb4f78f937665adcee44014d38571c..5aad56ea71536fa1dbc5875d601f7bd76eaae961 100644 (file)
@@ -294,6 +294,11 @@ static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl)
                        goto out;
        }
 
+       wl1251_acx_ac_cfg(wl, AC_BE, CWMIN_BE, CWMAX_BE, AIFS_DIFS, TXOP_BE);
+       wl1251_acx_ac_cfg(wl, AC_BK, CWMIN_BK, CWMAX_BK, AIFS_DIFS, TXOP_BK);
+       wl1251_acx_ac_cfg(wl, AC_VI, CWMIN_VI, CWMAX_VI, AIFS_DIFS, TXOP_VI);
+       wl1251_acx_ac_cfg(wl, AC_VO, CWMIN_VO, CWMAX_VO, AIFS_DIFS, TXOP_VO);
+
 out:
        kfree(config);
        return ret;
index b3b25ec885ea7489d19c3f6f3cd2d08d047e7217..269cefb3e7d43f20d96e3ca1902b1388fd5049e3 100644 (file)
 
 #include "wl1251.h"
 
+enum {
+       /* best effort/legacy */
+       AC_BE = 0,
+
+       /* background */
+       AC_BK = 1,
+
+       /* video */
+       AC_VI = 2,
+
+       /* voice */
+       AC_VO = 3,
+
+       /* broadcast dummy access category */
+       AC_BCAST = 4,
+
+       NUM_ACCESS_CATEGORIES = 4
+};
+
+/* following are defult values for the IE fields*/
+#define CWMIN_BK  15
+#define CWMIN_BE  15
+#define CWMIN_VI  7
+#define CWMIN_VO  3
+#define CWMAX_BK  1023
+#define CWMAX_BE  63
+#define CWMAX_VI  15
+#define CWMAX_VO  7
+
+/* slot number setting to start transmission at PIFS interval */
+#define AIFS_PIFS 1
+
+/*
+ * slot number setting to start transmission at DIFS interval - normal DCF
+ * access
+ */
+#define AIFS_DIFS 2
+
+#define AIFSN_BK  7
+#define AIFSN_BE  3
+#define AIFSN_VI  AIFS_PIFS
+#define AIFSN_VO  AIFS_PIFS
+#define TXOP_BK   0
+#define TXOP_BE   0
+#define TXOP_VI   3008
+#define TXOP_VO   1504
+
 int wl1251_hw_init_hwenc_config(struct wl1251 *wl);
 int wl1251_hw_init_templates_config(struct wl1251 *wl);
 int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter);
index 24050d56a9de74a8b213fd63335b51ee68aee3ef..c1c7cb5aea2b5c10b7d813b313eb7720acf53e03 100644 (file)
@@ -1285,6 +1285,32 @@ static struct ieee80211_channel wl1251_channels[] = {
        { .hw_value = 13, .center_freq = 2472},
 };
 
+static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
+                            const struct ieee80211_tx_queue_params *params)
+{
+       struct wl1251 *wl = hw->priv;
+       int ret;
+
+       mutex_lock(&wl->mutex);
+
+       wl1251_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
+
+       ret = wl1251_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto out;
+
+       ret = wl1251_acx_ac_cfg(wl, wl1251_tx_get_queue(queue),
+                               params->cw_min, params->cw_max,
+                               params->aifs, params->txop);
+
+       wl1251_ps_elp_sleep(wl);
+
+out:
+       mutex_unlock(&wl->mutex);
+
+       return ret;
+}
+
 /* can't be const, mac80211 writes to this */
 static struct ieee80211_supported_band wl1251_band_2ghz = {
        .channels = wl1251_channels,
@@ -1305,6 +1331,7 @@ static const struct ieee80211_ops wl1251_ops = {
        .hw_scan = wl1251_op_hw_scan,
        .bss_info_changed = wl1251_op_bss_info_changed,
        .set_rts_threshold = wl1251_op_set_rts_threshold,
+       .conf_tx = wl1251_op_conf_tx,
 };
 
 static int wl1251_register_hw(struct wl1251 *wl)
index 7c1c1665c81086f1a44966a55da55d4ddb8897f2..b7bead8b0aeb964fbbbda8f411507573f35c94c2 100644 (file)
@@ -26,6 +26,7 @@
 #define __WL1251_TX_H__
 
 #include <linux/bitops.h>
+#include "wl1251_acx.h"
 
 /*
  *
@@ -209,6 +210,25 @@ struct tx_result {
        u8 done_2;
 } __attribute__ ((packed));
 
+static inline int wl1251_tx_get_queue(int queue)
+{
+       /* FIXME: use best effort until WMM is enabled */
+       return QOS_AC_BE;
+
+       switch (queue) {
+       case 0:
+               return QOS_AC_VO;
+       case 1:
+               return QOS_AC_VI;
+       case 2:
+               return QOS_AC_BE;
+       case 3:
+               return QOS_AC_BK;
+       default:
+               return QOS_AC_BE;
+       }
+}
+
 void wl1251_tx_work(struct work_struct *work);
 void wl1251_tx_complete(struct wl1251 *wl);
 void wl1251_tx_flush(struct wl1251 *wl);