2012-01-09 08:39:31

by Raja Mani

[permalink] [raw]
Subject: [PATCH 0/8] Allow the user to define suspend mode

From: Raja Mani <[email protected]>

This series of patch enables the user to specify the suspend mode
via module parameter (suspend_mode) while doing insmod of the driver.

To select Cut Power mode:
insmod ath6kl_sdio.ko suspend_mode = 1

To select Deep Sleep mode:
insmod ath6kl_sdio.ko suspend_mode = 2

To select WOW suspend mode:
insmod ath6kl_sdio.ko suspend_mode = 3

Existing module param 'suspend_cutpower' variable is renamed to
'suspend_mode' for this purspose.

Dynamic suspend mode selection logic based on the host SDIO
host controller is removed in ath6kl_sdio_suspend().
Now, ath6kl_sdio_suspend() will react based on the module
parameter 'suspend_mode'.

Additionally, If the user doesn't provide any WOW patterns,
the default WOW patterns will be configured while going to
WOW suspend mode.

Please provide your comments on this patch series.

Raja Mani (8):
ath6kl: Rename modparam variable suspend_cutpower to suspend_mode
ath6kl: Re-architect suspend mode handling in ath6kl_sdio_suspend()
ath6kl: Add a new func to configure default WOW patterns for AP mode
ath6kl: Add a new func to config default WOW patterns for non AP mode
ath6kl: Move WOW patterns config code to a separate function.
ath6kl: Configure WOW patterns while going to wow_suspend
ath6kl: Removed unused ATH6KL_CONF_SUSPEND_CUTPOWER macro
ath6kl: Return a proper error code when not in connected state

drivers/net/wireless/ath/ath6kl/cfg80211.c | 222 +++++++++++++++++++++++-----
drivers/net/wireless/ath/ath6kl/core.h | 2 +-
drivers/net/wireless/ath/ath6kl/init.c | 11 +-
drivers/net/wireless/ath/ath6kl/sdio.c | 105 ++++++++-----
4 files changed, 258 insertions(+), 82 deletions(-)



2012-01-09 19:21:54

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 1/8] ath6kl: Rename modparam variable suspend_cutpower to suspend_mode

On 01/09/2012 10:36 AM, [email protected] wrote:
> From: Raja Mani <[email protected]>
>
> suspend_cutpower was introduced to force cut power mode when
> system goes to suspend state. Now, generic module parameter
> is required to specify suspend mode including DEEP SLEEP and WOW
> while doing insmod. Renaming existing module parameter variable
> suspend_cutpower would be sufficient to meet this requirement.
>
> suspend_mode can take any one of three suspend state,
> 1) cut power
> 2) deep sleep
> 3) wow
>
> For invalid value other than above mode, cut power mode will be
> selected.
>
> To avoid externing mod parameter suspend_mode, new variable
> ar->suspend_mode is added to have copy of mod param variable
> and will be in sdio.c in the following patches.
>
> Signed-off-by: Raja Mani <[email protected]>

I think this patch needs to be folded with something else, maybe with
patch 2?

Kalle

2012-01-09 08:37:18

by Raja Mani

[permalink] [raw]
Subject: [PATCH 2/8] ath6kl: Re-architect suspend mode handling in ath6kl_sdio_suspend()

From: Raja Mani <[email protected]>

Dynamic suspend mode selection logic based on the host sdio
controller capability (MMC_PM_KEEP_POWER and MMC_PM_WAKE_SDIO_IRQ)
is completely removed.

Now, ath6kl_sdio_suspend() func will react based on the suspend mode
specified at the time of loading the driver (via module parameter
suspend_mode).

Additionally, new logic is added to have backup retry.
In other words, If the driver fails to enter into either
WOW (or) DEEP SLEEP mode, it would give a try in CUT POWER mode.

