wl12xx: AP mode - support FW TX inactivity triggers
[pandora-kernel.git] / drivers / net / wireless / wl12xx / acx.c
index 8a39d1e..2f5207a 100644 (file)
@@ -25,7 +25,6 @@
 
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/crc7.h>
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 
@@ -325,12 +324,19 @@ out:
        return ret;
 }
 
-int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold)
+int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold)
 {
        struct acx_rts_threshold *rts;
        int ret;
 
-       wl1271_debug(DEBUG_ACX, "acx rts threshold");
+       /*
+        * If the RTS threshold is not configured or out of range, use the
+        * default value.
+        */
+       if (rts_threshold > IEEE80211_MAX_RTS_THRESHOLD)
+               rts_threshold = wl->conf.rx.rts_threshold;
+
+       wl1271_debug(DEBUG_ACX, "acx rts threshold: %d", rts_threshold);
 
        rts = kzalloc(sizeof(*rts), GFP_KERNEL);
        if (!rts) {
@@ -338,7 +344,7 @@ int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold)
                goto out;
        }
 
-       rts->threshold = cpu_to_le16(rts_threshold);
+       rts->threshold = cpu_to_le16((u16)rts_threshold);
 
        ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts));
        if (ret < 0) {
@@ -540,13 +546,13 @@ out:
        return ret;
 }
 
-int wl1271_acx_sg_cfg(struct wl1271 *wl)
+int wl1271_acx_sta_sg_cfg(struct wl1271 *wl)
 {
-       struct acx_bt_wlan_coex_param *param;
+       struct acx_sta_bt_wlan_coex_param *param;
        struct conf_sg_settings *c = &wl->conf.sg;
        int i, ret;
 
-       wl1271_debug(DEBUG_ACX, "acx sg cfg");
+       wl1271_debug(DEBUG_ACX, "acx sg sta cfg");
 
        param = kzalloc(sizeof(*param), GFP_KERNEL);
        if (!param) {
@@ -555,8 +561,38 @@ int wl1271_acx_sg_cfg(struct wl1271 *wl)
        }
 
        /* BT-WLAN coext parameters */
-       for (i = 0; i < CONF_SG_PARAMS_MAX; i++)
-               param->params[i] = cpu_to_le32(c->params[i]);
+       for (i = 0; i < CONF_SG_STA_PARAMS_MAX; i++)
+               param->params[i] = cpu_to_le32(c->sta_params[i]);
+       param->param_idx = CONF_SG_PARAMS_ALL;
+
+       ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
+       if (ret < 0) {
+               wl1271_warning("failed to set sg config: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(param);
+       return ret;
+}
+
+int wl1271_acx_ap_sg_cfg(struct wl1271 *wl)
+{
+       struct acx_ap_bt_wlan_coex_param *param;
+       struct conf_sg_settings *c = &wl->conf.sg;
+       int i, ret;
+
+       wl1271_debug(DEBUG_ACX, "acx sg ap cfg");
+
+       param = kzalloc(sizeof(*param), GFP_KERNEL);
+       if (!param) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /* BT-WLAN coext parameters */
+       for (i = 0; i < CONF_SG_AP_PARAMS_MAX; i++)
+               param->params[i] = cpu_to_le32(c->ap_params[i]);
        param->param_idx = CONF_SG_PARAMS_ALL;
 
        ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
@@ -804,7 +840,8 @@ int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c,
        struct acx_ap_rate_policy *acx;
        int ret = 0;
 
-       wl1271_debug(DEBUG_ACX, "acx ap rate policy");
+       wl1271_debug(DEBUG_ACX, "acx ap rate policy %d rates 0x%x",
+                    idx, c->enabled_rates);
 
        acx = kzalloc(sizeof(*acx), GFP_KERNEL);
        if (!acx) {
@@ -898,12 +935,19 @@ out:
        return ret;
 }
 
-int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold)
+int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold)
 {
        struct acx_frag_threshold *acx;
        int ret = 0;
 
-       wl1271_debug(DEBUG_ACX, "acx frag threshold");
+       /*
+        * If the fragmentation is not configured or out of range, use the
+        * default value.
+        */
+       if (frag_threshold > IEEE80211_MAX_FRAG_THRESHOLD)
+               frag_threshold = wl->conf.tx.frag_threshold;
+
+       wl1271_debug(DEBUG_ACX, "acx frag threshold: %d", frag_threshold);
 
        acx = kzalloc(sizeof(*acx), GFP_KERNEL);
 
@@ -912,7 +956,7 @@ int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold)
                goto out;
        }
 
