qcacld-3.0: Power offload unit test framework enhancements
Recently host power offload suspend/resume has switched to 3
stage process. Enhance power offload unit test framework accordingly,
and improve error handling.
Change-Id: I8cc1e955fbaca631ee7fd76b0c907d1e68c836bf
CRs-Fixed: 1072423
diff --git a/core/hdd/src/wlan_hdd_power.c b/core/hdd/src/wlan_hdd_power.c
index 7e82be6..26e5f66 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 @@
}
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