Signed-off-by: Raja Mani <[email protected]>
---
drivers/net/wireless/ath/ath6kl/sdio.c | 105 ++++++++++++++++++++------------
1 files changed, 66 insertions(+), 39 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
index 278a9f3..9eae745 100644
--- a/drivers/net/wireless/ath/ath6kl/sdio.c
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -787,66 +787,93 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
struct sdio_func *func = ar_sdio->func;
mmc_pm_flag_t flags;
- int ret;
+ unsigned char pmode_to_try;
+ int ret = -EINVAL;

flags = sdio_get_host_pm_caps(func);

ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sdio suspend pm_caps 0x%x\n", flags);

- if (!(flags & MMC_PM_KEEP_POWER) ||
- (ar->conf_flags & ATH6KL_CONF_SUSPEND_CUTPOWER)) {
- /* as host doesn't support keep power we need to cut power */
- return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER,
- NULL);
- }
-
- ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
- if (ret) {
- printk(KERN_ERR "ath6kl: set sdio pm flags failed: %d\n",
- ret);
- return ret;
- }
+ /* Schedule scan uses WOW internally */
+ pmode_to_try = (ar->state == ATH6KL_STATE_SCHED_SCAN) ?
+ WLAN_POWER_STATE_WOW : ar->suspend_mode;
+retry:
+ switch (pmode_to_try) {
+ case WLAN_POWER_STATE_CUT_PWR:
+ ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER,
+ NULL);
+ break;

- if (!(flags & MMC_PM_WAKE_SDIO_IRQ))
- goto deepsleep;
+ case WLAN_POWER_STATE_DEEP_SLEEP:
+ /* Try cut power if deep sleep suspend fails */
+ pmode_to_try = WLAN_POWER_STATE_CUT_PWR;

- /* sdio irq wakes up host */
+ if (!(flags & MMC_PM_KEEP_POWER))
+ goto retry;

- if (ar->state == ATH6KL_STATE_SCHED_SCAN) {
- ret = ath6kl_cfg80211_suspend(ar,
- ATH6KL_CFG_SUSPEND_SCHED_SCAN,
- NULL);
+ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
if (ret) {
- ath6kl_warn("Schedule scan suspend failed: %d", ret);
- return ret;
+ ath6kl_warn("failed to set sdio keep power flag: %d\n",
+ ret);
+ goto retry;
}

- ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
+ ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP,
+ NULL);
if (ret)
- ath6kl_warn("set sdio wake irq flag failed: %d\n", ret);
+ goto retry;

- return ret;
- }
+ break;

- if (wow) {
+ case WLAN_POWER_STATE_WOW:
+ /* Try cut power if wow suspend fails */
+ pmode_to_try = WLAN_POWER_STATE_CUT_PWR;
+
+ if (!(flags & MMC_PM_KEEP_POWER) ||
+ !(flags & MMC_PM_WAKE_SDIO_IRQ))
+ goto retry;
+
+ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+ if (ret) {
+ ath6kl_warn("failed to set sdio keep power flag: %d\n",
+ ret);
+ goto retry;
+ }
+
+ ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
+ if (ret) {
+ ath6kl_warn("failed to set sdio wake irq flag: %d\n",
+ ret);
+ goto retry;
+ }
/*
* The host sdio controller is capable of keep power and
- * sdio irq wake up at this point. It's fine to continue
- * wow suspend operation.
+ * sdio irq wake up at this point.
*/
- ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_WOW, wow);
- if (ret)
- return ret;
-
- ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
+ if (ar->state == ATH6KL_STATE_SCHED_SCAN) {
+ ath6kl_dbg(ATH6KL_DBG_SUSPEND,
+ "sched scan is in progress\n");
+ ret = ath6kl_cfg80211_suspend(ar,
+ ATH6KL_CFG_SUSPEND_SCHED_SCAN,
+ NULL);
+ if (ret)
+ ath6kl_warn("schedule scan suspend failed: %d",
+ ret);
+ } else
+ ret = ath6kl_cfg80211_suspend(ar,
+ ATH6KL_CFG_SUSPEND_WOW, wow);
if (ret)
- ath6kl_err("set sdio wake irq flag failed: %d\n", ret);
+ goto retry;
+ break;

