Просмотр исходного кода

qcacmn: Fix active_tasklet_cnt mismatch issue

Issue can be reproduced when test D0WOW ROME PCIE.
Multi interrupts may only trigger tasklet one time,
which will cause active_tasklet_cnt mismatch.

Check tasklet/napi scheduled state

Change-Id: I66b5544c4d57fe91eae75d4cf8578e30b498e1fd
CRs-Fixed: 2070872
Will Huang 6 лет назад
Родитель
Сommit
d6c3b87fcd
3 измененных файлов с 36 добавлено и 9 удалено
  1. 23 1
      hif/src/ce/ce_tasklet.c
  2. 10 5
      hif/src/hif_napi.c
  3. 3 3
      hif/src/hif_napi.h

+ 23 - 1
hif/src/ce/ce_tasklet.c

@@ -377,6 +377,28 @@ void hif_clear_ce_stats(struct HIF_CE_state *hif_ce_state)
 	qdf_mem_zero(&hif_ce_state->stats, sizeof(struct ce_stats));
 	qdf_mem_zero(&hif_ce_state->stats, sizeof(struct ce_stats));
 }
 }
 
 
+/**
+ * hif_tasklet_schedule() - schedule tasklet
+ * @hif_ctx: hif context
+ * @tasklet_entry: ce tasklet entry
+ *
+ * Return: false if tasklet already scheduled, otherwise true
+ */
+static inline bool hif_tasklet_schedule(struct hif_opaque_softc *hif_ctx,
+					struct ce_tasklet_entry *tasklet_entry)
+{
+	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
+
+	if (test_bit(TASKLET_STATE_SCHED, &tasklet_entry->intr_tq.state)) {
+		HIF_DBG("tasklet scheduled, return");
+		qdf_atomic_dec(&scn->active_tasklet_cnt);
+		return false;
+	}
+
+	tasklet_schedule(&tasklet_entry->intr_tq);
+	return true;
+}
+
 /**
 /**
  * ce_dispatch_interrupt() - dispatch an interrupt to a processing context
  * ce_dispatch_interrupt() - dispatch an interrupt to a processing context
  * @ce_id: ce_id
  * @ce_id: ce_id
@@ -422,7 +444,7 @@ irqreturn_t ce_dispatch_interrupt(int ce_id,
 	if (hif_napi_enabled(hif_hdl, ce_id))
 	if (hif_napi_enabled(hif_hdl, ce_id))
 		hif_napi_schedule(hif_hdl, ce_id);
 		hif_napi_schedule(hif_hdl, ce_id);
 	else
 	else
-		tasklet_schedule(&tasklet_entry->intr_tq);
+		hif_tasklet_schedule(hif_hdl, tasklet_entry);
 
 
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
 }
 }

+ 10 - 5
hif/src/hif_napi.c

@@ -750,17 +750,14 @@ inline void hif_napi_enable_irq(struct hif_opaque_softc *hif, int id)
  * @scn:  hif context
  * @scn:  hif context
  * @ce_id: index of napi instance
  * @ce_id: index of napi instance
  *
  *
- * Return: void
+ * Return: false if napi didn't enable or already scheduled, otherwise true
  */
  */
-int hif_napi_schedule(struct hif_opaque_softc *hif_ctx, int ce_id)
+bool hif_napi_schedule(struct hif_opaque_softc *hif_ctx, int ce_id)
 {
 {
 	int cpu = smp_processor_id();
 	int cpu = smp_processor_id();
 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
 	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
 	struct qca_napi_info *napii;
 	struct qca_napi_info *napii;
 
 
-	hif_record_ce_desc_event(scn,  ce_id, NAPI_SCHEDULE,
-				 NULL, NULL, 0, 0);
-
 	napii = scn->napi_data.napis[ce_id];
 	napii = scn->napi_data.napis[ce_id];
 	if (qdf_unlikely(!napii)) {
 	if (qdf_unlikely(!napii)) {
 		HIF_ERROR("%s, scheduling unallocated napi (ce:%d)",
 		HIF_ERROR("%s, scheduling unallocated napi (ce:%d)",
@@ -769,6 +766,14 @@ int hif_napi_schedule(struct hif_opaque_softc *hif_ctx, int ce_id)
 		return false;
 		return false;
 	}
 	}
 
 
+	if (test_bit(NAPI_STATE_SCHED, &napii->napi.state)) {
+		NAPI_DEBUG("napi scheduled, return");
+		qdf_atomic_dec(&scn->active_tasklet_cnt);
+		return false;
+	}
+
+	hif_record_ce_desc_event(scn,  ce_id, NAPI_SCHEDULE,
+				 NULL, NULL, 0, 0);
 	napii->stats[cpu].napi_schedules++;
 	napii->stats[cpu].napi_schedules++;
 	NAPI_DEBUG("scheduling napi %d (ce:%d)", napii->id, ce_id);
 	NAPI_DEBUG("scheduling napi %d (ce:%d)", napii->id, ce_id);
 	napi_schedule(&(napii->napi));
 	napi_schedule(&(napii->napi));

+ 3 - 3
hif/src/hif_napi.h

@@ -168,7 +168,7 @@ bool hif_napi_created(struct hif_opaque_softc *hif, int ce);
 void hif_napi_enable_irq(struct hif_opaque_softc *hif, int id);
 void hif_napi_enable_irq(struct hif_opaque_softc *hif, int id);
 
 
 /* called by ce_tasklet.c::ce_dispatch_interrupt*/
 /* called by ce_tasklet.c::ce_dispatch_interrupt*/
-int hif_napi_schedule(struct hif_opaque_softc *scn, int ce_id);
+bool hif_napi_schedule(struct hif_opaque_softc *scn, int ce_id);
 
 
 /* called by hdd_napi, which is called by kernel */
 /* called by hdd_napi, which is called by kernel */
 int hif_napi_poll(struct hif_opaque_softc *hif_ctx,
 int hif_napi_poll(struct hif_opaque_softc *hif_ctx,
@@ -253,8 +253,8 @@ static inline bool hif_napi_created(struct hif_opaque_softc *hif, int ce)
 static inline void hif_napi_enable_irq(struct hif_opaque_softc *hif, int id)
 static inline void hif_napi_enable_irq(struct hif_opaque_softc *hif, int id)
 { return; }
 { return; }
 
 
-static inline int hif_napi_schedule(struct hif_opaque_softc *hif, int ce_id)
-{ return 0; }
+static inline bool hif_napi_schedule(struct hif_opaque_softc *hif, int ce_id)
+{ return false; }
 
 
 static inline int hif_napi_poll(struct napi_struct *napi, int budget)
 static inline int hif_napi_poll(struct napi_struct *napi, int budget)
 { return -EPERM; }
 { return -EPERM; }