Commit e2f1e50f authored by Kobi L's avatar Kobi L Committed by Kalle Valo

wlcore: enable sleep during AP mode operation

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: default avatarKobi Leibovitch <kobi.lev100@gmail.com>
Signed-off-by: default avatarArik Nemtsov <arik@wizery.com>
Signed-off-by: default avatarEliad Peller <eliad@wizery.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent b8714d1b
...@@ -1731,6 +1731,7 @@ static struct wlcore_ops wl12xx_ops = { ...@@ -1731,6 +1731,7 @@ static struct wlcore_ops wl12xx_ops = {
.lnk_low_prio = wl12xx_lnk_low_prio, .lnk_low_prio = wl12xx_lnk_low_prio,
.interrupt_notify = NULL, .interrupt_notify = NULL,
.rx_ba_filter = NULL, .rx_ba_filter = NULL,
.ap_sleep = NULL,
}; };
static struct ieee80211_sta_ht_cap wl12xx_ht_cap = { static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "../wlcore/acx.h" #include "../wlcore/acx.h"
#include "acx.h" #include "acx.h"
#include "wl18xx.h"
int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap, int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
u32 sdio_blk_size, u32 extra_mem_blks, u32 sdio_blk_size, u32 extra_mem_blks,
...@@ -250,3 +251,34 @@ int wl18xx_acx_rx_ba_filter(struct wl1271 *wl, bool action) ...@@ -250,3 +251,34 @@ int wl18xx_acx_rx_ba_filter(struct wl1271 *wl, bool action)
kfree(acx); kfree(acx);
return ret; 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;
}
...@@ -34,8 +34,8 @@ enum { ...@@ -34,8 +34,8 @@ enum {
ACX_AUTO_RX_STREAMING = 0x0055, ACX_AUTO_RX_STREAMING = 0x0055,
ACX_PEER_CAP = 0x0056, ACX_PEER_CAP = 0x0056,
ACX_INTERRUPT_NOTIFY = 0x0057, 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) */ /* numbers of bits the length field takes (add 1 for the actual number) */
...@@ -347,6 +347,26 @@ struct wl18xx_acx_rx_ba_filter { ...@@ -347,6 +347,26 @@ struct wl18xx_acx_rx_ba_filter {
u32 enable; 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, int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
u32 sdio_blk_size, u32 extra_mem_blks, u32 sdio_blk_size, u32 extra_mem_blks,
u32 len_field_size); u32 len_field_size);
...@@ -359,5 +379,6 @@ int wl18xx_acx_set_peer_cap(struct wl1271 *wl, ...@@ -359,5 +379,6 @@ int wl18xx_acx_set_peer_cap(struct wl1271 *wl,
u32 rate_set, u8 hlid); u32 rate_set, u8 hlid);
int wl18xx_acx_interrupt_notify_config(struct wl1271 *wl, bool action); 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_rx_ba_filter(struct wl1271 *wl, bool action);
int wl18xx_acx_ap_sleep(struct wl1271 *wl);
#endif /* __WL18XX_ACX_H__ */ #endif /* __WL18XX_ACX_H__ */
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#define __WL18XX_CONF_H__ #define __WL18XX_CONF_H__
#define WL18XX_CONF_MAGIC 0x10e100ca #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_MASK 0x0000ffff
#define WL18XX_CONF_SIZE (WLCORE_CONF_SIZE + \ #define WL18XX_CONF_SIZE (WLCORE_CONF_SIZE + \
sizeof(struct wl18xx_priv_conf)) sizeof(struct wl18xx_priv_conf))
...@@ -110,12 +110,33 @@ struct wl18xx_ht_settings { ...@@ -110,12 +110,33 @@ struct wl18xx_ht_settings {
u8 mode; u8 mode;
} __packed; } __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 { struct wl18xx_priv_conf {
/* Module params structures */ /* Module params structures */
struct wl18xx_ht_settings ht; struct wl18xx_ht_settings ht;
/* this structure is copied wholesale to FW */ /* this structure is copied wholesale to FW */
struct wl18xx_mac_and_phy_params phy; struct wl18xx_mac_and_phy_params phy;
struct conf_ap_sleep_settings ap_sleep;
} __packed; } __packed;
#endif /* __WL18XX_CONF_H__ */ #endif /* __WL18XX_CONF_H__ */
...@@ -568,6 +568,12 @@ static struct wl18xx_priv_conf wl18xx_default_priv_conf = { ...@@ -568,6 +568,12 @@ static struct wl18xx_priv_conf wl18xx_default_priv_conf = {
.high_power_val_2nd = 0xff, .high_power_val_2nd = 0xff,
.tx_rf_margin = 1, .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] = { static const struct wlcore_partition_set wl18xx_ptable[PART_TABLE_LEN] = {
...@@ -1696,6 +1702,7 @@ static struct wlcore_ops wl18xx_ops = { ...@@ -1696,6 +1702,7 @@ static struct wlcore_ops wl18xx_ops = {
.smart_config_set_group_key = wl18xx_cmd_smart_config_set_group_key, .smart_config_set_group_key = wl18xx_cmd_smart_config_set_group_key,
.interrupt_notify = wl18xx_acx_interrupt_notify_config, .interrupt_notify = wl18xx_acx_interrupt_notify_config,
.rx_ba_filter = wl18xx_acx_rx_ba_filter, .rx_ba_filter = wl18xx_acx_rx_ba_filter,
.ap_sleep = wl18xx_acx_ap_sleep,
}; };
/* HT cap appropriate for wide channels in 2Ghz */ /* HT cap appropriate for wide channels in 2Ghz */
......
...@@ -233,6 +233,15 @@ wlcore_hw_rx_ba_filter(struct wl1271 *wl, bool action) ...@@ -233,6 +233,15 @@ wlcore_hw_rx_ba_filter(struct wl1271 *wl, bool action)
return 0; 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 static inline int
wlcore_hw_set_peer_cap(struct wl1271 *wl, wlcore_hw_set_peer_cap(struct wl1271 *wl,
struct ieee80211_sta_ht_cap *ht_cap, struct ieee80211_sta_ht_cap *ht_cap,
......
...@@ -392,6 +392,11 @@ static int wl1271_ap_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif) ...@@ -392,6 +392,11 @@ static int wl1271_ap_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif)
if (ret < 0) if (ret < 0)
return ret; return ret;
/* configure AP sleep, if enabled */
ret = wlcore_hw_ap_sleep(wl);
if (ret < 0)
return ret;
return 0; return 0;
} }
...@@ -567,8 +572,7 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif) ...@@ -567,8 +572,7 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
/* consider all existing roles before configuring psm. */ /* consider all existing roles before configuring psm. */
if (wl->ap_count == 0 && is_ap) { /* first AP */ if (wl->ap_count == 0 && is_ap) { /* first AP */
/* Configure for power always on */ ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -56,9 +56,6 @@ void wl1271_elp_work(struct work_struct *work) ...@@ -56,9 +56,6 @@ void wl1271_elp_work(struct work_struct *work)
goto out; goto out;
wl12xx_for_each_wlvif(wl, wlvif) { 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) && if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) &&
test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
goto out; goto out;
...@@ -95,9 +92,6 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl) ...@@ -95,9 +92,6 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
return; return;
wl12xx_for_each_wlvif(wl, wlvif) { wl12xx_for_each_wlvif(wl, wlvif) {
if (wlvif->bss_type == BSS_TYPE_AP_BSS)
return;
if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) && if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) &&
test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
return; return;
......
...@@ -118,6 +118,7 @@ struct wlcore_ops { ...@@ -118,6 +118,7 @@ struct wlcore_ops {
struct wl1271_link *lnk); struct wl1271_link *lnk);
int (*interrupt_notify)(struct wl1271 *wl, bool action); int (*interrupt_notify)(struct wl1271 *wl, bool action);
int (*rx_ba_filter)(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_start)(struct wl1271 *wl, u32 group_bitmap);
int (*smart_config_stop)(struct wl1271 *wl); int (*smart_config_stop)(struct wl1271 *wl);
int (*smart_config_set_group_key)(struct wl1271 *wl, u16 group_id, int (*smart_config_set_group_key)(struct wl1271 *wl, u16 group_id,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment