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));
|
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;
|
||||||
}
|
}
|
||||||
|
@@ -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));
|
||||||
|
@@ -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; }
|
||||||
|
Reference in New Issue
Block a user