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:
@@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_id: ce_id
|
||||
@@ -422,7 +444,7 @@ irqreturn_t ce_dispatch_interrupt(int ce_id,
|
||||
if (hif_napi_enabled(hif_hdl, ce_id))
|
||||
hif_napi_schedule(hif_hdl, ce_id);
|
||||
else
|
||||
tasklet_schedule(&tasklet_entry->intr_tq);
|
||||
hif_tasklet_schedule(hif_hdl, tasklet_entry);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@@ -750,17 +750,14 @@ inline void hif_napi_enable_irq(struct hif_opaque_softc *hif, int id)
|
||||
* @scn: hif context
|
||||
* @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();
|
||||
struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
|
||||
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];
|
||||
if (qdf_unlikely(!napii)) {
|
||||
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;
|
||||
}
|
||||
|
||||
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++;
|
||||
NAPI_DEBUG("scheduling napi %d (ce:%d)", napii->id, ce_id);
|
||||
napi_schedule(&(napii->napi));
|
||||
|
@@ -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);
|
||||
|
||||
/* 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 */
|
||||
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)
|
||||
{ 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)
|
||||
{ return -EPERM; }
|
||||
|
Reference in New Issue
Block a user