linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/7] wl12xx: add some psm/suspend features
@ 2012-01-30 14:58 Eliad Peller
  2012-01-30 14:58 ` [PATCH 1/7] wl12xx: Set different wake up conditions in case of suspend Eliad Peller
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: Eliad Peller @ 2012-01-30 14:58 UTC (permalink / raw)
  To: Luciano Coelho; +Cc: linux-wireless

Add some psm / suspend features:
* Add the ability to force psm (by default, the fw uses dynamic ps)
* Use differnet wake up conditions on suspend
* Add pattern support to wowlan triggers

Eyal Shapira (4):
  wl12xx: Set different wake up conditions in case of suspend
  wl12xx: add suspend_listen_interval debugfs file
  wl12xx: add forced_ps mode
  wl12xx: add forced_ps debugfs file

Pontus Fuchs (3):
  wl12xx: Add rx data filter commands
  wl12xx: Add functions for managing rx data filters
  wl12xx: Add support for WoWLAN packet pattern trigger

 drivers/net/wireless/wl12xx/acx.c     |  100 ++++++++++++++++++-
 drivers/net/wireless/wl12xx/acx.h     |   45 ++++++++-
 drivers/net/wireless/wl12xx/conf.h    |   19 ++++
 drivers/net/wireless/wl12xx/debugfs.c |  131 ++++++++++++++++++++++++-
 drivers/net/wireless/wl12xx/main.c    |  178 ++++++++++++++++++++++++++++++---
 drivers/net/wireless/wl12xx/ps.c      |   12 ++-
 drivers/net/wireless/wl12xx/rx.c      |  105 +++++++++++++++++++
 drivers/net/wireless/wl12xx/rx.h      |   14 +++-
 drivers/net/wireless/wl12xx/wl12xx.h  |   38 +++++++-
 9 files changed, 616 insertions(+), 26 deletions(-)

-- 
1.7.6.401.g6a319


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/7] wl12xx: Set different wake up conditions in case of suspend
  2012-01-30 14:58 [PATCH 0/7] wl12xx: add some psm/suspend features Eliad Peller
@ 2012-01-30 14:58 ` Eliad Peller
  2012-01-30 14:58 ` [PATCH 2/7] wl12xx: add suspend_listen_interval debugfs file Eliad Peller
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Eliad Peller @ 2012-01-30 14:58 UTC (permalink / raw)
  To: Luciano Coelho; +Cc: linux-wireless

From: Eyal Shapira <eyal@wizery.com>

Added ability to set different wake up conditions for suspend/resume.
Set default values to wake up every 3 DTIMs while suspended
and every 1 DTIM while resumed

Signed-off-by: Eyal Shapira <eyal@wizery.com>
Signed-off-by: Eliad Peller <eliad@wizery.com>
---
 drivers/net/wireless/wl12xx/acx.c  |   10 ++++---
 drivers/net/wireless/wl12xx/acx.h  |    3 +-
 drivers/net/wireless/wl12xx/conf.h |   13 +++++++++
 drivers/net/wireless/wl12xx/main.c |   51 +++++++++++++++++++++++++++++++++--
 drivers/net/wireless/wl12xx/ps.c   |    4 ++-
 5 files changed, 72 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index af2c312..bc96db0 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -34,12 +34,14 @@
 #include "reg.h"
 #include "ps.h"
 
-int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+				  u8 wake_up_event, u8 listen_interval)
 {
 	struct acx_wake_up_condition *wake_up;
 	int ret;
 
-	wl1271_debug(DEBUG_ACX, "acx wake up conditions");
+	wl1271_debug(DEBUG_ACX, "acx wake up conditions (wake_up_event %d listen_interval %d)",
+		     wake_up_event, listen_interval);
 
 	wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL);
 	if (!wake_up) {
@@ -48,8 +50,8 @@ int wl1271_acx_wake_up_conditions(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 	}
 
 	wake_up->role_id = wlvif->role_id;
-	wake_up->wake_up_event = wl->conf.conn.wake_up_event;
-	wake_up->listen_interval = wl->conf.conn.listen_interval;
+	wake_up->wake_up_event = wake_up_event;
+	wake_up->listen_interval = listen_interval;
 
 	ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS,
 				   wake_up, sizeof(*wake_up));
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index 0749df5..a28fc04 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -1226,7 +1226,8 @@ enum {
 
 
 int wl1271_acx_wake_up_conditions(struct wl1271 *wl,
-				  struct wl12xx_vif *wlvif);
+				  struct wl12xx_vif *wlvif,
+				  u8 wake_up_event, u8 listen_interval);
 int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth);
 int wl1271_acx_tx_power(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 			int power);
diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h
index 10e5e3d..d97aad6 100644
--- a/drivers/net/wireless/wl12xx/conf.h
+++ b/drivers/net/wireless/wl12xx/conf.h
@@ -810,6 +810,19 @@ struct conf_conn_settings {
 	u8 listen_interval;
 
 	/*
+	 * Firmware wakeup conditions during suspend
+	 * Range: CONF_WAKE_UP_EVENT_*
+	 */
+	u8 suspend_wake_up_event;
+
+	/*
+	 * Listen interval during suspend.
+	 * Currently will be in DTIMs (1-10)
+	 *
+	 */
+	u8 suspend_listen_interval;
+
+	/*
 	 * Enable or disable the beacon filtering.
 	 *
 	 * Range: CONF_BCN_FILT_MODE_*
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 2bb1c24..29a00fc 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -218,6 +218,8 @@ static struct conf_drv_settings default_conf = {
 	.conn = {
 		.wake_up_event               = CONF_WAKE_UP_EVENT_DTIM,
 		.listen_interval             = 1,
+		.suspend_wake_up_event       = CONF_WAKE_UP_EVENT_N_DTIM,
+		.suspend_listen_interval     = 3,
 		.bcn_filt_mode               = CONF_BCN_FILT_MODE_ENABLED,
 		.bcn_filt_ie_count           = 2,
 		.bcn_filt_ie = {
@@ -1561,6 +1563,35 @@ static struct notifier_block wl1271_dev_notifier = {
 };
 
 #ifdef CONFIG_PM
+static int wl1271_configure_suspend_sta(struct wl1271 *wl,
+					struct wl12xx_vif *wlvif)
+{
+	int ret = 0;
+
+	mutex_lock(&wl->mutex);
+
+	if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
+		goto out_unlock;
+
+	ret = wl1271_ps_elp_wakeup(wl);
+	if (ret < 0)
+		goto out_unlock;
+
+	ret = wl1271_acx_wake_up_conditions(wl, wlvif,
+				    wl->conf.conn.suspend_wake_up_event,
+				    wl->conf.conn.suspend_listen_interval);
+
+	if (ret < 0)
+		wl1271_error("suspend: set wake up conditions failed: %d", ret);
+
+
+	wl1271_ps_elp_sleep(wl);
+
+out_unlock:
+	mutex_unlock(&wl->mutex);
+	return ret;
+
+}
 
 static int wl1271_configure_suspend_ap(struct wl1271 *wl,
 				       struct wl12xx_vif *wlvif)
@@ -1588,6 +1619,8 @@ out_unlock:
 static int wl1271_configure_suspend(struct wl1271 *wl,
 				    struct wl12xx_vif *wlvif)
 {
+	if (wlvif->bss_type == BSS_TYPE_STA_BSS)
+		return wl1271_configure_suspend_sta(wl, wlvif);
 	if (wlvif->bss_type == BSS_TYPE_AP_BSS)
 		return wl1271_configure_suspend_ap(wl, wlvif);
 	return 0;
@@ -1596,10 +1629,11 @@ static int wl1271_configure_suspend(struct wl1271 *wl,
 static void wl1271_configure_resume(struct wl1271 *wl,
 				    struct wl12xx_vif *wlvif)
 {
-	int ret;
+	int ret = 0;
 	bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
+	bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
 
-	if (!is_ap)
+	if ((!is_ap) && (!is_sta))
 		return;
 
 	mutex_lock(&wl->mutex);
@@ -1607,7 +1641,18 @@ static void wl1271_configure_resume(struct wl1271 *wl,
 	if (ret < 0)
 		goto out;
 
-	wl1271_acx_beacon_filter_opt(wl, wlvif, false);
+	if (is_sta) {
+		ret = wl1271_acx_wake_up_conditions(wl, wlvif,
+				    wl->conf.conn.wake_up_event,
+				    wl->conf.conn.listen_interval);
+
+		if (ret < 0)
+			wl1271_error("resume: wake up conditions failed: %d",
+				     ret);
+
+	} else if (is_ap) {
+		ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
+	}
 
 	wl1271_ps_elp_sleep(wl);
 out:
diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c
index e209e29..d197922 100644
--- a/drivers/net/wireless/wl12xx/ps.c
+++ b/drivers/net/wireless/wl12xx/ps.c
@@ -170,7 +170,9 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 		wl1271_debug(DEBUG_PSM, "entering psm (mode=%d,timeout=%u)",
 			     mode, timeout);
 
-		ret = wl1271_acx_wake_up_conditions(wl, wlvif);
+		ret = wl1271_acx_wake_up_conditions(wl, wlvif,
+					    wl->conf.conn.wake_up_event,
+					    wl->conf.conn.listen_interval);
 		if (ret < 0) {
 			wl1271_error("couldn't set wake up conditions");
 			return ret;
-- 
1.7.6.401.g6a319


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/7] wl12xx: add suspend_listen_interval debugfs file
  2012-01-30 14:58 [PATCH 0/7] wl12xx: add some psm/suspend features Eliad Peller
  2012-01-30 14:58 ` [PATCH 1/7] wl12xx: Set different wake up conditions in case of suspend Eliad Peller
