From 6cb3c714e75c6e70fa1c379b7f3af2f143f31c70 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 7 Nov 2011 22:52:45 +0200 Subject: [PATCH] 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 Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 109 +++++++++++++++++++++ drivers/net/wireless/ath/ath6kl/core.h | 3 + 2 files changed, 112 insertions(+) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 44e2c76f9246..2e12c6f70a5a 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 c30642e9795d..b6442c1af3f4 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, -- GitLab