wlcore: enable sleep during AP mode operation
authorKobi L <kobi.lev100@gmail.com>
Mon, 29 Dec 2014 06:24:06 +0000 (08:24 +0200)
committerKalle Valo <kvalo@codeaurora.org>
Fri, 9 Jan 2015 13:47:56 +0000 (15:47 +0200)
Enable ELP authorization in AP mode and enable the use
of the wakeup bit in the ELP register.

Introduce AP role sleep configuration which is disabled
by default. When configured, it allows the AP to sleep
when ELP is authorized for it.

Signed-off-by: Kobi Leibovitch <kobi.lev100@gmail.com>
Signed-off-by: Arik Nemtsov <arik@wizery.com>
Signed-off-by: Eliad Peller <eliad@wizery.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/ti/wl12xx/main.c
drivers/net/wireless/ti/wl18xx/acx.c
drivers/net/wireless/ti/wl18xx/acx.h
drivers/net/wireless/ti/wl18xx/conf.h
drivers/net/wireless/ti/wl18xx/main.c
drivers/net/wireless/ti/wlcore/hw_ops.h
drivers/net/wireless/ti/wlcore/init.c
drivers/net/wireless/ti/wlcore/ps.c
drivers/net/wireless/ti/wlcore/wlcore.h

index f3cee5ad70263cb03dd6e72e55b68ac56aeb9318..144d1f8ba473463ce204de1188b8971cff3a841f 100644 (file)
@@ -1731,6 +1731,7 @@ static struct wlcore_ops wl12xx_ops = {
        .lnk_low_prio           = wl12xx_lnk_low_prio,
        .interrupt_notify       = NULL,
        .rx_ba_filter           = NULL,
+       .ap_sleep               = NULL,
 };
 
 static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
index 9d4b9aacd0374c26858cdef617814d43e412f121..67f2a0eec8542190ea6d8c374240492d9b95ed73 100644 (file)
@@ -24,6 +24,7 @@
 #include "../wlcore/acx.h"
 
 #include "acx.h"
+#include "wl18xx.h"
 
 int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
                                  u32 sdio_blk_size, u32 extra_mem_blks,
@@ -250,3 +251,34 @@ out:
        kfree(acx);
        return ret;
 }
+
+int wl18xx_acx_ap_sleep(struct wl1271 *wl)
+{
+       struct wl18xx_priv *priv = wl->priv;
+       struct acx_ap_sleep_cfg *acx;
+       struct conf_ap_sleep_settings *conf = &priv->conf.ap_sleep;
+       int ret;
+
+       wl1271_debug(DEBUG_ACX, "acx config ap sleep");
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       acx->idle_duty_cycle = conf->idle_duty_cycle;
+       acx->connected_duty_cycle = conf->connected_duty_cycle;
+       acx->max_stations_thresh = conf->max_stations_thresh;
+       acx->idle_conn_thresh = conf->idle_conn_thresh;
+
+       ret = wl1271_cmd_configure(wl, ACX_AP_SLEEP_CFG, acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1271_warning("acx config ap-sleep failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
index 1234bdc6d1b9ddada6e304337b88fe372ee3205b..4afccd4b946752b6312bc2301ab13e02c14944da 100644 (file)
@@ -34,8 +34,8 @@ enum {
        ACX_AUTO_RX_STREAMING            = 0x0055,
        ACX_PEER_CAP                     = 0x0056,
        ACX_INTERRUPT_NOTIFY             = 0x0057,
-       ACX_RX_BA_FILTER                 = 0x0058
-
+       ACX_RX_BA_FILTER                 = 0x0058,
+       ACX_AP_SLEEP_CFG                 = 0x0059
 };
 
 /* numbers of bits the length field takes (add 1 for the actual number) */
@@ -347,6 +347,26 @@ struct wl18xx_acx_rx_ba_filter {
        u32 enable;
 };
 
+struct acx_ap_sleep_cfg {
+       struct acx_header header;
+       /* Duty Cycle (20-80% of staying Awake) for IDLE AP
+        * (0: disable)
+        */
+       u8 idle_duty_cycle;
+       /* Duty Cycle (20-80% of staying Awake) for Connected AP
+        * (0: disable)
+        */
+       u8 connected_duty_cycle;
+       /* Maximum stations that are allowed to be connected to AP
+        *  (255: no limit)
+        */
+       u8 max_stations_thresh;
+       /* Timeout till enabling the Sleep Mechanism after data stops
+        * [unit: 100 msec]
+        */
+       u8 idle_conn_thresh;
+} __packed;
+
 int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
                                  u32 sdio_blk_size, u32 extra_mem_blks,
                                  u32 len_field_size);
@@ -359,5 +379,6 @@ int wl18xx_acx_set_peer_cap(struct wl1271 *wl,
                            u32 rate_set, u8 hlid);
 int wl18xx_acx_interrupt_notify_config(struct wl1271 *wl, bool action);
 int wl18xx_acx_rx_ba_filter(struct wl1271 *wl, bool action);
+int wl18xx_acx_ap_sleep(struct wl1271 *wl);
 
 #endif /* __WL18XX_ACX_H__ */
index e34302e3b51d90077006870f29e70a83360b5167..71f1ec448ba5f782f0a7b9acfb35afa3e08f76d8 100644 (file)
@@ -23,7 +23,7 @@
 #define __WL18XX_CONF_H__
 
 #define WL18XX_CONF_MAGIC      0x10e100ca
-#define WL18XX_CONF_VERSION    (WLCORE_CONF_VERSION | 0x0006)
+#define WL18XX_CONF_VERSION    (WLCORE_CONF_VERSION | 0x0007)
 #define WL18XX_CONF_MASK       0x0000ffff
 #define WL18XX_CONF_SIZE       (WLCORE_CONF_SIZE + \
                                 sizeof(struct wl18xx_priv_conf))
@@ -110,12 +110,33 @@ struct wl18xx_ht_settings {
        u8 mode;
 } __packed;
 
+struct conf_ap_sleep_settings {
+       /* Duty Cycle (20-80% of staying Awake) for IDLE AP
+        * (0: disable)
+        */
+       u8 idle_duty_cycle;
+       /* Duty Cycle (20-80% of staying Awake) for Connected AP
+        * (0: disable)
+        */
+       u8 connected_duty_cycle;
+       /* Maximum stations that are allowed to be connected to AP
+        *  (255: no limit)
+        */
+       u8 max_stations_thresh;
+       /* Timeout till enabling the Sleep Mechanism after data stops
+        * [unit: 100 msec]
+        */
+       u8 idle_conn_thresh;
+} __packed;
+
 struct wl18xx_priv_conf {
        /* Module params structures */
        struct wl18xx_ht_settings ht;
 
        /* this structure is copied wholesale to FW */
        struct wl18xx_mac_and_phy_params phy;
+
+       struct conf_ap_sleep_settings ap_sleep;
 } __packed;
 
 #endif /* __WL18XX_CONF_H__ */
index 6c1000d1735beb625fe315a4b463118a3e640c5b..04db941e19134398b43d7dc2707887d70aa6605a 100644 (file)
@@ -568,6 +568,12 @@ static struct wl18xx_priv_conf wl18xx_default_priv_conf = {
                .high_power_val_2nd             = 0xff,
                .tx_rf_margin                   = 1,
        },
+       .ap_sleep = {               /* disabled by default */
+               .idle_duty_cycle        = 0,
+               .connected_duty_cycle   = 0,
+               .max_stations_thresh    = 0,
+               .idle_conn_thresh       = 0,
+       },
 };
 
 static const struct wlcore_partition_set wl18xx_ptable[PART_TABLE_LEN] = {
@@ -1696,6 +1702,7 @@ static struct wlcore_ops wl18xx_ops = {
        .smart_config_set_group_key = wl18xx_cmd_smart_config_set_group_key,
        .interrupt_notify = wl18xx_acx_interrupt_notify_config,
        .rx_ba_filter   = wl18xx_acx_rx_ba_filter,
+       .ap_sleep       = wl18xx_acx_ap_sleep,
 };
 
 /* HT cap appropriate for wide channels in 2Ghz */
index c2545ce6b2dbeb009491f882a702c3421e917bd8..449050b5c7500267ee403cb4422819c176f524ce 100644 (file)
@@ -233,6 +233,15 @@ wlcore_hw_rx_ba_filter(struct wl1271 *wl, bool action)
        return 0;
 }
 
