summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKomal Seelam <kseelam@qti.qualcomm.com>2015-10-21 17:52:03 +0530
committerAnjaneedevi Kapparapu <akappa@codeaurora.org>2015-11-18 12:53:45 +0530
commited2633f6ec695d84d24928cd46066b221e867be3 (patch)
tree4f931cd9f35794fe8838106ebc5e17a7a5b94994
parent6c9b4fc25b47f3d0307a48df27fb61af8230521f (diff)
qcacld-2.0: Suspend Target in cfg80211 suspend for SDIO Targets
By Design SDIO MMC controller don't expect any card interrupts as part of SDIO bus suspend. MMC Host Controller is preventing APPS to enter suspend by calling pm_wakeup_event if any card interrupt comes in Suspend State or Suspending State. The MMC controller does so to ensure no interrupt is lost as part of suspending, and believes that the interrupt is expecting APPS to be awake. SDIO WiFi Driver as a client driver registers it's System PM callbacks to MMC host controller and MMC calls the client callbacks as part of it's Systsem PM operations. SDIO WiFi Driver which is a client device to SDIO MMC Controller expects interrupts as part of suspend, eg: ACK for WOW_ENABLE CMD or PDEV_SUSPEND CMD, this is causing APPS not to enter power collapse. Fix it by Suspending Target as part of cfg80211 suspend, hence target won't raise interrupts after that. Change-Id: I0839b48a9527a981231b05c4880efe1d1780a622 CRs-Fixed: 934405
-rw-r--r--CORE/HDD/src/wlan_hdd_cfg80211.c29
-rw-r--r--CORE/SERVICES/COMMON/hif.h10
-rw-r--r--CORE/SERVICES/HIF/PCIe/hif_pci.c14
-rw-r--r--CORE/SERVICES/HIF/PCIe/if_pci.h2
-rw-r--r--CORE/SERVICES/HIF/USB/hif_usb.c14
-rw-r--r--CORE/SERVICES/HIF/USB/if_usb.h2
-rw-r--r--CORE/SERVICES/HIF/sdio/linux/if_ath_sdio.c8
-rw-r--r--CORE/SERVICES/HIF/sdio/linux/if_ath_sdio.h2
-rw-r--r--CORE/SERVICES/HIF/sdio/linux/native_sdio/src/hif.c34
-rw-r--r--CORE/SERVICES/WMA/wma.c76
-rw-r--r--CORE/SERVICES/WMA/wma.h9
11 files changed, 170 insertions, 30 deletions
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index d3a9b29efc18..b8b87b792dff 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -94,6 +94,8 @@
#include "wlan_qct_wda.h"
#include "wlan_nv.h"
#include "wlan_hdd_dev_pwr.h"
+#include "hif.h"
+#include "wma.h"
#ifdef CONFIG_CNSS
#include <net/cnss.h>
#endif
@@ -21545,6 +21547,15 @@ int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy)
return -EINVAL;
}
+ if (hif_is_80211_fw_wow_required()) {
+ result = wma_resume_fw();
+ if (result) {
+ hddLog(LOGE, FL("Failed to resume FW err:%d"), result);
+ VOS_BUG(0);
+ return -EBUSY;
+ }
+ }
+
#ifdef CONFIG_CNSS
cnss_request_bus_bandwidth(CNSS_BUS_WIDTH_MEDIUM);
#endif
@@ -21811,9 +21822,27 @@ int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
cnss_request_bus_bandwidth(CNSS_BUS_WIDTH_NONE);
#endif
+ if (hif_is_80211_fw_wow_required()) {
+ rc = wma_suspend_fw();
+ if (rc) {
+ hddLog(LOGE, FL("Failed to suspend FW err:%d"), rc);
+ goto fail_suspend;
+ }
+ }
+
EXIT();
return 0;
+fail_suspend:
+#ifdef CONFIG_CNSS
+ cnss_request_bus_bandwidth(CNSS_BUS_WIDTH_MEDIUM);
+#endif
+ pHddCtx->isWiphySuspended = FALSE;
+#ifdef QCA_CONFIG_SMP
+ complete(&vosSchedContext->ResumeTlshimRxEvent);
+ pHddCtx->isTlshimRxThreadSuspended = FALSE;
+#endif
+
#ifdef QCA_CONFIG_SMP
resume_all:
diff --git a/CORE/SERVICES/COMMON/hif.h b/CORE/SERVICES/COMMON/hif.h
index 7b998630371f..4e163e104701 100644
--- a/CORE/SERVICES/COMMON/hif.h
+++ b/CORE/SERVICES/COMMON/hif.h
@@ -827,6 +827,16 @@ void HIFIpaGetCEResource(HIF_DEVICE *hif_device,
void HIFSetMailboxSwap(HIF_DEVICE *device);
+int hif_register_driver(void);
+void hif_unregister_driver(void);
+/* The API's check if FW can be suspended as part of cfg80211 suspend.
+ * This is done for SDIO drivers, for other bus types it's NO OP, they
+ * enable/disable wow in bus suspend callback.
+ * In SDIO driver bus suspend host will configure 4 bit sdio mode to
+ * 1 bit sdio mode and set the appropriate host flags.
+ */
+bool hif_is_80211_fw_wow_required(void);
+
#ifdef FEATURE_RUNTIME_PM
/* Runtime power management API of HIF to control
* runtime pm. During Runtime Suspend the get API
diff --git a/CORE/SERVICES/HIF/PCIe/hif_pci.c b/CORE/SERVICES/HIF/PCIe/hif_pci.c
index 27fd2a090dd3..fbfe1ce3c11e 100644
--- a/CORE/SERVICES/HIF/PCIe/hif_pci.c
+++ b/CORE/SERVICES/HIF/PCIe/hif_pci.c
@@ -3579,3 +3579,17 @@ void hif_runtime_pm_prevent_suspend_deinit(void *data)
adf_os_mem_free(context);
}
#endif
+
+/**
+ * hif_is_80211_fw_wow_required() - API to check if target suspend is needed
+ *
+ * API determines if fw can be suspended and returns true/false to the caller.
+ * Caller will call WMA WoW API's to suspend.
+ * This API returns true only for SDIO bus types, for others it's a false.
+ *
+ * Return: bool
+ */
+bool hif_is_80211_fw_wow_required(void)
+{
+ return false;
+}
diff --git a/CORE/SERVICES/HIF/PCIe/if_pci.h b/CORE/SERVICES/HIF/PCIe/if_pci.h
index 619278062439..3204f6101eb9 100644
--- a/CORE/SERVICES/HIF/PCIe/if_pci.h
+++ b/CORE/SERVICES/HIF/PCIe/if_pci.h
@@ -165,8 +165,6 @@ int hif_pci_check_soc_status(struct hif_pci_softc *sc);
void dump_CE_debug_register(struct hif_pci_softc *sc);
/*These functions are exposed to HDD*/
-int hif_register_driver(void);
-void hif_unregister_driver(void);
int hif_init_adf_ctx(void *ol_sc);
void hif_init_pdev_txrx_handle(void *ol_sc, void *txrx_handle);
void hif_disable_isr(void *ol_sc);
diff --git a/CORE/SERVICES/HIF/USB/hif_usb.c b/CORE/SERVICES/HIF/USB/hif_usb.c
index a3bf77d30e97..023e54d04868 100644
--- a/CORE/SERVICES/HIF/USB/hif_usb.c
+++ b/CORE/SERVICES/HIF/USB/hif_usb.c
@@ -1047,3 +1047,17 @@ void HIFSetBundleMode(HIF_DEVICE *hif_device, bool enabled, int rx_bundle_cnt)
enabled ? "enabled" : "disabled",
rx_bundle_cnt));
}
+
+/**
+ * hif_is_80211_fw_wow_required() - API to check if target suspend is needed
+ *
+ * API determines if fw can be suspended and returns true/false to the caller.
+ * Caller will call WMA WoW API's to suspend.
+ * This API returns true only for SDIO bus types, for others it's a false.
+ *
+ * Return: bool
+ */
+bool hif_is_80211_fw_wow_required(void)
+{
+ return false;
+}
diff --git a/CORE/SERVICES/HIF/USB/if_usb.h b/CORE/SERVICES/HIF/USB/if_usb.h
index 26c6aa3d3c98..1cd06d2f0c91 100644
--- a/CORE/SERVICES/HIF/USB/if_usb.h
+++ b/CORE/SERVICES/HIF/USB/if_usb.h
@@ -93,8 +93,6 @@ static inline void athdiag_procfs_remove(void) { return; }
#endif
/*These functions are exposed to HDD*/
-int hif_register_driver(void);
-void hif_unregister_driver(void);
int hif_init_adf_ctx(void *ol_sc);
void hif_init_pdev_txrx_handle(void *ol_sc, void *txrx_handle);
void hif_disable_isr(void *ol_sc);
diff --git a/CORE/SERVICES/HIF/sdio/linux/if_ath_sdio.c b/CORE/SERVICES/HIF/sdio/linux/if_ath_sdio.c
index b799c8368a86..2119c5dc57f4 100644
--- a/CORE/SERVICES/HIF/sdio/linux/if_ath_sdio.c
+++ b/CORE/SERVICES/HIF/sdio/linux/if_ath_sdio.c
@@ -262,15 +262,15 @@ ath_hif_sdio_remove(void *context, void *hif_handle)
static A_STATUS
ath_hif_sdio_suspend(void *context)
{
- printk(KERN_INFO "ol_ath_sdio_suspend TODO\n");
- return 0;
+ pr_debug("%s TODO\n", __func__);
+ return 0;
}
static A_STATUS
ath_hif_sdio_resume(void *context)
{
- printk(KERN_INFO "ol_ath_sdio_resume ODO\n");
- return 0;
+ pr_debug("%s TODO\n", __func__);
+ return 0;
}
static A_STATUS
diff --git a/CORE/SERVICES/HIF/sdio/linux/if_ath_sdio.h b/CORE/SERVICES/HIF/sdio/linux/if_ath_sdio.h
index a73d3af99bdf..1ba189377431 100644
--- a/CORE/SERVICES/HIF/sdio/linux/if_ath_sdio.h
+++ b/CORE/SERVICES/HIF/sdio/linux/if_ath_sdio.h
@@ -94,8 +94,6 @@ int ath_sdio_suspend(void *context);
int ath_sdio_resume(void *context);
/*These functions are exposed to HDD*/
-int hif_register_driver(void);
-void hif_unregister_driver(void);
int hif_init_adf_ctx(void *ol_sc);
void hif_deinit_adf_ctx(void *ol_sc);
void hif_disable_isr(void *ol_sc);
diff --git a/CORE/SERVICES/HIF/sdio/linux/native_sdio/src/hif.c b/CORE/SERVICES/HIF/sdio/linux/native_sdio/src/hif.c
index f8b48ea1ef72..835d4faa95ab 100644
--- a/CORE/SERVICES/HIF/sdio/linux/native_sdio/src/hif.c
+++ b/CORE/SERVICES/HIF/sdio/linux/native_sdio/src/hif.c
@@ -1900,18 +1900,6 @@ static int hifDeviceSuspend(struct device *dev)
return ret;
}
- if (wma_is_wow_mode_selected(temp_module)) {
- if (wma_enable_wow_in_fw(temp_module, 0)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("wow mode failure\n"));
- return -1;
- }
- } else {
- if (wma_suspend_target(temp_module, 0)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("PDEV Suspend Failed\n"));
- return -1;
- }
- }
-
if (pm_flag & MMC_PM_WAKE_SDIO_IRQ){
AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("hifDeviceSuspend: wow enter\n"));
config = HIF_DEVICE_POWER_DOWN;
@@ -2048,14 +2036,6 @@ static int hifDeviceResume(struct device *dev)
device->is_suspend = FALSE;
}
- /* No need to send WMI_PDEV_RESUME_CMDID to FW if WOW is enabled */
- if (!wma_is_wow_mode_selected(temp_module)) {
- wma_resume_target(temp_module, 0);
- } else if (wma_disable_wow_in_fw(temp_module, 0)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("%s: disable wow in fw failed\n", __func__));
- status = (-1);
- }
-
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -hifDeviceResume\n"));
device->DeviceState = HIF_DEVICE_STATE_ON;
@@ -2342,3 +2322,17 @@ A_BOOL HIFIsMailBoxSwapped(HIF_DEVICE *hd)
{
return ((struct hif_device *)hd)->swap_mailbox;
}
+
+/**
+ * hif_is_80211_fw_wow_required() - API to check if target suspend is needed
+ *
+ * API determines if fw can be suspended and returns true/false to the caller.
+ * Caller will call WMA WoW API's to suspend.
+ * The API returns true only for SDIO bus types, for others it's a false.
+ *
+ * Return: bool
+ */
+bool hif_is_80211_fw_wow_required(void)
+{
+ return true;
+}
diff --git a/CORE/SERVICES/WMA/wma.c b/CORE/SERVICES/WMA/wma.c
index 7e97cf4383e8..2607bc877af3 100644
--- a/CORE/SERVICES/WMA/wma.c
+++ b/CORE/SERVICES/WMA/wma.c
@@ -33035,3 +33035,79 @@ uint32_t wma_get_vht_ch_width(void)
return fw_ch_wd;
}
+/*
+ * wma_suspend_fw() - API to suspend FW
+ *
+ * The API will be called only for SDIO driver from HDD, for other drivers
+ * by default HIF return failure, FW suspend happens in bus suspend callbacks.
+ *
+ * Return : int
+ */
+
+int wma_suspend_fw(void)
+{
+ int ret = 0;
+ int is_wow_enabled;
+
+ tp_wma_handle wma = vos_get_context(VOS_MODULE_ID_WDA,
+ vos_get_global_context(VOS_MODULE_ID_VOSS, NULL));
+
+ if (!wma)
+ return -EINVAL;
+
+ is_wow_enabled = wma_is_wow_mode_selected(wma);
+ if (is_wow_enabled)
+ ret = wma_enable_wow_in_fw(wma, 0);
+ else
+ ret = wma_suspend_target(wma, 0);
+
+ if (ret) {
+ pr_err("%s: %s suspend failed\n", __func__,
+ is_wow_enabled ? "wow" : "pdev");
+ return ret;
+ }
+
+ pr_debug("%s: %s suspend successful\n", __func__,
+ is_wow_enabled ? "wow" : "pdev");
+
+ return ret;
+}
+
+/*
+ * wma_resume_fw() - API to resume FW
+ *
+ * The API will be called only for SDIO driver from HDD, for other drivers
+ * by default HIF return failure, FW resume happens in bus resume callbacks.
+ *
+ * Return : int
+ */
+
+
+int wma_resume_fw(void)
+{
+ int ret = 0;
+ int is_wow_enabled;
+
+ tp_wma_handle wma = vos_get_context(VOS_MODULE_ID_WDA,
+ vos_get_global_context(VOS_MODULE_ID_VOSS, NULL));
+
+ if (!wma)
+ return -EINVAL;
+
+ is_wow_enabled = wma_is_wow_mode_selected(wma);
+ if (is_wow_enabled)
+ ret = wma_disable_wow_in_fw(wma, 0);
+ else
+ ret = wma_resume_target(wma, 0);
+
+ if (ret) {
+ pr_err("%s: %s resume failed\n", __func__,
+ is_wow_enabled ? "wow" : "pdev");
+ return ret;
+ }
+
+ pr_debug("%s: %s resume successful\n", __func__,
+ is_wow_enabled ? "wow" : "pdev");
+
+ return ret;
+}
diff --git a/CORE/SERVICES/WMA/wma.h b/CORE/SERVICES/WMA/wma.h
index 499176c09e42..17c87c8aea7f 100644
--- a/CORE/SERVICES/WMA/wma.h
+++ b/CORE/SERVICES/WMA/wma.h
@@ -1676,6 +1676,15 @@ static inline void wma_set_wifi_start_packet_stats(void *wma_handle,
}
#endif
+/* API's to enable HDD to suspsend FW.
+ * This are active only if Bus Layer aggreed to suspend.
+ * This will be called for only for SDIO driver, for others
+ * by default HIF return failure, as we suspend FW in bus
+ * suspend callbacks
+ */
+int wma_suspend_fw(void);
+int wma_resume_fw(void);
+
void wma_send_flush_logs_to_fw(tp_wma_handle wma_handle);
struct wma_txrx_node *wma_get_interface_by_vdev_id(uint8_t vdev_id);
bool wma_is_vdev_up(uint8_t vdev_id);