2011-11-07 05:27:53

by Raja Mani

[permalink] [raw]
Subject: [PATCH v2 00/11] ath6kl: Add WOW support

Version 2 patch set is tested on Qualcomm MSM board and
takes care most of the review comments given by Kalle.

V2 changes:
* WOW mode selection logic is moved to HIF layer, earlier it was implemented in CFG i/f layer.
* Individual parameters are used in the functions instead of struct as a parameter.
* Unused one extra byte is removed in struct wmi_add_wow_pattern_cmd.
* Used ar->state for WOW state handling and separate WOW state handling is removed.
* host sdio irq wake up capability is checked before entering into WOW suspend mode.
* Empty commit logs are avoided. :-)
* No error is reported from Sparse.
* Rebased to multi vif implementation.

and other minor corrections.

Using these patch set, WOW patterns can be controlled and configured via iw command.
Please refer iw help menu for more details.

Limitations:
* Optional bytes can't be specified while configuring WOW patterns from iw command.
This is due to the limitation in the firmware.

* Pattern byte matching will always happen from the first byte of received packet.
This is the limitation in the recent "iw" command (It doesn't take the pattern
offset where to start pattern matching in the received packets as of now).

Raja Mani (11):
ath6kl: Add wmi functions to add/delete WOW patterns
ath6kl: Add wmi functions to configure WOW mode and host sleep mode
ath6kl: Add WOW suspend/resume implementation
ath6kl: Include new parameter in suspend path for wowlan
ath6kl: Add new state for WOW mode
ath6kl: Move ath6kl_cfg80211_stop() call specific to deep sleep and
cut pwr
ath6kl: Invoke WOW suspend/resume calls during PM operation
ath6kl: Perform WOW resume in RX path in case of SDIO IRQ wake up
ath6kl: Expose ath6kl's WOW capabilities to CFG layer
ath6kl: Remove WARN_ON msg in Suspend path
ath6kl: Remove few unused WMI stuff

drivers/net/wireless/ath/ath6kl/cfg80211.c | 188 +++++++++++++++++++++++++++-
drivers/net/wireless/ath/ath6kl/cfg80211.h | 5 +-
drivers/net/wireless/ath/ath6kl/core.h | 5 +
drivers/net/wireless/ath/ath6kl/hif-ops.h | 5 +-
drivers/net/wireless/ath/ath6kl/hif.h | 2 +-
drivers/net/wireless/ath/ath6kl/sdio.c | 29 ++++-
drivers/net/wireless/ath/ath6kl/txrx.c | 2 +
drivers/net/wireless/ath/ath6kl/wmi.c | 164 +++++++++++++++++++++++-
drivers/net/wireless/ath/ath6kl/wmi.h | 64 ++++++++--
9 files changed, 436 insertions(+), 28 deletions(-)



2011-11-07 05:27:16

by Raja Mani

[permalink] [raw]
Subject: [PATCH v2 04/11] ath6kl: Include new parameter in suspend path for wowlan

cfg80211 layer provides user defined wow parameters like Filter options, Patterns,
Pattern's mask, etc via "struct cfg80211_wowlan *wow" to suspend function.

Right now, this wowlan parameter is not handled in __ath6kl_cfg80211_suspend func.
This parameter has to be passed to HIF layer, So that it can be passed back to
ath6kl's cfg interface layer when WOW mode is selected.

In case of deep sleep and cut power mode, it's not handled.

Signed-off-by: Raja Mani <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 5 +++--
drivers/net/wireless/ath/ath6kl/cfg80211.h | 4 +++-
drivers/net/wireless/ath/ath6kl/hif-ops.h | 5 +++--
drivers/net/wireless/ath/ath6kl/hif.h | 2 +-
drivers/net/wireless/ath/ath6kl/sdio.c | 7 ++++---
5 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 68cfb81..1dc7374 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1754,7 +1754,8 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
}