@ 2012-01-30 14:58 ` Eliad Peller
  2012-01-30 14:58 ` [PATCH 3/7] wl12xx: add forced_ps mode Eliad Peller
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Eliad Peller @ 2012-01-30 14:58 UTC (permalink / raw)
  To: Luciano Coelho; +Cc: linux-wireless

From: Eyal Shapira <eyal@wizery.com>

Add read/write to suspend_dtim_interval file which
controls the number of DTIM periods between wakeups
while the host is suspended.
The value while the host is resumed is controlled
by the file dtim_interval which existed previously.

Signed-off-by: Eyal Shapira <eyal@wizery.com>
Signed-off-by: Eliad Peller <eliad@wizery.com>
---
 drivers/net/wireless/wl12xx/debugfs.c |   59 +++++++++++++++++++++++++++++++++
 1 files changed, 59 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index 4dcb3f7..15353fa 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -625,6 +625,64 @@ static const struct file_operations dtim_interval_ops = {
 	.llseek = default_llseek,
 };
 
+
+
+static ssize_t suspend_dtim_interval_read(struct file *file,
+					  char __user *user_buf,
+					  size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+	u8 value;
+
+	if (wl->conf.conn.suspend_wake_up_event == CONF_WAKE_UP_EVENT_DTIM ||
+	    wl->conf.conn.suspend_wake_up_event == CONF_WAKE_UP_EVENT_N_DTIM)
+		value = wl->conf.conn.suspend_listen_interval;
+	else
+		value = 0;
+
+	return wl1271_format_buffer(user_buf, count, ppos, "%d\n", value);
+}
+
+static ssize_t suspend_dtim_interval_write(struct file *file,
+					   const char __user *user_buf,
+					   size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+	unsigned long value;
+	int ret;
+
+	ret = kstrtoul_from_user(user_buf, count, 10, &value);
+	if (ret < 0) {
+		wl1271_warning("illegal value for suspend_dtim_interval");
+		return -EINVAL;
+	}
+
+	if (value < 1 || value > 10) {
+		wl1271_warning("suspend_dtim value is not in valid range");
+		return -ERANGE;
+	}
+
+	mutex_lock(&wl->mutex);
+
+	wl->conf.conn.suspend_listen_interval = value;
+	/* for some reason there are different event types for 1 and >1 */
+	if (value == 1)
+		wl->conf.conn.suspend_wake_up_event = CONF_WAKE_UP_EVENT_DTIM;
+	else
+		wl->conf.conn.suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM;
+
+	mutex_unlock(&wl->mutex);
+	return count;
+}
+
+
+static const struct file_operations suspend_dtim_interval_ops = {
+	.read = suspend_dtim_interval_read,
+	.write = suspend_dtim_interval_write,
+	.open = wl1271_open_file_generic,
+	.llseek = default_llseek,
+};
+
 static ssize_t beacon_interval_read(struct file *file, char __user *user_buf,
 				    size_t count, loff_t *ppos)
 {
@@ -949,6 +1007,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
 	DEBUGFS_ADD(driver_state, rootdir);
 	DEBUGFS_ADD(vifs_state, rootdir);
 	DEBUGFS_ADD(dtim_interval, rootdir);
+	DEBUGFS_ADD(suspend_dtim_interval, rootdir);
 	DEBUGFS_ADD(beacon_interval, rootdir);
 	DEBUGFS_ADD(beacon_filtering, rootdir);
 	DEBUGFS_ADD(dynamic_ps_timeout, rootdir);
-- 
1.7.6.401.g6a319


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 3/7] wl12xx: add forced_ps mode
  2012-01-30 14:58 [PATCH 0/7] wl12xx: add some psm/suspend features Eliad Peller
  2012-01-30 14:58 ` [PATCH 1/7] wl12xx: Set different wake up conditions in case of suspend Eliad Peller
  2012-01-30 14:58 ` [PATCH 2/7] wl12xx: add suspend_listen_interval debugfs file Eliad Peller
