Răsfoiți Sursa

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
Rajeev Kumar 8 ani în urmă
părinte
comite
9bb2e85aff

+ 2 - 0
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);

+ 22 - 0
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 */

+ 157 - 0
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

+ 4 - 36
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;

+ 3 - 0
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