int ath6kl_cfg80211_suspend(struct ath6kl *ar,
- enum ath6kl_cfg_suspend_mode mode)
+ enum ath6kl_cfg_suspend_mode mode,
+ struct cfg80211_wowlan *wow)
{
int ret;

@@ -1844,7 +1845,7 @@ static int __ath6kl_cfg80211_suspend(struct wiphy *wiphy,
{
struct ath6kl *ar = wiphy_priv(wiphy);

- return ath6kl_hif_suspend(ar);
+ return ath6kl_hif_suspend(ar, wow);
}

static int __ath6kl_cfg80211_resume(struct wiphy *wiphy)
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h
index 72eadf8..b4781e5 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.h
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h
@@ -46,7 +46,9 @@ void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid,
bool ismcast);

int ath6kl_cfg80211_suspend(struct ath6kl *ar,
- enum ath6kl_cfg_suspend_mode mode);
+ enum ath6kl_cfg_suspend_mode mode,
+ struct cfg80211_wowlan *wow);
+
int ath6kl_cfg80211_resume(struct ath6kl *ar);

void ath6kl_cfg80211_stop(struct ath6kl *ar);
diff --git a/drivers/net/wireless/ath/ath6kl/hif-ops.h b/drivers/net/wireless/ath/ath6kl/hif-ops.h
index 50fd3e9..eed2287 100644
--- a/drivers/net/wireless/ath/ath6kl/hif-ops.h
+++ b/drivers/net/wireless/ath/ath6kl/hif-ops.h
@@ -83,11 +83,12 @@ static inline void ath6kl_hif_cleanup_scatter(struct ath6kl *ar)
return ar->hif_ops->cleanup_scatter(ar);
}

-static inline int ath6kl_hif_suspend(struct ath6kl *ar)
+static inline int ath6kl_hif_suspend(struct ath6kl *ar,
+ struct cfg80211_wowlan *wow)
{
ath6kl_dbg(ATH6KL_DBG_HIF, "hif suspend\n");

- return ar->hif_ops->suspend(ar);
+ return ar->hif_ops->suspend(ar, wow);
}

static inline int ath6kl_hif_resume(struct ath6kl *ar)
diff --git a/drivers/net/wireless/ath/ath6kl/hif.h b/drivers/net/wireless/ath/ath6kl/hif.h
index 814386d..f2dc3bc 100644
--- a/drivers/net/wireless/ath/ath6kl/hif.h
+++ b/drivers/net/wireless/ath/ath6kl/hif.h
@@ -242,7 +242,7 @@ struct ath6kl_hif_ops {
int (*scat_req_rw) (struct ath6kl *ar,
struct hif_scatter_req *scat_req);
void (*cleanup_scatter)(struct ath6kl *ar);
- int (*suspend)(struct ath6kl *ar);
+ int (*suspend)(struct ath6kl *ar, struct cfg80211_wowlan *wow);
int (*resume)(struct ath6kl *ar);
int (*power_on)(struct ath6kl *ar);
int (*power_off)(struct ath6kl *ar);
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
index a026dae..b576b76 100644
--- a/drivers/net/wireless/ath/ath6kl/sdio.c
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -773,7 +773,7 @@ out:
return ret;
}

-static int ath6kl_sdio_suspend(struct ath6kl *ar)
+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;
@@ -787,7 +787,8 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar)
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);
+ return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER,
+ NULL);
}

ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
@@ -797,7 +798,7 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar)
return ret;
}

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

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


2011-11-07 05:28:13

by Raja Mani

[permalink] [raw]
Subject: [PATCH v2 09/11] ath6kl: Expose ath6kl's WOW capabilities to CFG layer

Set the list of ath6kl's WOW trigger options in wiphy->wowlan.flags
variable during wiphy registration. So that, those options can be
configured via iw.

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

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index f524276..603dbda 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -2509,6 +2509,16 @@ int ath6kl_register_ieee80211_hw(struct ath6kl *ar)
wiphy->cipher_suites = cipher_suites;
wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);

+ wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
+ WIPHY_WOWLAN_DISCONNECT |
+ WIPHY_WOWLAN_GTK_REKEY_FAILURE |
+ WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
+ WIPHY_WOWLAN_EAP_IDENTITY_REQ |
+ WIPHY_WOWLAN_4WAY_HANDSHAKE;
+ wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST;
+ wiphy->wowlan.pattern_min_len = 1;
+ wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
+
ret = wiphy_register(wiphy);
if (ret < 0) {
ath6kl_err("couldn't register wiphy device\n");
--
1.7.1


2011-11-07 05:28:27

by Raja Mani

[permalink] [raw]
Subject: [PATCH v2 02/11] ath6kl: Add wmi functions to configure WOW mode and host sleep mode

It will be used in WOW suspend/resume functions to
active/deactivate WOW suspend mode.

Signed-off-by: Raja Mani <[email protected]>
---
drivers/net/wireless/ath/ath6kl/wmi.c | 108 +++++++++++++++++++++++++++++++++
drivers/net/wireless/ath/ath6kl/wmi.h | 41 ++++++++++++
2 files changed, 149 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 925ef4c..3da1fb5 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -2412,6 +2412,114 @@ int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd)
return ret;
}