@ 2012-01-30 14:58 ` Eliad Peller
  2012-01-30 14:58 ` [PATCH 4/7] wl12xx: add forced_ps debugfs file Eliad Peller
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Eliad Peller @ 2012-01-30 14:58 UTC (permalink / raw)
  To: Luciano Coelho; +Cc: linux-wireless

From: Eyal Shapira <eyal@wizery.com>

For certain WiFi certification tests forcing PS
is necessary. Since DPS is now enabled in the FW
and this can't be achieved by using netlatency
this required a new config option.

Signed-off-by: Eyal Shapira <eyal@wizery.com>
Signed-off-by: Eliad Peller <eliad@wizery.com>
---
 drivers/net/wireless/wl12xx/conf.h    |    6 ++++++
 drivers/net/wireless/wl12xx/debugfs.c |    2 +-
 drivers/net/wireless/wl12xx/main.c    |   25 +++++++++++++++++++------
 drivers/net/wireless/wl12xx/ps.c      |    8 ++++----
 drivers/net/wireless/wl12xx/wl12xx.h  |    2 +-
 5 files changed, 31 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h
index d97aad6..f29fbfd 100644
--- a/drivers/net/wireless/wl12xx/conf.h
+++ b/drivers/net/wireless/wl12xx/conf.h
@@ -934,6 +934,12 @@ struct conf_conn_settings {
 	u16 dynamic_ps_timeout;
 
 	/*
+	 * Specifies whether dynamic PS should be disabled and PSM forced.
+	 * This is required for certain WiFi certification tests.
+	 */
+	u8 forced_ps;
+
+	/*
 	 *
 	 * Specifies the interval of the connection keep-alive null-func
 	 * frame in ms.
diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index 15353fa..02da445 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -358,7 +358,7 @@ static ssize_t dynamic_ps_timeout_write(struct file *file,
 	 */
 
 	wl12xx_for_each_wlvif_sta(wl, wlvif) {
-		if (test_bit(WLVIF_FLAG_IN_AUTO_PS, &wlvif->flags))
+		if (test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags))
 			wl1271_ps_set_mode(wl, wlvif, STATION_AUTO_PS_MODE);
 	}
 
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 29a00fc..f2960df 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -244,6 +244,7 @@ static struct conf_drv_settings default_conf = {
 		.psm_exit_retries            = 16,
 		.psm_entry_nullfunc_retries  = 3,
 		.dynamic_ps_timeout          = 100,
+		.forced_ps                   = false,
 		.keep_alive_interval         = 55000,
 		.max_listen_interval         = 20,
 	},
@@ -2481,17 +2482,29 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 
 		if ((conf->flags & IEEE80211_CONF_PS) &&
 		    test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
-		    !test_bit(WLVIF_FLAG_IN_AUTO_PS, &wlvif->flags)) {
+		    !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
 
-			wl1271_debug(DEBUG_PSM, "auto ps enabled");
+			int ps_mode;
+			char *ps_mode_str;
+
+			if (wl->conf.conn.forced_ps) {
+				ps_mode = STATION_POWER_SAVE_MODE;
+				ps_mode_str = "forced";
+			} else {
+				ps_mode = STATION_AUTO_PS_MODE;
+				ps_mode_str = "auto";
+			}
+
+			wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str);
+
+			ret = wl1271_ps_set_mode(wl, wlvif, ps_mode);
 
-			ret = wl1271_ps_set_mode(wl, wlvif,
-						 STATION_AUTO_PS_MODE);
 			if (ret < 0)
-				wl1271_warning("enter auto ps failed %d", ret);
+				wl1271_warning("enter %s ps failed %d",
+					       ps_mode_str, ret);
 
 		} else if (!(conf->flags & IEEE80211_CONF_PS) &&
-			   test_bit(WLVIF_FLAG_IN_AUTO_PS, &wlvif->flags)) {
+			   test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
 
 			wl1271_debug(DEBUG_PSM, "auto ps disabled");
 
diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c
index d197922..fa993c2 100644
--- a/drivers/net/wireless/wl12xx/ps.c
+++ b/drivers/net/wireless/wl12xx/ps.c
@@ -56,7 +56,7 @@ void wl1271_elp_work(struct work_struct *work)
 		if (wlvif->bss_type == BSS_TYPE_AP_BSS)
 			goto out;
 
-		if (!test_bit(WLVIF_FLAG_IN_AUTO_PS, &wlvif->flags) &&
+		if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) &&
 		    test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
 			goto out;
 	}