- return ret;
+ default:
+ /* We shouldn't be here. */
+ WARN_ON(1);
+ break;
}

-deepsleep:
- return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP, NULL);
+ return ret;
+
}

static int ath6kl_sdio_resume(struct ath6kl *ar)
--
1.7.1


2012-01-09 08:37:27

by Raja Mani

[permalink] [raw]
Subject: [PATCH 3/8] ath6kl: Add a new func to configure default WOW patterns for AP mode

From: Raja Mani <[email protected]>

ath6kl_ap_add_default_wow_patterns() is added to configure the below
default patterns when the system enters into WOW suspend in AP mode.

* Unicast IP, EAPOL-like and ARP packet pattern
* ARP packet pattern
* mDNS/SSDP/LLMNR pattern
* DHCP broadcast pattern

This will be called from ath6kl_wow_suspend() func.

Signed-off-by: Raja Mani <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 77 ++++++++++++++++++++++++++++
1 files changed, 77 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 2a166cc..deba99c 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1727,6 +1727,83 @@ static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
return 0;
}

+static int ath6kl_ap_add_default_wow_patterns(struct ath6kl *ar,
+ struct ath6kl_vif *vif)
+{
+ static u8 unicst_pattern[] = { 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08 };
+ static u8 unicst_mask[] = { 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f };
+ u8 unicst_offset = 0;
+ static u8 arp_pattern[] = { 0x08, 0x06 };
+ static u8 arp_mask[] = { 0xff, 0xff };
+ u8 arp_offset = 20;
+ static u8 discvr_pattern[] = { 0xe0, 0x00, 0x00, 0xf8 };
+ static u8 discvr_mask[] = { 0xf0, 0x00, 0x00, 0xf8 };
+ u8 discvr_offset = 38;
+ static u8 dhcp_pattern[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x43 /* port 67 */ };
+ static u8 dhcp_mask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff /* port 67 */ };
+ u8 dhcp_offset = 0;
+ int ret;
+
+ /* Setup unicast IP, EAPOL-like and ARP pkt pattern */
+ ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
+ vif->fw_vif_idx, WOW_LIST_ID,
+ sizeof(unicst_pattern), unicst_offset,
+ unicst_pattern, unicst_mask);
+ if (ret) {
+ ath6kl_err("failed to add WOW unicast IP pattern\n");
+ return ret;
+ }
+
+ /* Setup all ARP pkt pattern */
+ ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
+ vif->fw_vif_idx, WOW_LIST_ID,
+ sizeof(arp_pattern), arp_offset,
+ arp_pattern, arp_mask);
+ if (ret) {
+ ath6kl_err("failed to add WOW ARP pattern\n");
+ return ret;
+ }
+
+ /*
+ * Setup multicast pattern for mDNS 224.0.0.251,
+ * SSDP 239.255.255.250 and LLMNR 224.0.0.252
+ */
+ ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
+ vif->fw_vif_idx, WOW_LIST_ID,
+ sizeof(discvr_pattern), discvr_offset,
+ discvr_pattern, discvr_mask);
+ if (ret) {
+ ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR pattern\n");
+ return ret;
+ }
+
+ /* Setup all DHCP broadcast pkt pattern */
+ ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
+ vif->fw_vif_idx, WOW_LIST_ID,
+ sizeof(dhcp_pattern), dhcp_offset,
+ dhcp_pattern, dhcp_mask);
+ if (ret) {
+ ath6kl_err("failed to add WOW DHCP broadcast pattern\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
{
struct in_device *in_dev;
--
1.7.1


2012-01-09 17:53:15

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 0/8] Allow the user to define suspend mode

On 01/09/2012 10:36 AM, [email protected] wrote:

> This series of patch enables the user to specify the suspend mode
> via module parameter (suspend_mode) while doing insmod of the driver.
>
> To select Cut Power mode:
> insmod ath6kl_sdio.ko suspend_mode = 1
>
> To select Deep Sleep mode:
> insmod ath6kl_sdio.ko suspend_mode = 2
>
> To select WOW suspend mode:
> insmod ath6kl_sdio.ko suspend_mode = 3
>
> Existing module param 'suspend_cutpower' variable is renamed to
> 'suspend_mode' for this purspose.

I'm not sure about this one. In a way this makes sense so that user can
force the particular suspend mode, but on the other hand I'm not sure if
this is a bit too much.

J&J (John and Johannes), what do you think? Is this acceptable?

Kalle

2012-01-09 08:37:10

by Raja Mani

[permalink] [raw]
Subject: [PATCH 1/8] ath6kl: Rename modparam variable suspend_cutpower to suspend_mode

From: Raja Mani <[email protected]>

suspend_cutpower was introduced to force cut power mode when
system goes to suspend state. Now, generic module parameter
is required to specify suspend mode including DEEP SLEEP and WOW
while doing insmod. Renaming existing module parameter variable
suspend_cutpower would be sufficient to meet this requirement.

suspend_mode can take any one of three suspend state,
1) cut power
2) deep sleep
3) wow