+static void ath6kl_wmi_relinquish_implicit_pstream_credits(struct wmi *wmi)
+{
+ u16 active_tsids;
+ u8 stream_exist;
+ int i;
+
+ /*
+ * Relinquish credits from all implicitly created pstreams
+ * since when we go to sleep. If user created explicit
+ * thinstreams exists with in a fatpipe leave them intact
+ * for the user to delete.
+ */
+ spin_lock_bh(&wmi->lock);
+ stream_exist = wmi->fat_pipe_exist;
+ spin_unlock_bh(&wmi->lock);
+
+ for (i = 0; i < WMM_NUM_AC; i++) {
+ if (stream_exist & (1 << i)) {
+
+ /*
+ * FIXME: Is this lock & unlock inside
+ * for loop correct? may need rework.
+ */
+ spin_lock_bh(&wmi->lock);
+ active_tsids = wmi->stream_exist_for_ac[i];
+ spin_unlock_bh(&wmi->lock);
+
+ /*
+ * If there are no user created thin streams
+ * delete the fatpipe
+ */
+ if (!active_tsids) {
+ stream_exist &= ~(1 << i);
+ /*
+ * Indicate inactivity to driver layer for
+ * this fatpipe (pstream)
+ */
+ ath6kl_indicate_tx_activity(wmi->parent_dev,
+ i, false);
+ }
+ }
+ }
+
+ /* FIXME: Can we do this assignment without locking ? */
+ spin_lock_bh(&wmi->lock);
+ wmi->fat_pipe_exist = stream_exist;
+ spin_unlock_bh(&wmi->lock);
+}
+
+int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx,
+ enum ath6kl_host_mode host_mode)
+{
+ struct sk_buff *skb;
+ struct wmi_set_host_sleep_mode_cmd *cmd;
+ int ret;
+
+ if ((host_mode != ATH6KL_HOST_MODE_ASLEEP) &&
+ (host_mode != ATH6KL_HOST_MODE_AWAKE)) {
+ ath6kl_err("invalid host sleep mode: %d\n", host_mode);
+ return -EINVAL;
+ }
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_set_host_sleep_mode_cmd *) skb->data;
+
+ if (host_mode == ATH6KL_HOST_MODE_ASLEEP) {
+ ath6kl_wmi_relinquish_implicit_pstream_credits(wmi);
+ cmd->asleep = cpu_to_le32(1);
+ } else
+ cmd->awake = cpu_to_le32(1);
+
+ ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+ WMI_SET_HOST_SLEEP_MODE_CMDID,
+ NO_SYNC_WMIFLAG);
+ return ret;
+}
+
+int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx,
+ enum ath6kl_wow_mode wow_mode,
+ u32 filter, u16 host_req_delay)
+{
+ struct sk_buff *skb;
+ struct wmi_set_wow_mode_cmd *cmd;
+ int ret;
+
+ if ((wow_mode != ATH6KL_WOW_MODE_ENABLE) &&
+ wow_mode != ATH6KL_WOW_MODE_DISABLE) {
+ ath6kl_err("invalid wow mode: %d\n", wow_mode);
+ return -EINVAL;
+ }
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_set_wow_mode_cmd *) skb->data;
+ cmd->enable_wow = cpu_to_le32(wow_mode);
+ cmd->filter = cpu_to_le32(filter);
+ cmd->host_req_delay = cpu_to_le16(host_req_delay);
+
+ ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_WOW_MODE_CMDID,
+ NO_SYNC_WMIFLAG);
+ return ret;
+}
+
int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
u8 list_id, u8 filter_size,
u8 filter_offset, u8 *filter, u8 *mask)
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index df42e4b..a65eee2 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -1818,6 +1818,42 @@ struct wmi_set_ip_cmd {
__le32 ips[MAX_IP_ADDRS];
} __packed;