@@ -84,7 +84,7 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
 		if (wlvif->bss_type == BSS_TYPE_AP_BSS)
 			return;
 
-		if (!test_bit(WLVIF_FLAG_IN_AUTO_PS, &wlvif->flags) &&
+		if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) &&
 		    test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
 			return;
 	}
@@ -182,7 +182,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 		if (ret < 0)
 			return ret;
 
-		set_bit(WLVIF_FLAG_IN_AUTO_PS, &wlvif->flags);
+		set_bit(WLVIF_FLAG_IN_PS, &wlvif->flags);
 
 		/* enable beacon early termination. Not relevant for 5GHz */
 		if (wlvif->band == IEEE80211_BAND_2GHZ) {
@@ -205,7 +205,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
 		if (ret < 0)
 			return ret;
 
-		clear_bit(WLVIF_FLAG_IN_AUTO_PS, &wlvif->flags);
+		clear_bit(WLVIF_FLAG_IN_PS, &wlvif->flags);
 		break;
 	case STATION_POWER_SAVE_MODE:
 	default:
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 9cc7051..1463341 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -254,7 +254,7 @@ enum wl12xx_vif_flags {
 	WLVIF_FLAG_STA_ASSOCIATED,
 	WLVIF_FLAG_IBSS_JOINED,
 	WLVIF_FLAG_AP_STARTED,
-	WLVIF_FLAG_IN_AUTO_PS,
+	WLVIF_FLAG_IN_PS,
 	WLVIF_FLAG_STA_STATE_SENT,
 	WLVIF_FLAG_RX_STREAMING_STARTED,
 	WLVIF_FLAG_PSPOLL_FAILURE,
-- 
1.7.6.401.g6a319


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 4/7] wl12xx: add forced_ps debugfs file
  2012-01-30 14:58 [PATCH 0/7] wl12xx: add some psm/suspend features Eliad Peller
                   ` (2 preceding siblings ...)
  2012-01-30 14:58 ` [PATCH 3/7] wl12xx: add forced_ps mode Eliad Peller
@ 2012-01-30 14:58 ` Eliad Peller
  2012-01-30 14:58 ` [PATCH 5/7] wl12xx: Add rx data filter commands Eliad Peller
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Eliad Peller @ 2012-01-30 14:58 UTC (permalink / raw)
  To: Luciano Coelho; +Cc: linux-wireless

From: Eyal Shapira <eyal@wizery.com>

Added control over forced_ps option through debugfs.
This can be either 1 or 0.

Signed-off-by: Eyal Shapira <eyal@wizery.com>
Signed-off-by: Eliad Peller <eliad@wizery.com>
---
 drivers/net/wireless/wl12xx/debugfs.c |   70 +++++++++++++++++++++++++++++++++
 1 files changed, 70 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index 02da445..1c26238 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -376,6 +376,75 @@ static const struct file_operations dynamic_ps_timeout_ops = {
 	.llseek = default_llseek,
 };
 
+static ssize_t forced_ps_read(struct file *file, char __user *user_buf,
+			  size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+
+	return wl1271_format_buffer(user_buf, count,
+				    ppos, "%d\n",
+				    wl->conf.conn.forced_ps);
+}
+
+static ssize_t forced_ps_write(struct file *file,
+				    const char __user *user_buf,
+				    size_t count, loff_t *ppos)
+{
+	struct wl1271 *wl = file->private_data;
+	struct wl12xx_vif *wlvif;
+	unsigned long value;
+	int ret, ps_mode;
+
+	ret = kstrtoul_from_user(user_buf, count, 10, &value);
+	if (ret < 0) {
+		wl1271_warning("illegal value in forced_ps");
+		return -EINVAL;
+	}
+
+	if (value != 1 && value != 0) {
+		wl1271_warning("forced_ps should be either 0 or 1");
+		return -ERANGE;
+	}
+
+	mutex_lock(&wl->mutex);
+
+	if (wl->conf.conn.forced_ps == value)
+		goto out;
+
+	wl->conf.conn.forced_ps = value;
+
+	if (wl->state == WL1271_STATE_OFF)
+		goto out;
+
+	ret = wl1271_ps_elp_wakeup(wl);
+	if (ret < 0)
+		goto out;
+
+	/* In case we're already in PSM, trigger it again to switch mode
+	 * immediately without waiting for re-association
+	 */
+
+	ps_mode = value ? STATION_POWER_SAVE_MODE : STATION_AUTO_PS_MODE;
+
+	wl12xx_for_each_wlvif_sta(wl, wlvif) {
+		if (test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags))
+			wl1271_ps_set_mode(wl, wlvif, ps_mode);
+	}
+
+	wl1271_ps_elp_sleep(wl);
+
+out:
+	mutex_unlock(&wl->mutex);
+	return count;
+}
+
+static const struct file_operations forced_ps_ops = {
+	.read = forced_ps_read,
+	.write = forced_ps_write,
+	.open = wl1271_open_file_generic,
+	.llseek = default_llseek,
+};
+
 static ssize_t driver_state_read(struct file *file, char __user *user_buf,
 				 size_t count, loff_t *ppos)
 {
@@ -1011,6 +1080,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
 	DEBUGFS_ADD(beacon_interval, rootdir);
 	DEBUGFS_ADD(beacon_filtering, rootdir);
 	DEBUGFS_ADD(dynamic_ps_timeout, rootdir);
+	DEBUGFS_ADD(forced_ps, rootdir);
 
 	streaming = debugfs_create_dir("rx_streaming", rootdir);
 	if (!streaming || IS_ERR(streaming))
-- 
1.7.6.401.g6a319


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 5/7] wl12xx: Add rx data filter commands
  2012-01-30 14:58 [PATCH 0/7] wl12xx: add some psm/suspend features Eliad Peller
                   ` (3 preceding siblings ...)
  2012-01-30 14:58 ` [PATCH 4/7] wl12xx: add forced_ps debugfs file Eliad Peller