-       acx->frag_threshold = cpu_to_le16(frag_threshold);
+       acx->frag_threshold = cpu_to_le16((u16)frag_threshold);
        ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx));
        if (ret < 0) {
                wl1271_warning("Setting of frag threshold failed: %d", ret);
@@ -954,6 +998,7 @@ out:
 int wl1271_acx_ap_mem_cfg(struct wl1271 *wl)
 {
        struct wl1271_acx_ap_config_memory *mem_conf;
+       struct conf_memory_settings *mem;
        int ret;
 
        wl1271_debug(DEBUG_ACX, "wl1271 mem cfg");
@@ -964,14 +1009,21 @@ int wl1271_acx_ap_mem_cfg(struct wl1271 *wl)
                goto out;
        }
 
+       if (wl->chip.id == CHIP_ID_1283_PG20)
+               /*
+                * FIXME: The 128x AP FW does not yet support dynamic memory.
+                * Use the base memory configuration for 128x for now. This
+                * should be fine tuned in the future.
+                */
+               mem = &wl->conf.mem_wl128x;
+       else
+               mem = &wl->conf.mem_wl127x;
+
        /* memory config */
-       /* FIXME: for now we always use mem_wl127x for AP, because it
-        * doesn't support dynamic memory and we don't have the
-        * optimal values for wl128x without dynamic memory yet */
-       mem_conf->num_stations = wl->conf.mem_wl127x.num_stations;
-       mem_conf->rx_mem_block_num = wl->conf.mem_wl127x.rx_block_num;
-       mem_conf->tx_min_mem_block_num = wl->conf.mem_wl127x.tx_min_block_num;
-       mem_conf->num_ssid_profiles = wl->conf.mem_wl127x.ssid_profiles;
+       mem_conf->num_stations = mem->num_stations;
+       mem_conf->rx_mem_block_num = mem->rx_block_num;
+       mem_conf->tx_min_mem_block_num = mem->tx_min_block_num;
+       mem_conf->num_ssid_profiles = mem->ssid_profiles;
        mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS);
 
        ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
@@ -1015,6 +1067,7 @@ int wl1271_acx_sta_mem_cfg(struct wl1271 *wl)
        mem_conf->tx_free_req = mem->min_req_tx_blocks;
        mem_conf->rx_free_req = mem->min_req_rx_blocks;
        mem_conf->tx_min = mem->tx_min;
+       mem_conf->fwlog_blocks = wl->conf.fwlog.mem_blocks;
 
        ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
                                   sizeof(*mem_conf));
@@ -1524,46 +1577,69 @@ out:
        return ret;
 }
 
-int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl)
+int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable)
 {
-       struct wl1271_acx_ap_max_tx_retry *acx = NULL;
-       int ret;
-
-       wl1271_debug(DEBUG_ACX, "acx ap max tx retry");
+       struct wl1271_acx_ps_rx_streaming *rx_streaming;
+       u32 conf_queues, enable_queues;
+       int i, ret = 0;
 
-       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
-       if (!acx)
-               return -ENOMEM;
+       wl1271_debug(DEBUG_ACX, "acx ps rx streaming");
 
-       acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries);
-
-       ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx));
-       if (ret < 0) {
-               wl1271_warning("acx ap max tx retry failed: %d", ret);
+       rx_streaming = kzalloc(sizeof(*rx_streaming), GFP_KERNEL);
+       if (!rx_streaming) {
+               ret = -ENOMEM;
                goto out;
        }
 
+       conf_queues = wl->conf.rx_streaming.queues;
+       if (enable)
+               enable_queues = conf_queues;
+       else
+               enable_queues = 0;
+
+       for (i = 0; i < 8; i++) {
+               /*
+                * Skip non-changed queues, to avoid redundant acxs.
+                * this check assumes conf.rx_streaming.queues can't
+                * be changed while rx_streaming is enabled.
+                */
+               if (!(conf_queues & BIT(i)))
+                       continue;
+
+               rx_streaming->tid = i;
+               rx_streaming->enable = enable_queues & BIT(i);
+               rx_streaming->period = wl->conf.rx_streaming.interval;
+               rx_streaming->timeout = wl->conf.rx_streaming.interval;
+
+               ret = wl1271_cmd_configure(wl, ACX_PS_RX_STREAMING,
+                                          rx_streaming,
+                                          sizeof(*rx_streaming));
+               if (ret < 0) {
+                       wl1271_warning("acx ps rx streaming failed: %d", ret);
+                       goto out;
+               }
+       }
 out:
-       kfree(acx);
+       kfree(rx_streaming);
        return ret;
 }
 
-int wl1271_acx_sta_max_tx_retry(struct wl1271 *wl)
+int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl)
 {
-       struct wl1271_acx_sta_max_tx_retry *acx = NULL;
+       struct wl1271_acx_ap_max_tx_retry *acx = NULL;
        int ret;
 
-       wl1271_debug(DEBUG_ACX, "acx sta max tx retry");
+       wl1271_debug(DEBUG_ACX, "acx ap max tx retry");
 
        acx = kzalloc(sizeof(*acx), GFP_KERNEL);
        if (!acx)
                return -ENOMEM;
 
-       acx->max_tx_retry = wl->conf.tx.max_tx_retries;
+       acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries);
 
-       ret = wl1271_cmd_configure(wl, ACX_CONS_TX_FAILURE, acx, sizeof(*acx));
+       ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx));
        if (ret < 0) {
-               wl1271_warning("acx sta max tx retry failed: %d", ret);
+               wl1271_warning("acx ap max tx retry failed: %d", ret);
                goto out;
        }
 
@@ -1627,6 +1703,31 @@ out:
        return ret;
 }
 
+int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable)
+{
+       struct acx_ap_beacon_filter *acx = NULL;
+       int ret;
+
+       wl1271_debug(DEBUG_ACX, "acx set ap beacon filter: %d", enable);
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx)
+               return -ENOMEM;
+
+       acx->enable = enable ? 1 : 0;
+
+       ret = wl1271_cmd_configure(wl, ACX_AP_BEACON_FILTER_OPT,
+                                  acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1271_warning("acx set ap beacon filter failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
+
 int wl1271_acx_fm_coex(struct wl1271 *wl)
 {
        struct wl1271_acx_fm_coex *acx;