+enum ath6kl_wow_filters {
+ WOW_FILTER_SSID = BIT(0),
+ WOW_FILTER_OPTION_MAGIC_PACKET = BIT(2),
+ WOW_FILTER_OPTION_EAP_REQ = BIT(3),
+ WOW_FILTER_OPTION_PATTERNS = BIT(4),
+ WOW_FILTER_OPTION_OFFLOAD_ARP = BIT(5),
+ WOW_FILTER_OPTION_OFFLOAD_NS = BIT(6),
+ WOW_FILTER_OPTION_OFFLOAD_GTK = BIT(7),
+ WOW_FILTER_OPTION_8021X_4WAYHS = BIT(8),
+ WOW_FILTER_OPTION_NLO_DISCVRY = BIT(9),
+ WOW_FILTER_OPTION_NWK_DISASSOC = BIT(10),
+ WOW_FILTER_OPTION_GTK_ERROR = BIT(11),
+ WOW_FILTER_OPTION_TEST_MODE = BIT(15),
+};
+
+enum ath6kl_host_mode {
+ ATH6KL_HOST_MODE_AWAKE,
+ ATH6KL_HOST_MODE_ASLEEP,
+};
+
+struct wmi_set_host_sleep_mode_cmd {
+ __le32 awake;
+ __le32 asleep;
+} __packed;
+
+enum ath6kl_wow_mode {
+ ATH6KL_WOW_MODE_DISABLE,
+ ATH6KL_WOW_MODE_ENABLE,
+};
+
+struct wmi_set_wow_mode_cmd {
+ __le32 enable_wow;
+ __le32 filter;
+ __le16 host_req_delay;
+} __packed;
+
struct wmi_add_wow_pattern_cmd {
u8 filter_list_id;
u8 filter_size;
@@ -2285,6 +2321,11 @@ int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len);
s32 ath6kl_wmi_get_rate(s8 rate_index);

int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd);
+int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx,
+ enum ath6kl_host_mode host_mode);
+int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx,
+ enum ath6kl_wow_mode wow_mode,
+ u32 filter, u16 host_req_delay);
int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
u8 list_id, u8 filter_size,
u8 filter_offset, u8 *filter, u8 *mask);
--
1.7.1


2011-11-07 05:26:53

by Raja Mani

[permalink] [raw]
Subject: [PATCH v2 01/11] ath6kl: Add wmi functions to add/delete WOW patterns

These commands will be used in WOW suspend/resume functions
to configure WOW parameters like patterns to be matched
and it's mask value, etc.

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

diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 612326d..925ef4c 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -2412,6 +2412,62 @@ int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd)
return ret;
}

+int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
+ u8 list_id, u8 filter_size,
+ u8 filter_offset, u8 *filter, u8 *mask)
+{
+ struct sk_buff *skb;
+ struct wmi_add_wow_pattern_cmd *cmd;
+ u16 size;
+ u8 *filter_mask;
+ int ret;
+
+ /*
+ * Allocate additional memory in the buffer to hold
+ * filter and mask value, which is twice of filter_size.
+ */
+ size = sizeof(*cmd) + (2 * filter_size);
+
+ skb = ath6kl_wmi_get_new_buf(size);
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_add_wow_pattern_cmd *) skb->data;
+ cmd->filter_list_id = list_id;
+ cmd->filter_size = filter_size;
+ cmd->filter_offset = filter_offset;
+
+ memcpy(cmd->filter, filter, filter_size);
+
+ filter_mask = (u8 *) (cmd->filter + filter_size);
+ memcpy(filter_mask, mask, filter_size);
+
+ ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_ADD_WOW_PATTERN_CMDID,
+ NO_SYNC_WMIFLAG);
+
+ return ret;
+}
+
+int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
+ u16 list_id, u16 filter_id)
+{
+ struct sk_buff *skb;
+ struct wmi_del_wow_pattern_cmd *cmd;
+ int ret;
+
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_del_wow_pattern_cmd *) skb->data;
+ cmd->filter_list_id = cpu_to_le16(list_id);
+ cmd->filter_id = cpu_to_le16(filter_id);
+
+ ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_DEL_WOW_PATTERN_CMDID,
+ NO_SYNC_WMIFLAG);
+ return ret;
+}
+
static int ath6kl_wmi_get_wow_list_event_rx(struct wmi *wmi, u8 * datap,
int len)
{
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index 1d458f0..df42e4b 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -1818,6 +1818,18 @@ struct wmi_set_ip_cmd {
__le32 ips[MAX_IP_ADDRS];
} __packed;

+struct wmi_add_wow_pattern_cmd {
+ u8 filter_list_id;
+ u8 filter_size;
+ u8 filter_offset;
+ u8 filter[0];
+} __packed;
+
+struct wmi_del_wow_pattern_cmd {
+ __le16 filter_list_id;
+ __le16 filter_id;
+} __packed;
+
/* WMI_GET_WOW_LIST_CMD reply */
struct wmi_get_wow_list_reply {
/* number of patterns in reply */
@@ -2273,6 +2285,11 @@ int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len);
s32 ath6kl_wmi_get_rate(s8 rate_index);

int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd);
+int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
+ u8 list_id, u8 filter_size,
+ u8 filter_offset, u8 *filter, u8 *mask);
+int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
+ u16 list_id, u16 filter_id);
int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi);
int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid);
int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode);
--
1.7.1