@ 2012-01-30 14:58 ` Eliad Peller
  2012-01-30 14:58 ` [PATCH 6/7] wl12xx: Add functions for managing rx data filters Eliad Peller
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Eliad Peller @ 2012-01-30 14:58 UTC (permalink / raw)
  To: Luciano Coelho; +Cc: linux-wireless

From: Pontus Fuchs <pontus.fuchs@gmail.com>

Add acx command, structs and definitions needed for the rx data
filter commands.

Signed-off-by: Pontus Fuchs <pontus.fuchs@gmail.com>
Signed-off-by: Ido Reis <idor@ti.com>
Signed-off-by: Eliad Peller <eliad@wizery.com>
---
 drivers/net/wireless/wl12xx/acx.c    |   90 ++++++++++++++++++++++++++++++++++
 drivers/net/wireless/wl12xx/acx.h    |   42 ++++++++++++++++
 drivers/net/wireless/wl12xx/wl12xx.h |   15 ++++++
 3 files changed, 147 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index bc96db0..05bd79c 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -1740,3 +1740,93 @@ out:
 	return ret;
 
 }
+
+int wl1271_acx_toggle_rx_data_filter(struct wl1271 *wl, bool enable,
+				     u8 default_action)
+{
+	struct acx_rx_data_filter_state *acx;
+	int ret;
+
+	wl1271_debug(DEBUG_ACX, "acx toggle rx data filter en: %d act: %d",
+		     enable, default_action);
+
+	acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+	if (!acx) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	acx->enable = enable ? 1 : 0;
+	acx->default_action = default_action;
+
+	ret = wl1271_cmd_configure(wl, ACX_ENABLE_RX_DATA_FILTER, acx,
+				   sizeof(*acx));
+	if (ret < 0) {
+		wl1271_warning("toggling rx data filter failed: %d", ret);
+		goto out;
+	}
+
+out:
+	kfree(acx);
+	return ret;
+}
+
+int wl1271_acx_set_rx_data_filter(struct wl1271 *wl, bool add, u8 index,
+				  u8 action, u8 *pattern, u8 length, u16 offset)
+{
+	struct acx_rx_data_filter_cfg *acx;
+	int ret;
+
+	wl1271_debug(DEBUG_ACX, "acx set rx data filter add: %d idx: %d "
+		     "act: %d pat_len: %d offset: %d", add, index, action,
+		     length, offset);
+
+	acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+	if (!acx) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (index >= WL1271_MAX_RX_DATA_FILTERS ||
+	    length > WL1271_RX_DATA_FILTER_MAX_PATTERN_SIZE ||
+	    (add && !pattern)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	acx->add_filter = add ? 1 : 0;
+	acx->index = index;
+	acx->num_fields = 1;
+	acx->action = action;
+
+	if (add) {
+		/* pattern description */
+		acx->length = length;
+		memcpy(acx->pattern, pattern, length);
+
+		if (offset + length <= WL1271_RX_DATA_FILTER_ETH_HEADER_SIZE) {
+			acx->flag = WL1271_RX_DATA_FILTER_FLAG_ETHERNET_HEADER;
+			acx->offset = cpu_to_le16(offset);
+		} else if (offset >= WL1271_RX_DATA_FILTER_ETH_HEADER_SIZE) {
+			acx->flag = WL1271_RX_DATA_FILTER_FLAG_IP_HEADER;
+			acx->offset = cpu_to_le16(offset -
+				      WL1271_RX_DATA_FILTER_ETH_HEADER_SIZE);
+		} else {
+			wl1271_error("header boundry crossing filters not "
+				     "supported currently");
+			ret = -EINVAL;
+			goto out;
+		}
+	}
+
+	ret = wl1271_cmd_configure(wl, ACX_SET_RX_DATA_FILTER, acx,
+				   sizeof(*acx));
+	if (ret < 0) {
+		wl1271_warning("setting rx data filter failed: %d", ret);
+		goto out;
+	}
+
+out:
+	kfree(acx);
+	return ret;
+}
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index a28fc04..d68cfd2 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -1152,6 +1152,43 @@ struct wl12xx_acx_config_hangover {
 	u8 padding[2];
 } __packed;
 
+
+struct acx_rx_data_filter_state {
+	struct acx_header header;
+	u8 enable;
+
+	/* action of type FILTER_XXX */
+	u8 default_action;
+	u8 pad[2];
+} __packed;
+
+
+struct acx_rx_data_filter_cfg {
+	struct acx_header header;
+
+	u8 add_filter;
+
+	/* range 0 - MAX_DATA_FILTERS */
+	u8 index;
+
+	/* action of type FILTER_XXX */
+	u8 action;
+
+	/* number of fields in this filter */
+	u8 num_fields;
+
+	/*
+	 * currently we only support a single filtering field in the driver, so
+	 * spell it out directly here
+	 */
+
+	/* The offset is taken from the start of the first MAC addr */
+	__le16 offset;
+	u8 length;
+	u8 flag;
+	u8 pattern[WL1271_RX_DATA_FILTER_MAX_PATTERN_SIZE];
+} __packed;
+
 enum {
 	ACX_WAKE_UP_CONDITIONS           = 0x0000,
 	ACX_MEM_CFG                      = 0x0001,
@@ -1310,5 +1347,10 @@ int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
 int wl1271_acx_fm_coex(struct wl1271 *wl);
 int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl);
 int wl12xx_acx_config_hangover(struct wl1271 *wl);
+int wl1271_acx_toggle_rx_data_filter(struct wl1271 *wl, bool enable,
+				     u8 default_action);
+int wl1271_acx_set_rx_data_filter(struct wl1271 *wl, bool add, u8 index,
+				  u8 action, u8 *pattern, u8 length,
+				  u16 offset);
 
 #endif /* __WL1271_ACX_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 1463341..d29de3f 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -277,6 +277,21 @@ struct wl1271_link {
 	u8 ba_bitmap;
 };
 