For invalid value other than above mode, cut power mode will be
selected.

To avoid externing mod parameter suspend_mode, new variable
ar->suspend_mode is added to have copy of mod param variable
and will be in sdio.c in the following patches.

Signed-off-by: Raja Mani <[email protected]>
---
drivers/net/wireless/ath/ath6kl/core.h | 1 +
drivers/net/wireless/ath/ath6kl/init.c | 11 +++++++----
2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index c095faf..be61fc3 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -590,6 +590,7 @@ struct ath6kl {
} hw;

u16 conf_flags;
+ u8 suspend_mode;
wait_queue_head_t event_wq;
struct ath6kl_mbox_info mbox_info;

diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index a481b6a..feff095 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -27,12 +27,12 @@

unsigned int debug_mask;
static unsigned int testmode;
-static bool suspend_cutpower;
+static unsigned char suspend_mode;
static unsigned int uart_debug;

module_param(debug_mask, uint, 0644);
module_param(testmode, uint, 0644);
-module_param(suspend_cutpower, bool, 0444);
+module_param(suspend_mode, byte, 0644);
module_param(uart_debug, uint, 0644);

static const struct ath6kl_hw hw_list[] = {
@@ -1676,8 +1676,11 @@ int ath6kl_core_init(struct ath6kl *ar)
ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER |
ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST;

- if (suspend_cutpower)
- ar->conf_flags |= ATH6KL_CONF_SUSPEND_CUTPOWER;
+ if (suspend_mode < WLAN_POWER_STATE_CUT_PWR ||
+ suspend_mode > WLAN_POWER_STATE_WOW)
+ ar->suspend_mode = WLAN_POWER_STATE_CUT_PWR;
+ else
+ ar->suspend_mode = suspend_mode;

ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
WIPHY_FLAG_HAVE_AP_SME |
--
1.7.1


2012-01-09 08:37:58

by Raja Mani

[permalink] [raw]
Subject: [PATCH 7/8] ath6kl: Removed unused ATH6KL_CONF_SUSPEND_CUTPOWER macro

From: Raja Mani <[email protected]>

Title says everything.

Signed-off-by: Raja Mani <[email protected]>
---
drivers/net/wireless/ath/ath6kl/core.h | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index be61fc3..b6b756b 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -188,7 +188,6 @@ struct ath6kl_fw_ie {
#define ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN BIT(1)
#define ATH6KL_CONF_ENABLE_11N BIT(2)
#define ATH6KL_CONF_ENABLE_TX_BURST BIT(3)
-#define ATH6KL_CONF_SUSPEND_CUTPOWER BIT(4)

enum wlan_low_pwr_state {
WLAN_POWER_STATE_ON,
--
1.7.1


2012-01-09 19:30:26

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 2/8] ath6kl: Re-architect suspend mode handling in ath6kl_sdio_suspend()

On 01/09/2012 10:36 AM, [email protected] wrote:
> From: Raja Mani <[email protected]>
>
> Dynamic suspend mode selection logic based on the host sdio
> controller capability (MMC_PM_KEEP_POWER and MMC_PM_WAKE_SDIO_IRQ)
> is completely removed.

What's the reason for this change? This loses all the automatic
detection we have. I would hope that we could keep the existing
detection capability and use the module parameter to override the
detection logic or something like that.

The driver should be as automatic as possible and the suspend_mode
module parameter should be used to override something.

> Additionally, new logic is added to have backup retry.
> In other words, If the driver fails to enter into either
> WOW (or) DEEP SLEEP mode, it would give a try in CUT POWER mode.

So the function now has a loop. To me that sounds very confusing and
error prone. What's the reason for this?

Kalle

2012-01-09 19:47:19

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 7/8] ath6kl: Removed unused ATH6KL_CONF_SUSPEND_CUTPOWER macro

On 01/09/2012 10:36 AM, [email protected] wrote:
> From: Raja Mani <[email protected]>
>
> Title says everything.

You can fold this with patch 1 where you remove the code using this define.

Kalle

2012-01-09 08:37:42

by Raja Mani

[permalink] [raw]
Subject: [PATCH 5/8] ath6kl: Move WOW patterns config code to a separate function.

From: Raja Mani <[email protected]>

Move the user provided WOW patterns configuration code
from ath6kl_wow_suspend() to a separate function called
ath6kl_add_usr_wow_patterns().

It gives more modularity to the existing code.

Signed-off-by: Raja Mani <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 108 +++++++++++++++------------
1 files changed, 60 insertions(+), 48 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 65e4609..347c5a4 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1727,6 +1727,64 @@ static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
return 0;
}

