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
This commit is contained in:
Will Huang
2018-06-26 10:53:59 +08:00
committed by nshrivas
parent fe1ee41cd8
commit d6c3b87fcd
3 changed files with 36 additions and 9 deletions

View File

@@ -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;
} }

View File

@@ -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));

View File

@@ -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) static inline bool hif_napi_schedule(struct hif_opaque_softc *hif, int ce_id)
{ return 0; } { 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; }