2011-11-07 05:30:27

by Raja Mani

[permalink] [raw]
Subject: [PATCH v2 10/11] ath6kl: Remove WARN_ON msg in Suspend path

In the current code, WOW resume is executed first from RX path
and ar->state is moved to ATH6KL_STATE_ON. When platform calls
ath6kl_sdio_resume() in CFG resume context, that time ar->state
could have moved to ON state. Printing WARN_ON(1) is void in
this context. Hence removing this.

Once WOW resume is removed from RX path, This WARN_ON msg can be
reverted.

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

diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
index 0586b3b..beb5f9b 100644
--- a/drivers/net/wireless/ath/ath6kl/sdio.c
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -831,8 +831,6 @@ static int ath6kl_sdio_resume(struct ath6kl *ar)
break;

case ATH6KL_STATE_ON:
- /* we shouldn't be on this state during resume */
- WARN_ON(1);
break;

case ATH6KL_STATE_DEEPSLEEP:
--
1.7.1


2011-11-07 21:05:05

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH v2 10/11] ath6kl: Remove WARN_ON msg in Suspend path

On 11/07/2011 07:25 AM, Raja Mani wrote:
> In the current code, WOW resume is executed first from RX path
> and ar->state is moved to ATH6KL_STATE_ON. When platform calls
> ath6kl_sdio_resume() in CFG resume context, that time ar->state
> could have moved to ON state. Printing WARN_ON(1) is void in
> this context. Hence removing this.
>
> Once WOW resume is removed from RX path, This WARN_ON msg can be
> reverted.

I changed places with this and patch 9. This is to avoid useless
warnings during bisect.

Kalle

2011-11-07 05:28:07

by Raja Mani

[permalink] [raw]
Subject: [PATCH v2 11/11] ath6kl: Remove few unused WMI stuff

* Removed unused WOW_MAX_FILTER_LISTS macro.

* Removed empty ath6kl_wmi_get_wow_list_event_rx() function.
List of configured WOW patterns are maintained in CFG layer
itself. No need to have this function in ath6kl to get
configured WOW pattern list. It can added later if we need
it for debugging.

Signed-off-by: Raja Mani <[email protected]>
---
drivers/net/wireless/ath/ath6kl/wmi.c | 10 ----------
drivers/net/wireless/ath/ath6kl/wmi.h | 14 --------------
2 files changed, 0 insertions(+), 24 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 3da1fb5..922344d 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -2576,15 +2576,6 @@ int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
return ret;
}