+static int ath6kl_add_usr_wow_patterns(struct ath6kl *ar,
+ struct ath6kl_vif *vif,
+ struct cfg80211_wowlan *wow,
+ u32 *filter)
+{
+ int ret, pos;
+ u8 mask[WOW_MASK_SIZE];
+ u16 i;
+
+ /* Configure the patterns that we received from the user. */
+ for (i = 0; i < wow->n_patterns; i++) {
+
+ /*
+ * Convert given nl80211 specific mask value to equivalent
+ * driver specific mask value and send it to the chip along
+ * with patterns. For example, If the mask value defined in
+ * struct cfg80211_wowlan is 0xA (equivalent binary is 1010),
+ * then equivalent driver specific mask value is
+ * "0xFF 0x00 0xFF 0x00".
+ */
+ memset(&mask, 0, sizeof(mask));
+ for (pos = 0; pos < wow->patterns[i].pattern_len; pos++) {
+ if (wow->patterns[i].mask[pos / 8] & (0x1 << (pos % 8)))
+ mask[pos] = 0xFF;
+ }
+ /*
+ * Note: Pattern's offset is not passed as part of wowlan
+ * parameter from CFG layer. So it's always passed as ZERO
+ * to the firmware. It means, given WOW patterns are always
+ * matched from the first byte of received pkt in the firmware.
+ */
+ ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
+ vif->fw_vif_idx, WOW_LIST_ID,
+ wow->patterns[i].pattern_len,
+ 0 /* pattern offset */,
+ wow->patterns[i].pattern, mask);
+ if (ret)
+ return ret;
+ }
+
+ if (wow->disconnect)
+ *filter |= WOW_FILTER_OPTION_NWK_DISASSOC;
+
+ if (wow->magic_pkt)
+ *filter |= WOW_FILTER_OPTION_MAGIC_PACKET;
+
+ if (wow->gtk_rekey_failure)
+ *filter |= WOW_FILTER_OPTION_GTK_ERROR;
+
+ if (wow->eap_identity_req)
+ *filter |= WOW_FILTER_OPTION_EAP_REQ;
+
+ if (wow->four_way_handshake)
+ *filter |= WOW_FILTER_OPTION_8021X_4WAYHS;
+
+ return 0;
+}
+
static int ath6kl_ap_add_default_wow_patterns(struct ath6kl *ar,
struct ath6kl_vif *vif)
{
@@ -1849,10 +1907,10 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
struct in_device *in_dev;
struct in_ifaddr *ifa;
struct ath6kl_vif *vif;
- int ret, pos, left;
+ int ret, left;
u32 filter = 0;
u16 i;
- u8 mask[WOW_MASK_SIZE], index = 0;
+ u8 index = 0;
__be32 ips[MAX_IP_ADDRS];

vif = ath6kl_vif_first(ar);
@@ -1869,37 +1927,6 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++)
ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx,
WOW_LIST_ID, i);
- /* Configure new WOW patterns */
- for (i = 0; i < wow->n_patterns; i++) {
-
- /*
- * Convert given nl80211 specific mask value to equivalent
- * driver specific mask value and send it to the chip along
- * with patterns. For example, If the mask value defined in
- * struct cfg80211_wowlan is 0xA (equivalent binary is 1010),
- * then equivalent driver specific mask value is
- * "0xFF 0x00 0xFF 0x00".
- */
- memset(&mask, 0, sizeof(mask));
- for (pos = 0; pos < wow->patterns[i].pattern_len; pos++) {
- if (wow->patterns[i].mask[pos / 8] & (0x1 << (pos % 8)))
- mask[pos] = 0xFF;
- }
- /*
- * Note: Pattern's offset is not passed as part of wowlan
- * parameter from CFG layer. So it's always passed as ZERO
- * to the firmware. It means, given WOW patterns are always
- * matched from the first byte of received pkt in the firmware.
- */
- ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
- vif->fw_vif_idx, WOW_LIST_ID,
- wow->patterns[i].pattern_len,
- 0 /* pattern offset */,
- wow->patterns[i].pattern, mask);
- if (ret)
- return ret;
- }
-
/* Setup own IP addr for ARP agent. */
in_dev = __in_dev_get_rtnl(vif->ndev);
if (!in_dev)
@@ -1927,21 +1954,6 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
}

