summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/hdd/inc/wlan_hdd_driver_ops.h2
-rw-r--r--core/hdd/inc/wlan_hdd_power.h22
-rw-r--r--core/hdd/src/wlan_hdd_power.c157
-rw-r--r--core/hdd/src/wlan_hdd_wext.c40
-rw-r--r--core/pld/inc/pld_common.h3
5 files changed, 188 insertions, 36 deletions
diff --git a/core/hdd/inc/wlan_hdd_driver_ops.h b/core/hdd/inc/wlan_hdd_driver_ops.h
index 3ea44449b55c..f919e8decf1c 100644
--- a/core/hdd/inc/wlan_hdd_driver_ops.h
+++ b/core/hdd/inc/wlan_hdd_driver_ops.h
@@ -38,7 +38,9 @@
int wlan_hdd_register_driver(void);
void wlan_hdd_unregister_driver(void);
int wlan_hdd_bus_suspend(pm_message_t state);
+int wlan_hdd_bus_suspend_noirq(void);
int wlan_hdd_bus_resume(void);
+int wlan_hdd_bus_resume_noirq(void);
void hdd_hif_close(void *hif_ctx);
int hdd_hif_open(struct device *dev, void *bdev, const hif_bus_id *bid,
enum qdf_bus_type bus_type, bool reinit);
diff --git a/core/hdd/inc/wlan_hdd_power.h b/core/hdd/inc/wlan_hdd_power.h
index e173d4f517db..61f4d6d490c9 100644
--- a/core/hdd/inc/wlan_hdd_power.h
+++ b/core/hdd/inc/wlan_hdd_power.h
@@ -200,4 +200,26 @@ void hdd_wlan_suspend_resume_event(uint8_t state) {}
#endif /* FEATURE_WLAN_DIAG_SUPPORT */
+/*
+ * Unit-test suspend/resume is a testing feature that allows putting firmware
+ * into WoW suspend irrespective of Apps suspend status. It emulates the chain
+ * of events that occur durring normal system-level suspend/resume, such as
+ * initiating all of the suspend/resume stages in the correct order, and
+ * enabling/disabling appropriate copy engine irqs.
+ */
+#ifdef WLAN_SUSPEND_RESUME_TEST
+int hdd_wlan_fake_apps_resume(struct wiphy *wiphy);
+int hdd_wlan_fake_apps_suspend(struct wiphy *wiphy);
+#else
+static inline int hdd_wlan_fake_apps_resume(struct wiphy *wiphy)
+{
+ return 0;
+}
+
+static inline int hdd_wlan_fake_apps_suspend(struct wiphy *wiphy)
+{
+ return 0;
+}
+#endif /* WLAN_SUSPEND_RESUME_TEST */
+
#endif /* __WLAN_HDD_POWER_H */
diff --git a/core/hdd/src/wlan_hdd_power.c b/core/hdd/src/wlan_hdd_power.c
index 7e82be6f9ae7..26e5f6641987 100644
--- a/core/hdd/src/wlan_hdd_power.c
+++ b/core/hdd/src/wlan_hdd_power.c
@@ -74,6 +74,7 @@
#include "cds_concurrency.h"
#include "cdp_txrx_flow_ctrl_v2.h"
#include "pld_common.h"
+#include "wlan_hdd_driver_ops.h"
/* Preprocessor definitions and constants */
#define HDD_SSR_BRING_UP_TIME 30000
@@ -2349,3 +2350,159 @@ int hdd_set_qpower_config(hdd_context_t *hddctx, hdd_adapter_t *adapter,
}
return 0;
}
+
+#ifdef WLAN_SUSPEND_RESUME_TEST
+/*
+ * On Rome/iHelium there are 12 CE irqs and #2 is the wake irq. This may not be
+ * a valid assumption on future platforms.
+ */
+#define CE_IRQ_COUNT 12
+#define CE_WAKE_IRQ 2
+static struct wiphy *g_wiphy;
+
+#define HDD_FA_SUSPENDED_BIT (0)
+static unsigned long fake_apps_state;
+
+static int __hdd_wlan_fake_apps_resume(struct wiphy *wiphy);
+
+/**
+ * hdd_wlan_fake_apps_resume_irq_callback() - Irq callback function for resuming
+ * from unit-test initiated suspend from irq wakeup signal
+ * @val: interrupt val
+ *
+ * Resume wlan after getting very 1st CE interrupt from target
+ *
+ * Return: none
+ */
+static void hdd_wlan_fake_apps_resume_irq_callback(uint32_t val)
+{
+ hdd_info("Trigger unit-test resume WLAN; val: 0x%x", val);
+
+ QDF_BUG(g_wiphy);
+ __hdd_wlan_fake_apps_resume(g_wiphy);
+ g_wiphy = NULL;
+}
+
+/**
+ * hdd_wlan_fake_apps_suspend() - Initiate a unit-test triggered suspend
+ * @wiphy: wiphy struct from a validated hdd context
+ *
+ * Return: Zero on success, suspend related non-zero error code on failure
+ */
+int hdd_wlan_fake_apps_suspend(struct wiphy *wiphy)
+{
+ qdf_device_t qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
+ struct hif_opaque_softc *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
+ pm_message_t state;
+ int i, resume_err, suspend_err;
+
+ hdd_info("Unit-test suspend WLAN");
+ if (test_and_set_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) {
+ hdd_info("Already unit-test suspended; Nothing to do");
+ return 0;
+ }
+
+ suspend_err = wlan_hdd_cfg80211_suspend_wlan(wiphy, NULL);
+ if (suspend_err)
+ goto resume_done;
+
+ state.event = PM_EVENT_SUSPEND;
+ suspend_err = wlan_hdd_bus_suspend(state);
+ if (suspend_err)
+ goto cfg80211_resume;
+
+ /* simulate kernel disabling irqs */
+ for (i = 0; i < CE_IRQ_COUNT; i++)
+ pld_disable_irq(qdf_dev->dev, i);
+
+ suspend_err = wlan_hdd_bus_suspend_noirq();
+ if (suspend_err)
+ goto enable_irqs_and_bus_resume;
+
+ /* re-enable wake irq */
+ pld_enable_irq(qdf_dev->dev, CE_WAKE_IRQ);
+
+ /* pass wiphy to callback via global variable */
+ g_wiphy = wiphy;
+ hif_fake_apps_suspend(hif_ctx, hdd_wlan_fake_apps_resume_irq_callback);
+
+ return 0;
+
+enable_irqs_and_bus_resume:
+ /* re-enable irqs */
+ for (i = 0; i < CE_IRQ_COUNT; i++)
+ pld_enable_irq(qdf_dev->dev, i);
+
+ resume_err = wlan_hdd_bus_resume();
+ QDF_BUG(resume_err == 0);
+
+cfg80211_resume:
+ resume_err = wlan_hdd_cfg80211_resume_wlan(wiphy);
+ QDF_BUG(resume_err == 0);
+
+resume_done:
+ clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state);
+ hdd_err("Unit-test suspend failed: %d", suspend_err);
+ return suspend_err;
+}
+
+/**
+ * hdd_wlan_fake_apps_resume() - Resume from unit-test triggered suspend
+ * @wiphy: wiphy struct from a validated hdd context
+ *
+ * Return: Zero on success, calls QDF_BUG() on failure
+ */
+int hdd_wlan_fake_apps_resume(struct wiphy *wiphy)
+{
+ struct hif_opaque_softc *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
+ int err;
+
+ hif_fake_apps_resume(hif_ctx);
+ err = __hdd_wlan_fake_apps_resume(wiphy);
+ if (err) {
+ hif_fake_apps_suspend(hif_ctx,
+ hdd_wlan_fake_apps_resume_irq_callback);
+ return err;
+ }
+
+ return 0;
+}
+
+/**
+ * __hdd_wlan_fake_apps_resume() - The core logic for
+ * hdd_wlan_fake_apps_resume() skipping the call to hif_fake_apps_resume(),
+ * which is only need for non-irq resume
+ * @wiphy: wiphy struct from a validated hdd context
+ *
+ * Return: Zero on success, calls QDF_BUG() on failure
+ */
+static int __hdd_wlan_fake_apps_resume(struct wiphy *wiphy)
+{
+ qdf_device_t qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
+ int i, resume_err;
+
+ hdd_info("Unit-test resume WLAN");
+ if (!test_and_clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) {
+ hdd_info("Not unit-test suspended; Nothing to do");
+ return 0;
+ }
+
+ /* disable wake irq */
+ pld_disable_irq(qdf_dev->dev, CE_WAKE_IRQ);
+
+ resume_err = wlan_hdd_bus_resume_noirq();
+ QDF_BUG(resume_err == 0);
+
+ /* simulate kernel enable irqs */
+ for (i = 0; i < CE_IRQ_COUNT; i++)
+ pld_enable_irq(qdf_dev->dev, i);
+
+ resume_err = wlan_hdd_bus_resume();
+ QDF_BUG(resume_err == 0);
+
+ resume_err = wlan_hdd_cfg80211_resume_wlan(wiphy);
+ QDF_BUG(resume_err == 0);
+
+ return 0;
+}
+#endif
diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c
index 9992c4b41a8d..397bdcd2d019 100644
--- a/core/hdd/src/wlan_hdd_wext.c
+++ b/core/hdd/src/wlan_hdd_wext.c
@@ -92,6 +92,7 @@
#ifdef WLAN_SUSPEND_RESUME_TEST
#include "wlan_hdd_driver_ops.h"
#include "hif.h"
+#include "pld_common.h"
#endif
#define HDD_FINISH_ULA_TIME_OUT 800
@@ -439,10 +440,9 @@ static const hdd_freq_chan_map_t freq_chan_map[] = {
#define WE_ENABLE_FW_PROFILE 4
#define WE_SET_FW_PROFILE_HIST_INTVL 5
-#ifdef WLAN_SUSPEND_RESUME_TEST
+/* Private sub-ioctl for initiating WoW suspend without Apps suspend */
#define WE_SET_WLAN_SUSPEND 6
#define WE_SET_WLAN_RESUME 7
-#endif
/* (SIOCIWFIRSTPRIV + 29) is currently unused */
@@ -9782,25 +9782,6 @@ static int wlan_hdd_set_mon_chan(hdd_adapter_t *adapter, uint32_t chan,
return qdf_status_to_os_return(status);
}
-#ifdef WLAN_SUSPEND_RESUME_TEST
-static void *g_wiphy;
-
-/**
- * hdd_wlan_trigger_resume() - resume wlan
- * @val: interrupt val
- *
- * Resume wlan after getting very 1st CE interrupt from target
- *
- * Return: none
- */
-static void hdd_wlan_trigger_resume(uint32_t val)
-{
- hdd_err("Resume WLAN val 0x%x", val);
- wlan_hdd_bus_resume();
- wlan_hdd_cfg80211_resume_wlan(g_wiphy);
-}
-#endif
-
static int __iw_set_two_ints_getnone(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
@@ -9810,10 +9791,6 @@ static int __iw_set_two_ints_getnone(struct net_device *dev,
int sub_cmd = value[0];
int ret;
hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
-#ifdef WLAN_SUSPEND_RESUME_TEST
- pm_message_t state;
-#endif
-
ENTER_DEV(dev);
@@ -9877,21 +9854,12 @@ static int __iw_set_two_ints_getnone(struct net_device *dev,
case WE_SET_MON_MODE_CHAN:
ret = wlan_hdd_set_mon_chan(pAdapter, value[1], value[2]);
break;
-#ifdef WLAN_SUSPEND_RESUME_TEST
case WE_SET_WLAN_SUSPEND:
- hdd_err("Suspend WLAN");
- g_wiphy = hdd_ctx->wiphy;
- state.event = PM_EVENT_SUSPEND;
- ret = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL);
- wlan_hdd_bus_suspend(state);
- hif_fake_apps_suspend(hdd_wlan_trigger_resume);
+ ret = hdd_wlan_fake_apps_suspend(hdd_ctx->wiphy);
break;
case WE_SET_WLAN_RESUME:
- hdd_err("Resume WLAN");
- wlan_hdd_bus_resume();
- ret = wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy);
+ ret = hdd_wlan_fake_apps_resume(hdd_ctx->wiphy);
break;
-#endif
default:
hdd_err("Invalid IOCTL command %d", sub_cmd);
break;
diff --git a/core/pld/inc/pld_common.h b/core/pld/inc/pld_common.h
index bcf647b0b1a4..4bb77b27cb94 100644
--- a/core/pld/inc/pld_common.h
+++ b/core/pld/inc/pld_common.h
@@ -379,4 +379,7 @@ void *pld_smmu_get_mapping(struct device *dev);
int pld_smmu_map(struct device *dev, phys_addr_t paddr,
uint32_t *iova_addr, size_t size);
unsigned int pld_socinfo_get_serial_number(struct device *dev);
+
+void pld_enable_irq(struct device *dev, unsigned int ce_id);
+void pld_disable_irq(struct device *dev, unsigned int ce_id);
#endif