瀏覽代碼

qcacmn: 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. This is a companion change for
I8cc1e955fbaca631ee7fd76b0c907d1e68c836bf in qcacld-3.0.

Change-Id: I8c4e062d4a51a7a245500bc135571fc67cf1b4d0
CRs-Fixed: 1072424
Dustin Brown 8 年之前
父節點
當前提交
6bdbda50fb
共有 4 個文件被更改,包括 122 次插入49 次删除
  1. 4 2
      hif/inc/hif.h
  2. 12 0
      hif/src/ce/ce_main.c
  3. 86 47
      hif/src/ce/ce_tasklet.c
  4. 20 0
      hif/src/hif_main.h

+ 4 - 2
hif/inc/hif.h

@@ -724,8 +724,10 @@ void hif_set_bundle_mode(struct hif_opaque_softc *scn, bool enabled,
 int hif_bus_reset_resume(struct hif_opaque_softc *scn);
 
 #ifdef WLAN_SUSPEND_RESUME_TEST
-typedef void (*hdd_fake_resume_callback)(uint32_t val);
-void hif_fake_apps_suspend(hdd_fake_resume_callback callback);
+typedef void (*hif_fake_resume_callback)(uint32_t val);
+void hif_fake_apps_suspend(struct hif_opaque_softc *hif_ctx,
+			   hif_fake_resume_callback callback);
+void hif_fake_apps_resume(struct hif_opaque_softc *hif_ctx);
 #endif
 
 uint32_t hif_register_ext_group_int_handler(struct hif_opaque_softc *hif_ctx,

+ 12 - 0
hif/src/ce/ce_main.c

@@ -2155,6 +2155,16 @@ static inline void hif_post_static_buf_to_target(struct hif_softc *scn)
 }
 #endif
 
+#ifdef WLAN_SUSPEND_RESUME_TEST
+static void hif_fake_apps_init_ctx(struct hif_softc *scn)
+{
+	INIT_WORK(&scn->fake_apps_ctx.resume_work,
+		  hif_fake_apps_resume_work);
+}
+#else
+static inline void hif_fake_apps_init_ctx(struct hif_softc *scn) {}
+#endif
+
 /**
  * hif_config_ce() - configure copy engines
  * @scn: hif context
@@ -2240,6 +2250,7 @@ int hif_config_ce(struct hif_softc *scn)
 	HIF_INFO_MED("%s: ce_init done", __func__);
 
 	init_tasklet_workers(hif_hdl);
+	hif_fake_apps_init_ctx(scn);
 
 	HIF_TRACE("%s: X, ret = %d", __func__, rv);
 
@@ -2990,3 +3001,4 @@ void hif_wlan_disable(struct hif_softc *scn)
 
 	pld_wlan_disable(scn->qdf_dev->dev, mode);
 }
+

+ 86 - 47
hif/src/ce/ce_tasklet.c

@@ -253,11 +253,12 @@ void ce_tasklet_kill(struct hif_softc *scn)
 int hif_drain_tasklets(struct hif_softc *scn)
 {
 	uint32_t ce_drain_wait_cnt = 0;
+	int32_t tasklet_cnt;
 
-	while (qdf_atomic_read(&scn->active_tasklet_cnt)) {
+	while ((tasklet_cnt = qdf_atomic_read(&scn->active_tasklet_cnt))) {
 		if (++ce_drain_wait_cnt > HIF_CE_DRAIN_WAIT_CNT) {
-			HIF_ERROR("%s: CE still not done with access",
-			       __func__);
+			HIF_ERROR("%s: CE still not done with access: %d",
+				  __func__, tasklet_cnt);
 
 			return -EFAULT;
 		}
@@ -267,55 +268,81 @@ int hif_drain_tasklets(struct hif_softc *scn)
 	return 0;
 }
 
-
-
 #ifdef WLAN_SUSPEND_RESUME_TEST
-static bool g_hif_apps_fake_suspended;
-static hdd_fake_resume_callback hdd_fake_apps_resume;
-
-static void hif_wlan_resume_work_handler(struct work_struct *work)
+/**
+ * hif_fake_apps_resume_work() - Work handler for fake apps resume callback
+ * @work:	The work struct being passed from the linux kernel
+ *
+ * Return: none
+ */
+void hif_fake_apps_resume_work(struct work_struct *work)
 {
-	hdd_fake_apps_resume(0);
-}
+	struct fake_apps_context *ctx =
+		container_of(work, struct fake_apps_context, resume_work);
 
-static DECLARE_WORK(hif_resume_work, hif_wlan_resume_work_handler);
+	QDF_BUG(ctx->resume_callback);
+	ctx->resume_callback(0);
+	ctx->resume_callback = NULL;
+}
 
 /**
- * hif_fake_apps_suspend(): Suspend WLAN
+ * hif_fake_apps_suspend(): Setup unit-test related suspend state. Call after
+ *	a normal WoW suspend has been completed.
+ * @hif_ctx:	The HIF context to operate on
+ * @callback:	The function to call when fake apps resume is triggered
  *
  * Set the fake suspend flag such that hif knows that it will need
- * to fake the apps resume process using the hdd_fake_apps_resume
+ * to fake the apps resume process using hdd_trigger_fake_apps_resume
+ *
+ * Return: none
+ */
+void hif_fake_apps_suspend(struct hif_opaque_softc *hif_ctx,
+			   hif_fake_resume_callback callback)
+{
+	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
+
+	scn->fake_apps_ctx.resume_callback = callback;
+	set_bit(HIF_FA_SUSPENDED_BIT, &scn->fake_apps_ctx.state);
+}
+
+/**
+ * hif_fake_apps_resume(): Cleanup unit-test related suspend state. Call before
+ *	doing a normal WoW resume if suspend was initiated via fake apps
+ *	suspend.
+ * @hif_ctx:	The HIF context to operate on
  *
  * Return: none
  */