skip_arp:
- if (wow->disconnect)
- filter |= WOW_FILTER_OPTION_NWK_DISASSOC;
-
- if (wow->magic_pkt)
- filter |= WOW_FILTER_OPTION_MAGIC_PACKET;
-
- if (wow->gtk_rekey_failure)
- filter |= WOW_FILTER_OPTION_GTK_ERROR;
-
- if (wow->eap_identity_req)
- filter |= WOW_FILTER_OPTION_EAP_REQ;
-
- if (wow->four_way_handshake)
- filter |= WOW_FILTER_OPTION_8021X_4WAYHS;
-
ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_WOW_MODE_ENABLE,
filter,
--
1.7.1


2012-01-09 08:38:07

by Raja Mani

[permalink] [raw]
Subject: [PATCH 8/8] ath6kl: Return a proper error code when not in connected state

From: Raja Mani <[email protected]>

Error code ENOTCONN is more suitable than EINVAL to report
when the driver is not in connected state in ath6kl_wow_suspend().

Signed-off-by: Raja Mani <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index a8880af..a5929b3 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1921,7 +1921,7 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
return -EIO;

if (!test_bit(CONNECTED, &vif->flags))
- return -EINVAL;
+ return -ENOTCONN;

if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST))
return -EINVAL;
--
1.7.1


2012-01-09 08:37:50

by Raja Mani

[permalink] [raw]
Subject: [PATCH 6/8] ath6kl: Configure WOW patterns while going to wow_suspend

