From 3a9dadbfd3a55b70f6ad63ce4cbda7e03731a44e Mon Sep 17 00:00:00 2001 From: Sarada Prasanna Garnayak Date: Wed, 22 Nov 2017 20:45:22 +0530 Subject: [PATCH 1/2] net: update rdev suspend method for the wowlan suspend/resume Pass wowlan configuration data as parameter in the rdev suspend. The userspace wlan utility (iw, wpa_supplicant etc.) configured the wow pattern and event through nl80211 cmd. During the wlan system suspend the wlan device configured the wakeup source and event as per the configuration data passed by the wlan utility to wkae up the device from the sleep state on wow pattern or event match. CRs-Fixed: 2147919 Change-Id: Iaca21724e8dd5a9c18e104c44ee6fe73752594e6 Signed-off-by: Sarada Prasanna Garnayak --- net/wireless/sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 460c4b0e343c..e0eb2a4cfd8e 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c @@ -97,7 +97,7 @@ static int wiphy_suspend(struct device *dev) rtnl_lock(); if (rdev->wiphy.registered) if (rdev->ops->suspend) - ret = rdev_suspend(rdev, NULL); + ret = rdev_suspend(rdev, rdev->wiphy.wowlan_config); rtnl_unlock(); return ret; From 8bb321456562903bca7b681470847c382b1b3bf4 Mon Sep 17 00:00:00 2001 From: Sarada Prasanna Garnayak Date: Fri, 6 Oct 2017 16:29:41 +0530 Subject: [PATCH 2/2] ath10k: Enable WoWLAN for the wcn3990 snoc wlan module Register snoc bus layer suspend/resume PM ops and configure the wakeup source for the device to adds support for WOWLAN feature for the wcn3990 snoc wlan module. CRs-Fixed: 2139961 Change-Id: Ic43414b965aee27564f8bbbe237c706f5262c2e4 Signed-off-by: Sarada Prasanna Garnayak --- drivers/net/wireless/ath/ath10k/core.c | 3 ++ drivers/net/wireless/ath/ath10k/mac.c | 1 + drivers/net/wireless/ath/ath10k/snoc.c | 52 ++++++++++++++++++++++- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 2 + drivers/net/wireless/ath/ath10k/wmi-tlv.h | 1 + drivers/net/wireless/ath/ath10k/wow.c | 14 ++++++ drivers/net/wireless/ath/ath10k/wow.h | 1 + 7 files changed, 72 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 8b8bea5d546a..55033aed6d6b 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1304,6 +1304,9 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar) fw_file = &ar->normal_mode_fw.fw_file; fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_TLV; fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_TLV; + __set_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, + fw_file->fw_features); + __set_bit(WMI_SERVICE_WOW, ar->wmi.svc_map); return 0; } diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 5a84626dff14..1147dee4051e 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -7578,6 +7578,7 @@ static const struct ieee80211_ops ath10k_ops = { #ifdef CONFIG_PM .suspend = ath10k_wow_op_suspend, .resume = ath10k_wow_op_resume, + .set_wakeup = ath10k_wow_op_set_wakeup, #endif #ifdef CONFIG_MAC80211_DEBUGFS .sta_add_debugfs = ath10k_sta_add_debugfs, diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index c42d7eebf465..a1a4812feeed 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -30,7 +30,8 @@ #include #include -#define WCN3990_MAX_IRQ 12 +#define WCN3990_MAX_IRQ 12 +#define WCN3990_WAKE_IRQ_CE 2 const char *ce_name[WCN3990_MAX_IRQ] = { "WLAN_CE_0", @@ -1161,7 +1162,8 @@ static int ath10k_snoc_hif_power_up(struct ath10k *ar) atomic_set(&ar_snoc->pm_ops_inprogress, 0); } - if (ar->state == ATH10K_STATE_ON || + if ((ar->state == ATH10K_STATE_ON) || + (ar->state == ATH10K_STATE_RESTARTING) || test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) { ret = ath10k_snoc_bus_configure(ar); if (ret) { @@ -1571,6 +1573,50 @@ static int ath10k_hw_power_off(struct ath10k *ar) return ret; } +static int ath10k_snoc_hif_suspend(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + int ret = 0; + + if (!ar_snoc) + return -EINVAL; + + if (!device_may_wakeup(ar->dev)) + return -EINVAL; + + ret = enable_irq_wake(ar_snoc->ce_irqs[WCN3990_WAKE_IRQ_CE].irq_line); + if (ret) { + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "HIF Suspend: Failed to enable wakeup IRQ\n"); + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "HIF Suspended\n"); + return ret; +} + +static int ath10k_snoc_hif_resume(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + int ret = 0; + + if (!ar_snoc) + return -EINVAL; + + if (!device_may_wakeup(ar->dev)) + return -EINVAL; + + ret = disable_irq_wake(ar_snoc->ce_irqs[WCN3990_WAKE_IRQ_CE].irq_line); + if (ret) { + ath10k_dbg(ar, ATH10K_DBG_SNOC, + "HIF Resume: Failed to disable wakeup IRQ\n"); + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_SNOC, "HIF Resumed\n"); + return ret; +} + static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { .tx_sg = ath10k_snoc_hif_tx_sg, .start = ath10k_snoc_hif_start, @@ -1583,6 +1629,8 @@ static const struct ath10k_hif_ops ath10k_snoc_hif_ops = { .power_down = ath10k_snoc_hif_power_down, .read32 = ath10k_snoc_read32, .write32 = ath10k_snoc_write32, + .suspend = ath10k_snoc_hif_suspend, + .resume = ath10k_snoc_hif_resume, }; static const struct ath10k_bus_ops ath10k_snoc_bus_ops = { diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index f5360444a083..95bd588e0d2c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -3028,6 +3028,8 @@ ath10k_wmi_tlv_op_gen_wow_enable(struct ath10k *ar) cmd = (void *)tlv->value; cmd->enable = __cpu_to_le32(1); + if (QCA_REV_WCN3990(ar)) + cmd->pause_iface_config = __cpu_to_le32(1); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv wow enable\n"); return skb; diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 500d1d8f441f..7140e5e23307 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1554,6 +1554,7 @@ struct wmi_tlv_wow_add_del_event_cmd { struct wmi_tlv_wow_enable_cmd { __le32 enable; + __le32 pause_iface_config; } __packed; struct wmi_tlv_wow_host_wakeup_ind { diff --git a/drivers/net/wireless/ath/ath10k/wow.c b/drivers/net/wireless/ath/ath10k/wow.c index dfc4cf016c99..de678fd3b801 100644 --- a/drivers/net/wireless/ath/ath10k/wow.c +++ b/drivers/net/wireless/ath/ath10k/wow.c @@ -309,6 +309,18 @@ exit: return ret ? 1 : 0; } +void ath10k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled) +{ + struct ath10k *ar = hw->priv; + + mutex_lock(&ar->conf_mutex); + if (test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, + ar->running_fw->fw_file.fw_features)) { + device_set_wakeup_enable(ar->dev, enabled); + } + mutex_unlock(&ar->conf_mutex); +} + int ath10k_wow_op_resume(struct ieee80211_hw *hw) { struct ath10k *ar = hw->priv; @@ -368,5 +380,7 @@ int ath10k_wow_init(struct ath10k *ar) ar->wow.wowlan_support.n_patterns = ar->wow.max_num_patterns; ar->hw->wiphy->wowlan = &ar->wow.wowlan_support; + device_set_wakeup_capable(ar->dev, true); + return 0; } diff --git a/drivers/net/wireless/ath/ath10k/wow.h b/drivers/net/wireless/ath/ath10k/wow.h index abbb04b6d1bd..9745b9ddc7f5 100644 --- a/drivers/net/wireless/ath/ath10k/wow.h +++ b/drivers/net/wireless/ath/ath10k/wow.h @@ -28,6 +28,7 @@ int ath10k_wow_init(struct ath10k *ar); int ath10k_wow_op_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan); int ath10k_wow_op_resume(struct ieee80211_hw *hw); +void ath10k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled); #else