-void hif_fake_apps_suspend(hdd_fake_resume_callback callback)
+void hif_fake_apps_resume(struct hif_opaque_softc *hif_ctx)
 {
-	hdd_fake_apps_resume = callback;
-	g_hif_apps_fake_suspended = true;
+	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
+
+	clear_bit(HIF_FA_SUSPENDED_BIT, &scn->fake_apps_ctx.state);
+	scn->fake_apps_ctx.resume_callback = NULL;
 }
 
 /**
- * hif_fake_apps_resume(): trigger WLAN resume if needed
- * @fid_hdl: hif context
- * @ce_id: copy engine Id
+ * hif_interrupt_is_fake_apps_resume(): Determines if the raised irq should
+ *	trigger a fake apps resume.
+ * @hif_ctx:	The HIF context to operate on
+ * @ce_id:	The copy engine Id from the originating interrupt
  *
- * Return: True if a fake apps resume has been been triggered,
- *         returns false if regular interrupt processing is needed.
- *	   Ensures copy engine Id matches mapped Irq
+ * Return: true if the raised irq should trigger a fake apps resume
  */
-static bool hif_fake_apps_resume(struct hif_opaque_softc *hif_hdl, int ce_id)
+static bool hif_interrupt_is_fake_apps_resume(struct hif_opaque_softc *hif_ctx,
+					      int ce_id)
 {
+	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
 	uint8_t ul_pipe, dl_pipe;
 	int ul_is_polled, dl_is_polled;
 	QDF_STATUS status;
 
-	/* can't resume if not already suspended */
-	if (!g_hif_apps_fake_suspended)
+	if (!test_bit(HIF_FA_SUSPENDED_BIT, &scn->fake_apps_ctx.state))
 		return false;
 
-	/* ensure passed copy engine Id matches Id from irq map */
-
-	status = hif_map_service_to_pipe(hif_hdl, HTC_CTRL_RSVD_SVC,
+	/* ensure passed ce_id matches wake irq */
+	/* dl_pipe will be populated with the wake irq number */
+	status = hif_map_service_to_pipe(hif_ctx, HTC_CTRL_RSVD_SVC,
 					 &ul_pipe, &dl_pipe,
 					 &ul_is_polled, &dl_is_polled);
 
@@ -324,29 +351,40 @@ static bool hif_fake_apps_resume(struct hif_opaque_softc *hif_hdl, int ce_id)
 		return false;
 	}
 
-	/* dl_pipe is equivalent to a copy engine Id at this point */
-	if (ce_id != dl_pipe)
-		return false;
-
-	/* trigger fake apps resume */
-	g_hif_apps_fake_suspended = false;
-	schedule_work(&hif_resume_work);
-	return true;
+	return ce_id == dl_pipe;
 }
 