+static inline int
+wlcore_hw_ap_sleep(struct wl1271 *wl)
+{
+       if (wl->ops->ap_sleep)
+               return wl->ops->ap_sleep(wl);
+
+       return 0;
+}
+
 static inline int
 wlcore_hw_set_peer_cap(struct wl1271 *wl,
                       struct ieee80211_sta_ht_cap *ht_cap,
index 199e941208644864e16479c4eb586afe8df69e86..5ca1fb161a50c8bbc612d859891fb9a3c8a441cf 100644 (file)
@@ -392,6 +392,11 @@ static int wl1271_ap_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif)
        if (ret < 0)
                return ret;
 
+       /* configure AP sleep, if enabled */
+       ret = wlcore_hw_ap_sleep(wl);
+       if (ret < 0)
+               return ret;
+
        return 0;
 }
 
@@ -567,8 +572,7 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
        /* consider all existing roles before configuring psm. */
 
        if (wl->ap_count == 0 && is_ap) { /* first AP */
-               /* Configure for power always on */
-               ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
+               ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
                if (ret < 0)
                        return ret;
 
index b52516eed7b20302b618fcbe4e7934651e12646e..f3ed543bfe73945b45e80a40d5f907b981994819 100644 (file)
@@ -56,9 +56,6 @@ void wl1271_elp_work(struct work_struct *work)
                goto out;
 
        wl12xx_for_each_wlvif(wl, wlvif) {
-               if (wlvif->bss_type == BSS_TYPE_AP_BSS)
-                       goto out;
-
                if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) &&
                    test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
                        goto out;
@@ -95,9 +92,6 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
                return;
 
        wl12xx_for_each_wlvif(wl, wlvif) {
-               if (wlvif->bss_type == BSS_TYPE_AP_BSS)
-                       return;
-
                if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) &&
                    test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
                        return;
index 7860a4e1d7916f54c42a573bdd56130fefb83c53..c8fe2ae272ac6e66a878a5f750a4d66aa3ae8b35 100644 (file)
@@ -118,6 +118,7 @@ struct wlcore_ops {
                             struct wl1271_link *lnk);
        int (*interrupt_notify)(struct wl1271 *wl, bool action);
        int (*rx_ba_filter)(struct wl1271 *wl, bool action);
+       int (*ap_sleep)(struct wl1271 *wl);
        int (*smart_config_start)(struct wl1271 *wl, u32 group_bitmap);
        int (*smart_config_stop)(struct wl1271 *wl);
        int (*smart_config_set_group_key)(struct wl1271 *wl, u16 group_id,