-static int ath6kl_wmi_get_wow_list_event_rx(struct wmi *wmi, u8 * datap,
- int len)
-{
- if (len < sizeof(struct wmi_get_wow_list_reply))
- return -EINVAL;
-
- return 0;
-}
-
static int ath6kl_wmi_cmd_send_xtnd(struct wmi *wmi, struct sk_buff *skb,
enum wmix_command_id cmd_id,
enum wmi_sync_flag sync_flag)
@@ -3295,7 +3286,6 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
break;
case WMI_GET_WOW_LIST_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_WOW_LIST_EVENTID\n");
- ret = ath6kl_wmi_get_wow_list_event_rx(wmi, datap, len);
break;
case WMI_GET_PMKID_LIST_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_PMKID_LIST_EVENTID\n");
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index a65eee2..76342d5 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -1795,7 +1795,6 @@ struct wmi_set_appie_cmd {
#define WSC_REG_ACTIVE 1
#define WSC_REG_INACTIVE 0

-#define WOW_MAX_FILTER_LISTS 1
#define WOW_MAX_FILTERS_PER_LIST 4
#define WOW_PATTERN_SIZE 64
#define WOW_MASK_SIZE 64
@@ -1866,19 +1865,6 @@ struct wmi_del_wow_pattern_cmd {
__le16 filter_id;
} __packed;

-/* WMI_GET_WOW_LIST_CMD reply */
-struct wmi_get_wow_list_reply {
- /* number of patterns in reply */
- u8 num_filters;
-
- /* this is filter # x of total num_filters */
- u8 this_filter_num;
-
- u8 wow_mode;
- u8 host_mode;
- struct wow_filter wow_filters[1];
-} __packed;
-
/* WMI_SET_AKMP_PARAMS_CMD */

struct wmi_pmkid {
--
1.7.1


2011-11-07 05:27:45

by Raja Mani

[permalink] [raw]
Subject: [PATCH v2 08/11] ath6kl: Perform WOW resume in RX path in case of SDIO IRQ wake up

The target triggers sdio data line to wake up the host when
WOW pattern matches. This causes sdio irq handler is being
executed in the host side which internally hits ath6kl's RX path.

WOW resume should happen before start processing any data from
the target. So it's required to perform WOW resume in RX path.

This area needs bit rework to avoid WOW resume in RX path,
As of now it's fine to have this model, rework will be done later.

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

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 42dcbea..f524276 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1886,6 +1886,34 @@ static int __ath6kl_cfg80211_resume(struct wiphy *wiphy)

return ath6kl_hif_resume(ar);
}
+
+/*
+ * FIXME: WOW suspend mode is selected if the host sdio controller supports
+ * both sdio irq wake up and keep power. The target pulls sdio data line to
+ * wake up the host when WOW pattern matches. This causes sdio irq handler
+ * is being called in the host side which internally hits ath6kl's RX path.
+ *
+ * Since sdio interrupt is not disabled, RX path executes even before
+ * the host executes the actual resume operation from PM module.
+ *
+ * In the current scenario, WOW resume should happen before start processing
+ * any data from the target. So It's required to perform WOW resume in RX path.
+ * Ideally we should perform WOW resume only in the actual platform
+ * resume path. This area needs bit rework to avoid WOW resume in RX path.
+ *
+ * ath6kl_check_wow_status() is called from ath6kl_rx().
+ */
+void ath6kl_check_wow_status(struct ath6kl *ar)
+{
+ if (ar->state == ATH6KL_STATE_WOW)
+ ath6kl_cfg80211_resume(ar);
+}
+
+#else
+
+void ath6kl_check_wow_status(struct ath6kl *ar)
+{
+}
#endif

static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index 9e8b8e3..e7e095e 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -678,5 +678,6 @@ struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar);
void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready);
int ath6kl_init_hw_start(struct ath6kl *ar);
int ath6kl_init_hw_stop(struct ath6kl *ar);
+void ath6kl_check_wow_status(struct ath6kl *ar);

#endif /* CORE_H */
diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c
index 06e4912..6f1de44 100644
--- a/drivers/net/wireless/ath/ath6kl/txrx.c
+++ b/drivers/net/wireless/ath/ath6kl/txrx.c
@@ -1134,6 +1134,8 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
return;
}

+ ath6kl_check_wow_status(ar);
+
if (ept == ar->ctrl_ep) {
ath6kl_wmi_control_rx(ar->wmi, skb);
return;
--
1.7.1


2011-11-07 21:03:16

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH v2 00/11] ath6kl: Add WOW support

On 11/07/2011 07:25 AM, Raja Mani wrote:
> Version 2 patch set is tested on Qualcomm MSM board and
> takes care most of the review comments given by Kalle.
>
> V2 changes:
> * WOW mode selection logic is moved to HIF layer, earlier it was implemented in CFG i/f layer.
> * Individual parameters are used in the functions instead of struct as a parameter.
> * Unused one extra byte is removed in struct wmi_add_wow_pattern_cmd.
> * Used ar->state for WOW state handling and separate WOW state handling is removed.
> * host sdio irq wake up capability is checked before entering into WOW suspend mode.
> * Empty commit logs are avoided. :-)
> * No error is reported from Sparse.
> * Rebased to multi vif implementation.
>
> and other minor corrections.
>
> Using these patch set, WOW patterns can be controlled and configured via iw command.
> Please refer iw help menu for more details.
>
> Limitations:
> * Optional bytes can't be specified while configuring WOW patterns from iw command.
> This is due to the limitation in the firmware.
>
> * Pattern byte matching will always happen from the first byte of received packet.
> This is the limitation in the recent "iw" command (It doesn't take the pattern
> offset where to start pattern matching in the received packets as of now).