+#define WL1271_MAX_RX_DATA_FILTERS 4
+#define WL1271_MAX_RX_DATA_FILTER_SIZE 98
+#define WL1271_RX_DATA_FILTER_MAX_FIELD_PATTERNS 8
+#define WL1271_RX_DATA_FILTER_MAX_PATTERN_SIZE 64
+#define WL1271_RX_DATA_FILTER_ETH_HEADER_SIZE 14
+
+#define WL1271_RX_DATA_FILTER_FLAG_IP_HEADER           0
+#define WL1271_RX_DATA_FILTER_FLAG_ETHERNET_HEADER     2
+
+enum rx_data_filter_action {
+	FILTER_DROP = 0,
+	FILTER_SIGNAL = 1,
+	FILTER_FW_HANDLE = 2
+};
+
 struct wl1271 {
 	struct ieee80211_hw *hw;
 	bool mac80211_registered;
-- 
1.7.6.401.g6a319


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 6/7] wl12xx: Add functions for managing rx data filters
  2012-01-30 14:58 [PATCH 0/7] wl12xx: add some psm/suspend features Eliad Peller
                   ` (4 preceding siblings ...)
  2012-01-30 14:58 ` [PATCH 5/7] wl12xx: Add rx data filter commands Eliad Peller
@ 2012-01-30 14:58 ` Eliad Peller
  2012-01-30 14:58 ` [PATCH 7/7] wl12xx: Add support for WoWLAN packet pattern trigger Eliad Peller
  2012-01-31  7:43 ` [PATCH 0/7] wl12xx: add some psm/suspend features Luciano Coelho
  7 siblings, 0 replies; 9+ messages in thread
From: Eliad Peller @ 2012-01-30 14:58 UTC (permalink / raw)
  To: Luciano Coelho; +Cc: linux-wireless

From: Pontus Fuchs <pontus.fuchs@gmail.com>

These functions will make sure filters are set according to what the
firmware expects. It also stores the filter state in the driver.

Signed-off-by: Pontus Fuchs <pontus.fuchs@gmail.com>
Signed-off-by: Ido Reis <idor@ti.com>
Signed-off-by: Eliad Peller <eliad@wizery.com>
---
 drivers/net/wireless/wl12xx/rx.c     |  105 ++++++++++++++++++++++++++++++++++
 drivers/net/wireless/wl12xx/rx.h     |   14 ++++-
 drivers/net/wireless/wl12xx/wl12xx.h |   21 +++++++
 3 files changed, 139 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c
index 4fbd2a7..3468db3 100644
--- a/drivers/net/wireless/wl12xx/rx.c
+++ b/drivers/net/wireless/wl12xx/rx.c
@@ -282,3 +282,108 @@ void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status)
 
 	wl12xx_rearm_rx_streaming(wl, active_hlids);
 }
+
+/*
+ * Global on / off for RX packet filtering in firmware
+ */
+int wl1271_rx_data_filtering_enable(struct wl1271 *wl, bool enable,
+				    enum rx_data_filter_action policy)
+{
+	int ret;
+
+	if (policy < FILTER_DROP || policy > FILTER_FW_HANDLE) {
+		wl1271_warning("filter policy value is not in valid range");
+		return -ERANGE;
+	}
+
+	if (enable < 0 || enable > 1) {
+		wl1271_warning("filter enable value is not in valid range");
+		return -ERANGE;
+	}
+
+	ret = wl1271_acx_toggle_rx_data_filter(wl, enable, policy);
+
+	if (ret)
+		return ret;
+
+	wl->rx_data_filter_enabled = enable;
+	wl->rx_data_filter_policy = policy;
+	return 0;
+}
+
+int wl1271_rx_data_filter_enable(struct wl1271 *wl,
+				 struct wl12xx_rx_data_filter *f, int nr,
+				 bool enable)
+{
+	int ret;
+
+	if (f->enabled == enable)
+		return 0;
+
+	ret = wl1271_acx_set_rx_data_filter(wl, enable, nr, f->action,
+					    f->pattern, f->len, f->offset);
+	if (ret) {
+		wl1271_error("Failed to enable/disable rx data filter");
+		return ret;
+	}
+
+	f->enabled = enable;
+	return 0;
+}
+
+int wl1271_rx_data_filter_set_action(struct wl12xx_rx_data_filter *f,
+				     enum rx_data_filter_action action)
+{
+	if (f->enabled)
+		return -EBUSY;
+
+	if (action < FILTER_DROP || action > FILTER_FW_HANDLE) {
+		wl1271_warning("filter action is not in valid range");
+		return -ERANGE;
+	}
+
+	f->action = action;
+	return 0;
+}
+
+int wl1271_rx_data_filter_set_offset(struct wl12xx_rx_data_filter *f,
+				     u16 offset)
+{
+	if (f->enabled)
+		return -EBUSY;
+
+	if (offset > USHRT_MAX-1) {
+		wl1271_warning("illegal value for filter offset");
+		return -ERANGE;
+	}
+
+	f->offset = offset;
+	return 0;
+}
+
+int wl1271_rx_data_filter_set_pattern(struct wl12xx_rx_data_filter *f, u8 *buf,
+				      u8 len)
+{
+	if (f->enabled)
+		return -EBUSY;
+	if (len > WL1271_RX_DATA_FILTER_MAX_PATTERN_SIZE)
+		return -E2BIG;
+
+	memcpy(f->pattern, buf, len);
+	f->len = len;
+	return 0;
+}
+
+/* Unset any active filters */
+void wl1271_rx_data_filters_clear_all(struct wl1271 *wl)
+{
+	int i;
+	struct wl12xx_rx_data_filter *f;
+
+	for (i = 0; i < WL1271_MAX_RX_DATA_FILTERS; i++) {
+		f  = &wl->rx_data_filters[i];
+		if (!f->enabled)
+			continue;
+		wl1271_rx_data_filter_enable(wl, f, i, 0);
+	}
+}
diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/rx.h
index 86ba6b1..019d6ce 100644
--- a/drivers/net/wireless/wl12xx/rx.h
+++ b/drivers/net/wireless/wl12xx/rx.h
@@ -128,5 +128,17 @@ struct wl1271_rx_descriptor {
 
 void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status);
 u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
-
+void wl1271_set_default_filters(struct wl1271 *wl);
+int wl1271_rx_data_filtering_enable(struct wl1271 *wl, bool enable,
+				    enum rx_data_filter_action policy);
+int wl1271_rx_data_filter_enable(struct wl1271 *wl,
+				 struct wl12xx_rx_data_filter *f, int nr,
+				 bool enable);
+int wl1271_rx_data_filter_set_action(struct wl12xx_rx_data_filter *f,
+				     enum rx_data_filter_action action);
+int wl1271_rx_data_filter_set_offset(struct wl12xx_rx_data_filter *f,
+				     u16 offset);
+int wl1271_rx_data_filter_set_pattern(struct wl12xx_rx_data_filter *f, u8 *buf,
+				      u8 len);
+void wl1271_rx_data_filters_clear_all(struct wl1271 *wl);
 #endif
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index d29de3f..66bda55 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -292,6 +292,14 @@ enum rx_data_filter_action {
 	FILTER_FW_HANDLE = 2
 };
 
+struct wl12xx_rx_data_filter {
+	bool enabled;
+	enum rx_data_filter_action action;
+	u8 len;
+	u16 offset;
+	u8 pattern[WL1271_MAX_RX_DATA_FILTER_SIZE];
+};
+
 struct wl1271 {
 	struct ieee80211_hw *hw;
 	bool mac80211_registered;
@@ -491,6 +499,19 @@ struct wl1271 {
 
 	/* last wlvif we transmitted from */
 	struct wl12xx_vif *last_wlvif;
+
+	/* AP-mode - work to add stations back on AP reconfig */
+	struct work_struct ap_start_work;
+
+	/* Global on/off switch for rx all rx filters */
+	bool rx_data_filter_enabled;
+
+	/* Default action for packets not matching any rule */
+	enum rx_data_filter_action rx_data_filter_policy;
+
+	/* RX Data filter rule descriptors */
+	struct wl12xx_rx_data_filter
+				rx_data_filters[WL1271_MAX_RX_DATA_FILTERS];
 };
 
 struct wl1271_station {
-- 
1.7.6.401.g6a319


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 7/7] wl12xx: Add support for WoWLAN packet pattern trigger
  2012-01-30 14:58 [PATCH 0/7] wl12xx: add some psm/suspend features Eliad Peller
                   ` (5 preceding siblings ...)
  2012-01-30 14:58 ` [PATCH 6/7] wl12xx: Add functions for managing rx data filters Eliad Peller
@ 2012-01-30 14:58 ` Eliad Peller
  2012-01-31  7:43 ` [PATCH 0/7] wl12xx: add some psm/suspend features Luciano Coelho
  7 siblings, 0 replies; 9+ messages in thread
From: Eliad Peller @ 2012-01-30 14:58 UTC (permalink / raw)
  To: Luciano Coelho; +Cc: linux-wireless

From: Pontus Fuchs <pontus.fuchs@gmail.com>

Add support for waking up if a pattern in a incoming packet is found.
Up to 4 patterns are supported.

Signed-off-by: Pontus Fuchs <pontus.fuchs@gmail.com>
Signed-off-by: Ido Reis <idor@ti.com>
Signed-off-by: Eliad Peller <eliad@wizery.com>
---
 drivers/net/wireless/wl12xx/main.c |  106 ++++++++++++++++++++++++++++++++++--
 1 files changed, 100 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index f2960df..34bb277 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1564,8 +1564,88 @@ static struct notifier_block wl1271_dev_notifier = {
 };
 
 #ifdef CONFIG_PM
+/* Count number of 1->0 or 0->1 transitions in a bit mask */
+static int wl1271_count_bit_flips(void *bitmap, int len)
+{
+	int i, flips = 0;
+	int b, bt;
+
+	if (!len)
+		return 0;
+
+	b = test_bit(0, bitmap);
+
+	for (i = 0; i < len; i++) {
+		bt = test_bit(i, bitmap);
+		if (bt != b)
+			flips++;
+		b = bt;
+	}
+
+	return flips;
+}
+
+static int wl1271_configure_wowlan(struct wl1271 *wl,
+				   struct cfg80211_wowlan *wow)
+{
+	int i, ret;
+
+	if (!wow) {
+		wl1271_rx_data_filtering_enable(wl, 0, FILTER_SIGNAL);
+		return 0;
+	}
+
+	WARN_ON(wow->n_patterns > WL1271_MAX_RX_DATA_FILTERS);
+	if (wow->any || !wow->n_patterns)
+		return 0;
+
+	wl1271_rx_data_filters_clear_all(wl);
+
+	/* Translate WoWLAN patterns into filters */
+	for (i = 0; i < wow->n_patterns; i++) {
+		struct cfg80211_wowlan_trig_pkt_pattern *p;
+		struct wl12xx_rx_data_filter *f;
+		int offset, len;
+
+		p = &wow->patterns[i];
+		f = &wl->rx_data_filters[i];
+
+		/* WoWLAN triggers as defined by nl80211 does not match wl12xx's
+		   capabilities 1:1 so it's possible to get a pattern that
+		   FW cannot handle */
+		if (wl1271_count_bit_flips(p->mask, p->pattern_len) > 1) {
+			wl1271_warning("WoWLAN pattern too advanced\n");
+			goto err;
+		}
+		offset = find_first_bit((const unsigned long *) p->mask,
+					p->pattern_len);
+		len = p->pattern_len - offset;
+
+		ret = wl1271_rx_data_filter_set_action(f, FILTER_SIGNAL);
+		if (ret)
+			goto err;
+		ret = wl1271_rx_data_filter_set_offset(f, offset);
+		if (ret)
+			goto err;
+		ret = wl1271_rx_data_filter_set_pattern(f, &p->pattern[offset],
+							len);
+		if (ret)
+			goto err;
+		ret = wl1271_rx_data_filter_enable(wl, f, i, 1);
+		if (ret)
+			goto err;
+	}
+	ret = wl1271_rx_data_filtering_enable(wl, 1, FILTER_DROP);
+	if (ret)
+		goto err;
+	return 0;
+err:
+	return ret;
+}
+
 static int wl1271_configure_suspend_sta(struct wl1271 *wl,
-					struct wl12xx_vif *wlvif)
+					struct wl12xx_vif *wlvif,
+					struct cfg80211_wowlan *wow)
 {
 	int ret = 0;
 
@@ -1578,6 +1658,10 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
 	if (ret < 0)
 		goto out_unlock;
 
+	ret = wl1271_configure_wowlan(wl, wow);
+	if (ret < 0)
+		wl1271_error("suspend: Could not configure WoWLAN: %d", ret);
+
 	ret = wl1271_acx_wake_up_conditions(wl, wlvif,
 				    wl->conf.conn.suspend_wake_up_event,
 				    wl->conf.conn.suspend_listen_interval);
@@ -1618,10 +1702,11 @@ out_unlock:
 }
 
 static int wl1271_configure_suspend(struct wl1271 *wl,
-				    struct wl12xx_vif *wlvif)
+				    struct wl12xx_vif *wlvif,
+					struct cfg80211_wowlan *wow)
 {
 	if (wlvif->bss_type == BSS_TYPE_STA_BSS)
-		return wl1271_configure_suspend_sta(wl, wlvif);
+		return wl1271_configure_suspend_sta(wl, wlvif, wow);
 	if (wlvif->bss_type == BSS_TYPE_AP_BSS)
 		return wl1271_configure_suspend_ap(wl, wlvif);
 	return 0;
@@ -1643,6 +1728,9 @@ static void wl1271_configure_resume(struct wl1271 *wl,
 		goto out;
 
 	if (is_sta) {
+		/* Remove WoWLAN filtering */
+		wl1271_configure_wowlan(wl, NULL);
+
 		ret = wl1271_acx_wake_up_conditions(wl, wlvif,
 				    wl->conf.conn.wake_up_event,
 				    wl->conf.conn.listen_interval);
@@ -1668,11 +1756,11 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
 	int ret;
 
 	wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
-	WARN_ON(!wow || !wow->any);
+	WARN_ON(!wow);
 
 	wl->wow_enabled = true;
 	wl12xx_for_each_wlvif(wl, wlvif) {
-		ret = wl1271_configure_suspend(wl, wlvif);
+		ret = wl1271_configure_suspend(wl, wlvif, wow);
 		if (ret < 0) {
 			wl1271_warning("couldn't prepare device to suspend");
 			return ret;
@@ -5172,8 +5260,14 @@ static int __devinit wl12xx_probe(struct platform_device *pdev)
 	if (!ret) {
 		wl->irq_wake_enabled = true;
 		device_init_wakeup(wl->dev, 1);
-		if (pdata->pwr_in_suspend)
+		if (pdata->pwr_in_suspend) {
 			hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
+			hw->wiphy->wowlan.n_patterns =
+				WL1271_MAX_RX_DATA_FILTERS;
+			hw->wiphy->wowlan.pattern_min_len = 1;
+			hw->wiphy->wowlan.pattern_max_len =
+				WL1271_RX_DATA_FILTER_MAX_PATTERN_SIZE;
+		}
 
 	}
 	disable_irq(wl->irq);
-- 
1.7.6.401.g6a319


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 0/7] wl12xx: add some psm/suspend features
  2012-01-30 14:58 [PATCH 0/7] wl12xx: add some psm/suspend features Eliad Peller
                   ` (6 preceding siblings ...)
  2012-01-30 14:58 ` [PATCH 7/7] wl12xx: Add support for WoWLAN packet pattern trigger Eliad Peller
@ 2012-01-31  7:43 ` Luciano Coelho
  7 siblings, 0 replies; 9+ messages in thread
