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.
Additionally, If the user doesn't provide any WOW patterns,
the default WOW patterns will be configured while going to
WOW suspend mode.
V2 changes:
* Existing automatic suspend mode selection logic is retained.
* Suspend mode retry logic is improved without using loop.
* Small patches are folded with appropriate patches as per Kalle's comments.
* New wmi function is added to process set host sleep mode cmd processed event.
Raja Mani (8):
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: Return a proper error code when not in connected state
ath6kl: Add a support to handle the host sleep mode cmd processed
event
ath6kl: Wait for host sleep mode cmd processed event during WOW
suspend
drivers/net/wireless/ath/ath6kl/cfg80211.c | 238 +++++++++++++++++++++++-----
drivers/net/wireless/ath/ath6kl/core.c | 12 +-
drivers/net/wireless/ath/ath6kl/core.h | 5 +-
drivers/net/wireless/ath/ath6kl/sdio.c | 86 +++++++----
drivers/net/wireless/ath/ath6kl/wmi.c | 20 +++-
drivers/net/wireless/ath/ath6kl/wmi.h | 5 +-
6 files changed, 288 insertions(+), 78 deletions(-)
On 01/20/2012 03:35 PM, [email protected] wrote:
> 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]>
> +static int ath6kl_non_ap_add_default_wow_patterns(struct ath6kl *ar,
> + struct ath6kl_vif *vif)
> +{
Maybe ath6kl_wow_sta() or something like that?
Kalle
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 e244d83..5d7aabe 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1921,10 +1921,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
From: Raja Mani <[email protected]>
ath6kl_wow_suspend() has to wait until get an
WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENT after sending
set host sleep mode command.
This wait creates perfect sync with the firmware before
the driver enter into wow suspend state.
Signed-off-by: Raja Mani <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 14 ++++++++++++++
1 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 038d63b..2d40fd0 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1976,11 +1976,25 @@ skip_arp:
if (ret)
return ret;
+ clear_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags);
+
ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_HOST_MODE_ASLEEP);
if (ret)
return ret;
+ left = wait_event_interruptible_timeout(ar->event_wq,
+ test_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags),
+ WMI_TIMEOUT);
+ if (left == 0) {
+ ath6kl_warn("timeout, didn't get host sleep cmd processed event\n");
+ ret = -ETIMEDOUT;
+ } else if (left < 0) {
+ ath6kl_warn("error while waiting for host sleep cmd processed event %d\n",
+ left);
+ ret = left;
+ }
+
if (ar->tx_pending[ar->ctrl_ep]) {
left = wait_event_interruptible_timeout(ar->event_wq,
ar->tx_pending[ar->ctrl_ep] == 0, WMI_TIMEOUT);
--
1.7.1
From: Raja Mani <[email protected]>
Using this patch, the user can bypass existing auto
suspend mode selection logic and force ath6kl to enter
into the suspend mode what he/she wants.
If the user doesn't choose any suspend mode while doing
insmod of the driver, auto suspend mode selection logic
will kick in and choose suspend mode based on the host
SDIO controller capability.
Generic module parameter is required to specify suspend
mode including Deep Sleep and WOW while doing insmod.
Renaming existing mod param variable suspend_cutpower
would be sufficient to meet this requirement.
New module parameter suspend_mode can take any one of
the below suspend state,
1. cut power
2. deep sleep
3. wow
Signed-off-by: Raja Mani <[email protected]>
---
drivers/net/wireless/ath/ath6kl/core.c | 12 +++--
drivers/net/wireless/ath/ath6kl/core.h | 4 +-
drivers/net/wireless/ath/ath6kl/sdio.c | 86 ++++++++++++++++++++------------
3 files changed, 64 insertions(+), 38 deletions(-)
diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c
index d764afe..7bed2e5 100644
--- a/drivers/net/wireless/ath/ath6kl/core.c
+++ b/drivers/net/wireless/ath/ath6kl/core.c
@@ -25,12 +25,12 @@
#include "cfg80211.h"
unsigned int debug_mask;
-static bool suspend_cutpower;
+static unsigned char suspend_mode;
static unsigned int uart_debug;
static unsigned int ath6kl_p2p;
module_param(debug_mask, uint, 0644);
-module_param(suspend_cutpower, bool, 0444);
+module_param(suspend_mode, byte, 0644);
module_param(uart_debug, uint, 0644);
module_param(ath6kl_p2p, uint, 0644);
@@ -143,8 +143,12 @@ 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 &&
+ suspend_mode >= WLAN_POWER_STATE_CUT_PWR &&
+ suspend_mode <= WLAN_POWER_STATE_WOW)
+ ar->suspend_mode = suspend_mode;
+ else
+ ar->suspend_mode = 0;
if (uart_debug)
ar->conf_flags |= ATH6KL_CONF_UART_DEBUG;
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index 67b22e4..1ddff66 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -196,8 +196,7 @@ 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)
-#define ATH6KL_CONF_UART_DEBUG BIT(5)
+#define ATH6KL_CONF_UART_DEBUG BIT(4)
enum wlan_low_pwr_state {
WLAN_POWER_STATE_ON,
@@ -612,6 +611,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/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
index 7bb6107..8e7f9e3 100644
--- a/drivers/net/wireless/ath/ath6kl/sdio.c
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -779,7 +779,7 @@ out:
return ret;
}
-static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
+static int ath6kl_set_sdio_pm_keep_pwr_wake_irq(struct ath6kl *ar)
{
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
struct sdio_func *func = ar_sdio->func;
@@ -790,60 +790,82 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
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);
- }
+ if (!(flags & MMC_PM_WAKE_SDIO_IRQ) ||
+ !(flags & MMC_PM_KEEP_POWER))
+ return -EINVAL;
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);
+ ath6kl_err("set sdio keep pwr flag failed: %d\n", ret);
return ret;
}
- if (!(flags & MMC_PM_WAKE_SDIO_IRQ))
- goto deepsleep;
-
/* sdio irq wakes up host */
+ 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;
+}
+
+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;
if (ar->state == ATH6KL_STATE_SCHED_SCAN) {
+ ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sched scan is in progress\n");
+
+ ret = ath6kl_set_sdio_pm_keep_pwr_wake_irq(ar);
+ if (ret)
+ goto cut_pwr;
+
ret = ath6kl_cfg80211_suspend(ar,
ATH6KL_CFG_SUSPEND_SCHED_SCAN,
NULL);
- if (ret) {
- ath6kl_warn("Schedule scan suspend failed: %d", ret);
- return ret;
- }
-
- ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
if (ret)
- ath6kl_warn("set sdio wake irq flag failed: %d\n", ret);
+ goto cut_pwr;
- return ret;
+ return 0;
}
- if (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.
- */
+ if (ar->suspend_mode == WLAN_POWER_STATE_WOW ||
+ (!ar->suspend_mode && wow)) {
+
+ ret = ath6kl_set_sdio_pm_keep_pwr_wake_irq(ar);
+ if (ret)
+ goto cut_pwr;
+
ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_WOW, wow);
if (ret)
- return ret;
+ goto cut_pwr;
+
+ return 0;
+ }
+
+ if (ar->suspend_mode == WLAN_POWER_STATE_DEEP_SLEEP ||
+ !ar->suspend_mode) {
- ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
+ flags = sdio_get_host_pm_caps(func);
+ if (!(flags & MMC_PM_KEEP_POWER))
+ goto cut_pwr;
+
+ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
if (ret)
- ath6kl_err("set sdio wake irq flag failed: %d\n", ret);
+ goto cut_pwr;
- return ret;
+ ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP,
+ NULL);
+ if (ret)
+ goto cut_pwr;
+
+ return 0;
}
-deepsleep:
- return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP, NULL);
+cut_pwr:
+ return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER, NULL);
}
static int ath6kl_sdio_resume(struct ath6kl *ar)
--
1.7.1
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 9ab92c4..e244d83 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1723,6 +1723,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)
{
@@ -1847,10 +1905,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);
@@ -1867,37 +1925,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)
@@ -1925,21 +1952,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
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 5d7aabe..038d63b 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1919,7 +1919,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
On 01/20/2012 03:35 PM, [email protected] wrote:
> 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]>
> +static int ath6kl_add_usr_wow_patterns(struct ath6kl *ar,
> + struct ath6kl_vif *vif,
> + struct cfg80211_wowlan *wow,
> + u32 *filter)
> +{
ath6kl_wow_usr()?
Kalle
Hi Raja,
On 01/20/2012 03:35 PM, [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.
>
> Additionally, If the user doesn't provide any WOW patterns,
> the default WOW patterns will be configured while going to
> WOW suspend mode.
>
> V2 changes:
>
> * Existing automatic suspend mode selection logic is retained.
> * Suspend mode retry logic is improved without using loop.
> * Small patches are folded with appropriate patches as per Kalle's comments.
> * New wmi function is added to process set host sleep mode cmd processed event.
Thanks, this is much better now. I reviewed the patches and found only
minor issues.
Kalle
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.
In addition, two argument variable's ('filter' and 'mask)
data type in ath6kl_wmi_add_wow_pattern_cmd() are changed
from 'u8 *' to 'const u8 *'. This is needed to make all
pattern and mask arrays to be 'static const u8' in
the caller function.
Signed-off-by: Raja Mani <[email protected]>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 79 ++++++++++++++++++++++++++++
drivers/net/wireless/ath/ath6kl/wmi.c | 3 +-
drivers/net/wireless/ath/ath6kl/wmi.h | 3 +-
3 files changed, 83 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 594d246..88cce8f 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1723,6 +1723,85 @@ 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 const 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 const 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 const u8 arp_pattern[] = { 0x08, 0x06 };
+ static const u8 arp_mask[] = { 0xff, 0xff };
+ u8 arp_offset = 20;
+ static const u8 discvr_pattern[] = { 0xe0, 0x00, 0x00, 0xf8 };
+ static const u8 discvr_mask[] = { 0xf0, 0x00, 0x00, 0xf8 };
+ u8 discvr_offset = 38;
+ static const 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 const 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;
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 5d678bf..9c8e4df 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -2620,7 +2620,8 @@ int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx,
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)
+ u8 filter_offset, const u8 *filter,
+ const u8 *mask)
{
struct sk_buff *skb;
struct wmi_add_wow_pattern_cmd *cmd;
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index 48e9d26..85698ef 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -2461,7 +2461,8 @@ int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx,
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);
+ u8 filter_offset, const u8 *filter,
+ const 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);
--
1.7.1
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 88cce8f..9ab92c4 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1802,6 +1802,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 const u8 discvr_pattern[] = { 0xe0, 0x00, 0x00, 0xf8 };
+ static const 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
On Tuesday 24 January 2012 05:17 PM, Kalle Valo wrote:
> Hi Raja,
>
> On 01/20/2012 03:35 PM, [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.
>>
>> Additionally, If the user doesn't provide any WOW patterns,
>> the default WOW patterns will be configured while going to
>> WOW suspend mode.
>>
>> V2 changes:
>>
>> * Existing automatic suspend mode selection logic is retained.
>> * Suspend mode retry logic is improved without using loop.
>> * Small patches are folded with appropriate patches as per Kalle's comments.
>> * New wmi function is added to process set host sleep mode cmd processed event.
>
> Thanks, this is much better now. I reviewed the patches and found only
> minor issues.
Thanks for your review. I'll take care your comments in V3.
>
> Kalle
From: Raja Mani <[email protected]>
For every WMI_SET_HOST_SLEEP_MODE_CMDID command (send from the host),
the firmware sends WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID as
an acknowledgement to the host.
In order to being sync with the firmware, the host has to wait for
this event before going to the suspend state.
This patch adds,
* New command WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID in
WMI event table.
* New WMI function ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx()
to process the event.
* New flag HOST_SLEEP_MODE_CMD_PROCESSED in VIF flags to record
the arrival of the event.
Signed-off-by: Raja Mani <[email protected]>
---
drivers/net/wireless/ath/ath6kl/core.h | 1 +
drivers/net/wireless/ath/ath6kl/wmi.c | 17 +++++++++++++++++
drivers/net/wireless/ath/ath6kl/wmi.h | 2 ++
3 files changed, 20 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index 1ddff66..b62cff9 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -445,6 +445,7 @@ enum ath6kl_vif_state {
DTIM_PERIOD_AVAIL,
WLAN_ENABLED,
STATS_UPDATE_PEND,
+ HOST_SLEEP_MODE_CMD_PROCESSED,
};
struct ath6kl_vif {
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 9c8e4df..18fa9aa 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -2590,6 +2590,18 @@ int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx,
return ret;
}
+/* This command has zero length payload */
+static int ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx(struct wmi *wmi,
+ struct ath6kl_vif *vif)
+{
+ struct ath6kl *ar = wmi->parent_dev;
+
+ set_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags);
+ wake_up(&ar->event_wq);
+
+ return 0;
+}
+
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)
@@ -3556,6 +3568,11 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_COMPLETE_EVENTID\n");
ret = ath6kl_wmi_tx_complete_event_rx(datap, len);
break;
+ case WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID:
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID");
+ ret = ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx(wmi, vif);
+ break;
case WMI_REMAIN_ON_CHNL_EVENTID:
ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n");
ret = ath6kl_wmi_remain_on_chnl_event_rx(wmi, datap, len, vif);
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index 85698ef..e791986 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -1357,6 +1357,8 @@ enum wmi_event_id {
WMI_P2P_START_SDPD_EVENTID,
WMI_P2P_SDPD_RX_EVENTID,
+ WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID = 0x1047,
+
WMI_THIN_RESERVED_START_EVENTID = 0x8000,
/* Events in this range are reserved for thinmode */
WMI_THIN_RESERVED_END_EVENTID = 0x8fff,
--
1.7.1
On 01/20/2012 03:35 PM, [email protected] wrote:
> From: Raja Mani <[email protected]>
>
> Using this patch, the user can bypass existing auto
> suspend mode selection logic and force ath6kl to enter
> into the suspend mode what he/she wants.
>
> If the user doesn't choose any suspend mode while doing
> insmod of the driver, auto suspend mode selection logic
> will kick in and choose suspend mode based on the host
> SDIO controller capability.
>
> Generic module parameter is required to specify suspend
> mode including Deep Sleep and WOW while doing insmod.
> Renaming existing mod param variable suspend_cutpower
> would be sufficient to meet this requirement.
>
> New module parameter suspend_mode can take any one of
> the below suspend state,
> 1. cut power
> 2. deep sleep
> 3. wow
>
> Signed-off-by: Raja Mani <[email protected]>
Few comments:
> --- a/drivers/net/wireless/ath/ath6kl/core.c
> +++ b/drivers/net/wireless/ath/ath6kl/core.c
> @@ -25,12 +25,12 @@
> #include "cfg80211.h"
>
> unsigned int debug_mask;
> -static bool suspend_cutpower;
> +static unsigned char suspend_mode;
IMHO uint is better, just like below.
> static unsigned int uart_debug;
> static unsigned int ath6kl_p2p;
>
> module_param(debug_mask, uint, 0644);
> -module_param(suspend_cutpower, bool, 0444);
> +module_param(suspend_mode, byte, 0644);
> module_param(uart_debug, uint, 0644);
> module_param(ath6kl_p2p, uint, 0644);
> --- a/drivers/net/wireless/ath/ath6kl/sdio.c
> +++ b/drivers/net/wireless/ath/ath6kl/sdio.c
> @@ -779,7 +779,7 @@ out:
> return ret;
> }
>
> -static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
> +static int ath6kl_set_sdio_pm_keep_pwr_wake_irq(struct ath6kl *ar)
The function name doesn't need to be this long, ath6kl_sdio_pm_caps(),
or something like that, is enough. And I'm not really sure if this
function makes sense, it complicates the error handling.
> + if (ar->suspend_mode == WLAN_POWER_STATE_WOW ||
> + (!ar->suspend_mode && wow)) {
> +
> + ret = ath6kl_set_sdio_pm_keep_pwr_wake_irq(ar);
> + if (ret)
> + goto cut_pwr;
This changes functionality so that if MMC_PM_WAKE_SDIO_IRQ is not
supported we will fallback to cutpower, earlier we would go to deep
sleep mode. I guess that's ok, but it still is a functionality change.
Kalle
On 01/20/2012 03:35 PM, [email protected] wrote:
> 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.
>
> In addition, two argument variable's ('filter' and 'mask)
> data type in ath6kl_wmi_add_wow_pattern_cmd() are changed
> from 'u8 *' to 'const u8 *'. This is needed to make all
> pattern and mask arrays to be 'static const u8' in
> the caller function.
>
> Signed-off-by: Raja Mani <[email protected]>
You could fold patches 2-5 into one patch as they seem to be the same
logical change. At least patches 4 and 5 need to be folded, otherwise
wow will be broken between the patches.
> --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
> +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
> @@ -1723,6 +1723,85 @@ 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)
> +{
ath6kl_wow_ap() or similar would be a lot shorter name.
Kalle
On 01/20/2012 03:35 PM, [email protected] wrote:
> 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]>
Does this fix a visible bug? Or did you find this during code review?
Kalle
On 01/20/2012 03:35 PM, [email protected] wrote:
> From: Raja Mani <[email protected]>
>
> For every WMI_SET_HOST_SLEEP_MODE_CMDID command (send from the host),
> the firmware sends WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID as
> an acknowledgement to the host.
>
> In order to being sync with the firmware, the host has to wait for
> this event before going to the suspend state.
>
> This patch adds,
> * New command WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID in
> WMI event table.
> * New WMI function ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx()
> to process the event.
> * New flag HOST_SLEEP_MODE_CMD_PROCESSED in VIF flags to record
> the arrival of the event.
>
> Signed-off-by: Raja Mani <[email protected]>
You could fold patches 7 and 8 as they are one logical change.
Kalle