From: Raja Mani <[email protected]>

First preference is given to the user configured WOW patterns.
If the user doesn't configure any patterns (for ex, via iw command),
the default patterns will be configured while going to WOW suspend.

Make use of ath6kl_ap_add_default_wow_patterns() and
ath6kl_non_ap_add_default_wow_patterns() func to configure
default WOW patterns.

Additionally, new conditional check is added to make sure user
configured pattern count is within the limit (WOW_MAX_FILTERS_PER_LIST).

Signed-off-by: Raja Mani <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 17 +++++++++++++++++
1 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 347c5a4..a8880af 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1923,10 +1923,27 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
if (!test_bit(CONNECTED, &vif->flags))
return -EINVAL;

+ if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST))
+ return -EINVAL;
+
/* Clear existing WOW patterns */
for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++)
ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx,
WOW_LIST_ID, i);
+ /*
+ * Skip the default WOW pattern configuration if the driver
+ * receives any WOW patterns from the user.
+ */
+ if (wow)
+ ret = ath6kl_add_usr_wow_patterns(ar, vif, wow, &filter);
+ else if (vif->nw_type == AP_NETWORK)
+ ret = ath6kl_ap_add_default_wow_patterns(ar, vif);
+ else
+ ret = ath6kl_non_ap_add_default_wow_patterns(ar, vif);
+
+ if (ret)
+ return ret;
+
/* Setup own IP addr for ARP agent. */
in_dev = __in_dev_get_rtnl(vif->ndev);
if (!in_dev)
--
1.7.1


2012-01-09 08:37:34

by Raja Mani

[permalink] [raw]
Subject: [PATCH 4/8] ath6kl: Add a new func to config default WOW patterns for non AP mode

From: Raja Mani <[email protected]>

ath6kl_non_ap_add_default_wow_patterns() is added to configure the below
default patterns when the system enters into WOW suspend in non AP mode.

* Unicast packet pattern
* mDNS/SSDP/LLMNR pattern

This func will be called from ath6kl_wow_suspend().

Signed-off-by: Raja Mani <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 40 ++++++++++++++++++++++++++++
1 files changed, 40 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index deba99c..65e4609 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1804,6 +1804,46 @@ static int ath6kl_ap_add_default_wow_patterns(struct ath6kl *ar,
return 0;
}

+static int ath6kl_non_ap_add_default_wow_patterns(struct ath6kl *ar,
+ struct ath6kl_vif *vif)
+{
+ struct net_device *ndev = vif->ndev;
+ static u8 discvr_pattern[] = { 0xe0, 0x00, 0x00, 0xf8 };
+ static u8 discvr_mask[] = { 0xf0, 0x00, 0x00, 0xf8 };
+ u8 discvr_offset = 38;
+ u8 mac_mask[ETH_ALEN];
+ int ret;
+
+ /* Setup unicast pkt pattern */
+ memset(mac_mask, 0xff, ETH_ALEN);
+ ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
+ vif->fw_vif_idx, WOW_LIST_ID,
+ ETH_ALEN, 0, ndev->dev_addr,
+ mac_mask);
+ if (ret) {
+ ath6kl_err("failed to add WOW unicast pattern\n");
+ return ret;
+ }
+
+ /*
+ * Setup multicast pattern for mDNS 224.0.0.251,
+ * SSDP 239.255.255.250 and LLMNR 224.0.0.252
+ */
+ if ((ndev->flags & IFF_ALLMULTI) ||
+ (ndev->flags & IFF_MULTICAST && netdev_mc_count(ndev) > 0)) {
+ ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
+ vif->fw_vif_idx, WOW_LIST_ID,
+ sizeof(discvr_pattern), discvr_offset,
+ discvr_pattern, discvr_mask);
+ if (ret) {
+ ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR pattern\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
{
struct in_device *in_dev;
--
1.7.1