Thanks, patchset looks really good now. There were two things I didn't
like, the check_wow() call in RX path and locking for
ath6kl_wmi_relinquish_implicit_pstream_credits(). But we can fix those
later.

All 11 patches applied. I did a couple of minor changes, I'll send a
separate email describing those.

Kalle

2011-11-07 05:27:39

by Raja Mani

[permalink] [raw]
Subject: [PATCH v2 07/11] ath6kl: Invoke WOW suspend/resume calls during PM operation

Link ath6kl's wow suspend/resume functions with the actual suspend/resume path.

WOW mode is selected when the host sdio controller supports both
MMC_PM_KEEP_POWER and MMC_PM_WAKE_SDIO_IRQ capabilities.

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

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 2cd43c8..42dcbea 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1760,6 +1760,21 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
int ret;

switch (mode) {
+ case ATH6KL_CFG_SUSPEND_WOW:
+
+ ath6kl_dbg(ATH6KL_DBG_SUSPEND, "wow mode suspend\n");
+
+ /* Flush all non control pkts in TX path */
+ ath6kl_tx_data_cleanup(ar);
+
+ ret = ath6kl_wow_suspend(ar, wow);
+ if (ret) {
+ ath6kl_err("wow suspend failed: %d\n", ret);
+ return ret;
+ }
+ ar->state = ATH6KL_STATE_WOW;
+ break;
+
case ATH6KL_CFG_SUSPEND_DEEPSLEEP:

ath6kl_cfg80211_stop(ar);
@@ -1811,6 +1826,18 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar)
int ret;

switch (ar->state) {
+ case ATH6KL_STATE_WOW:
+ ath6kl_dbg(ATH6KL_DBG_SUSPEND, "wow mode resume\n");
+
+ ret = ath6kl_wow_resume(ar);
+ if (ret) {
+ ath6kl_warn("wow mode resume failed: %d\n", ret);
+ return ret;
+ }
+
+ ar->state = ATH6KL_STATE_ON;
+ break;
+
case ATH6KL_STATE_DEEPSLEEP:
if (ar->wmi->pwr_mode != ar->wmi->saved_pwr_mode) {
ret = ath6kl_wmi_powermode_cmd(ar->wmi, 0,
@@ -1833,6 +1860,7 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar)
ath6kl_warn("Failed to boot hw in resume: %d\n", ret);
return ret;
}
+ break;

default:
break;
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
index b576b76..0586b3b 100644
--- a/drivers/net/wireless/ath/ath6kl/sdio.c
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -798,6 +798,23 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
return ret;
}

+ if ((flags & MMC_PM_WAKE_SDIO_IRQ) && wow) {
+ /*
+ * 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.
+ */
+ 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 (ret)
+ ath6kl_err("set sdio wake irq flag failed: %d\n", ret);
+
+ return ret;
+ }
+
return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP, NULL);
}

@@ -820,6 +837,9 @@ static int ath6kl_sdio_resume(struct ath6kl *ar)

case ATH6KL_STATE_DEEPSLEEP:
break;
+
+ case ATH6KL_STATE_WOW:
+ break;
}

ath6kl_cfg80211_resume(ar);
--
1.7.1


2011-11-07 05:27:23

by Raja Mani

[permalink] [raw]
Subject: [PATCH v2 05/11] ath6kl: Add new state for WOW mode

In addition to existing deep sleep and cut pwr mode, new state
is added in ath6kl_cfg_suspend_mode as well as in ath6kl_state for WOW.

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

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h
index b4781e5..59fa9d8 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.h
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h
@@ -20,6 +20,7 @@
enum ath6kl_cfg_suspend_mode {
ATH6KL_CFG_SUSPEND_DEEPSLEEP,
ATH6KL_CFG_SUSPEND_CUTPOWER,
+ ATH6KL_CFG_SUSPEND_WOW
};

struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index b6442c1..9e8b8e3 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -459,6 +459,7 @@ enum ath6kl_state {
ATH6KL_STATE_ON,
ATH6KL_STATE_DEEPSLEEP,
ATH6KL_STATE_CUTPOWER,
+ ATH6KL_STATE_WOW,
};