From: Luciano Coelho @ 2012-01-31  7:43 UTC (permalink / raw)
  To: Eliad Peller; +Cc: linux-wireless

On Mon, 2012-01-30 at 16:58 +0200, Eliad Peller wrote: 
> Add some psm / suspend features:
> * Add the ability to force psm (by default, the fw uses dynamic ps)
> * Use differnet wake up conditions on suspend
> * Add pattern support to wowlan triggers
> 
> Eyal Shapira (4):
>   wl12xx: Set different wake up conditions in case of suspend
>   wl12xx: add suspend_listen_interval debugfs file
>   wl12xx: add forced_ps mode
>   wl12xx: add forced_ps debugfs file
> 
> Pontus Fuchs (3):
>   wl12xx: Add rx data filter commands
>   wl12xx: Add functions for managing rx data filters
>   wl12xx: Add support for WoWLAN packet pattern trigger

Skipping this patchset on Eliad's request.  He will send a v2 with some
squashes and new patches soon.

-- 
Cheers,
Luca.


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2012-01-31  7:43 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-01-30 14:58 [PATCH 0/7] wl12xx: add some psm/suspend features Eliad Peller
2012-01-30 14:58 ` [PATCH 1/7] wl12xx: Set different wake up conditions in case of suspend Eliad Peller
2012-01-30 14:58 ` [PATCH 2/7] wl12xx: add suspend_listen_interval debugfs file Eliad Peller
2012-01-30 14:58 ` [PATCH 3/7] wl12xx: add forced_ps mode Eliad Peller
2012-01-30 14:58 ` [PATCH 4/7] wl12xx: add forced_ps debugfs file Eliad Peller
2012-01-30 14:58 ` [PATCH 5/7] wl12xx: Add rx data filter commands Eliad Peller
2012-01-30 14:58 ` [PATCH 6/7] wl12xx: Add functions for managing rx data filters Eliad Peller
2012-01-30 14:58 ` [PATCH 7/7] wl12xx: Add support for WoWLAN packet pattern trigger Eliad Peller
2012-01-31  7:43 ` [PATCH 0/7] wl12xx: add some psm/suspend features Luciano Coelho

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).