-#else
-
 /**
- * hif_fake_apps_resume(): trigger WLAN resume if needed
- * @hif_hdl: hif context
- * @ce_id: copy engine Id
+ * hif_trigger_fake_apps_resume(): Trigger a fake apps resume by scheduling the
+ *	previously registered callback for execution
+ * @hif_ctx:	The HIF context to operate on
  *
- * Return: always false if WLAN_SUSPEND_RESUME_TEST is not defined
+ * Return: None
  */
-static bool hif_fake_apps_resume(struct hif_opaque_softc *hif_hdl, int ce_id)
+static void hif_trigger_fake_apps_resume(struct hif_opaque_softc *hif_ctx)
+{
+	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
+
+	if (!test_and_clear_bit(HIF_FA_SUSPENDED_BIT,
+				&scn->fake_apps_ctx.state))
+		return;
+
+	schedule_work(&scn->fake_apps_ctx.resume_work);
+}
+
+#else
+
+static inline bool
+hif_interrupt_is_fake_apps_resume(struct hif_opaque_softc *hif_ctx, int ce_id)
 {
 	return false;
 }
+
+static inline void
+hif_trigger_fake_apps_resume(struct hif_opaque_softc *hif_ctx)
+{
+}
+
 #endif /* End of WLAN_SUSPEND_RESUME_TEST */
 
 /**
@@ -447,16 +485,17 @@ irqreturn_t ce_dispatch_interrupt(int ce_id,
 		return IRQ_NONE;
 	}
 	hif_irq_disable(scn, ce_id);
-	qdf_atomic_inc(&scn->active_tasklet_cnt);
 	hif_record_ce_desc_event(scn, ce_id, HIF_IRQ_EVENT, NULL, NULL, 0);
 	hif_ce_increment_interrupt_count(hif_ce_state, ce_id);
 
-	if (unlikely(hif_fake_apps_resume(hif_hdl, ce_id))) {
-		HIF_ERROR("received resume interrupt");
+	if (unlikely(hif_interrupt_is_fake_apps_resume(hif_hdl, ce_id))) {
+		hif_trigger_fake_apps_resume(hif_hdl);
 		hif_irq_enable(scn, ce_id);
 		return IRQ_HANDLED;
 	}
 
+	qdf_atomic_inc(&scn->active_tasklet_cnt);
+
 	if (hif_napi_enabled(hif_hdl, ce_id))
 		hif_napi_schedule(hif_hdl, ce_id);
 	else

+ 20 - 0
hif/src/hif_main.h

@@ -111,6 +111,22 @@ struct hif_ce_stats {
 	int ce_ring_delta_fail_count;
 };
 
+#ifdef WLAN_SUSPEND_RESUME_TEST
+struct fake_apps_context {
+	unsigned long state;
+	hif_fake_resume_callback resume_callback;
+	struct work_struct resume_work;
+};
+
+enum hif_fake_apps_state_bits {
+	HIF_FA_SUSPENDED_BIT = 0
+};
+
+void hif_fake_apps_resume_work(struct work_struct *work);
+#else
+static inline void hif_init_fake_apps_ctx(struct hif_softc *scn) {}
+#endif /* WLAN_SUSPEND_RESUME_TEST */
+
 struct hif_softc {
 	struct hif_opaque_softc osc;
 	struct hif_config_info hif_config;
@@ -156,6 +172,9 @@ struct hif_softc {
 	uint32_t nss_wifi_ol_mode;
 #endif
 	void *hal_soc;
+#ifdef WLAN_SUSPEND_RESUME_TEST
+	struct fake_apps_context fake_apps_ctx;
+#endif /* WLAN_SUSPEND_RESUME_TEST */
 };
 
 #ifdef QCA_NSS_WIFI_OFFLOAD_SUPPORT
@@ -224,4 +243,5 @@ static inline void hif_ramdump_handler(struct hif_opaque_softc *scn) {}
 #endif
 void hif_ext_grp_tasklet(unsigned long data);
 void hif_grp_tasklet_kill(struct hif_softc *scn);
+
 #endif /* __HIF_MAIN_H__ */