struct ath6kl {
--
1.7.1


2011-11-07 21:03:41

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH v2 07/11] ath6kl: Invoke WOW suspend/resume calls during PM operation

On 11/07/2011 07:25 AM, Raja Mani wrote:
> Link ath6kl's wow suspend/resume functions with the actual suspend/resume path.
>
> WOW mode is selected when the host sdio controller supports both
> MMC_PM_KEEP_POWER and MMC_PM_WAKE_SDIO_IRQ capabilities.
>

[...]

> @@ -1833,6 +1860,7 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar)
> ath6kl_warn("Failed to boot hw in resume: %d\n", ret);
> return ret;
> }
> + break;
>
> default:
> break;


Good catch, I had missed that break. But when you make small fixes like
this, please also mention that in the commit log.

Kalle

2011-11-07 05:27:30

by Raja Mani

[permalink] [raw]
Subject: [PATCH v2 06/11] ath6kl: Move ath6kl_cfg80211_stop() call specific to deep sleep and cut pwr

ath6kl_cfg80211_stop() call is not applicable for WOW mode. Hence moving
this call to deep sleep and cut pwr specific cases.

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

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 1dc7374..2cd43c8 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1759,10 +1759,11 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
{
int ret;

- ath6kl_cfg80211_stop(ar);
-
switch (mode) {
case ATH6KL_CFG_SUSPEND_DEEPSLEEP:
+
+ ath6kl_cfg80211_stop(ar);
+
/* save the current power mode before enabling power save */
ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;

@@ -1777,6 +1778,9 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
break;

case ATH6KL_CFG_SUSPEND_CUTPOWER:
+
+ ath6kl_cfg80211_stop(ar);
+
if (ar->state == ATH6KL_STATE_OFF) {
ath6kl_dbg(ATH6KL_DBG_SUSPEND,
"suspend hw off, no action for cutpower\n");
--
1.7.1


2011-11-07 05:29:44

by Raja Mani

[permalink] [raw]
Subject: [PATCH v2 03/11] ath6kl: Add WOW suspend/resume implementation

This is the core WOW suspend/resume functions will be called
in PM suspend/resume path.

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

diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 04d24d4..68cfb81 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1644,6 +1644,115 @@ static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
return 0;
}

+static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
+{
+ struct ath6kl_vif *vif;
+ int ret, pos, left;
+ u32 filter = 0;
+ u16 i;
+ u8 mask[WOW_MASK_SIZE];
+
+ vif = ath6kl_vif_first(ar);
+ if (!vif)
+ return -EIO;
+
+ if (!ath6kl_cfg80211_ready(vif))
+ return -EIO;
+
+ if (!test_bit(CONNECTED, &vif->flags))
+ 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);
+ /* 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;
+ }
+
+ 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,
+ WOW_HOST_REQ_DELAY);
+ if (ret)
+ return ret;
+
+ ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
+ ATH6KL_HOST_MODE_ASLEEP);
+ if (ret)
+ return ret;
+
+ if (ar->tx_pending[ar->ctrl_ep]) {
+ left = wait_event_interruptible_timeout(ar->event_wq,
+ ar->tx_pending[ar->ctrl_ep] == 0, WMI_TIMEOUT);
+ if (left == 0) {
+ ath6kl_warn("clear wmi ctrl data timeout\n");
+ ret = -ETIMEDOUT;
+ } else if (left < 0) {
+ ath6kl_warn("clear wmi ctrl data failed: %d\n", left);
+ ret = left;
+ }
+ }
+
+ return ret;
+}
+
+static int ath6kl_wow_resume(struct ath6kl *ar)
+{
+ struct ath6kl_vif *vif;
+ int ret;
+
+ vif = ath6kl_vif_first(ar);
+ if (!vif)
+ return -EIO;
+
+ ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
+ ATH6KL_HOST_MODE_AWAKE);
+ return ret;
+}
+
int ath6kl_cfg80211_suspend(struct ath6kl *ar,
enum ath6kl_cfg_suspend_mode mode)
{
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index c30642e..b6442c1 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -439,6 +439,9 @@ struct ath6kl_vif {
struct target_stats target_stats;
};

+#define WOW_LIST_ID 0
+#define WOW_HOST_REQ_DELAY 500 /* ms */
+
/* Flag info */
enum ath6kl_dev_state {
WMI_ENABLED,
--
1.7.1