Skip to content

Commit 0c1683c

Browse files
jahay1anguy11
authored andcommitted
idpf: trigger SW interrupt when exiting wb_on_itr mode
There is a race condition between exiting wb_on_itr and completion write backs. For example, we are in wb_on_itr mode and a Tx completion is generated by HW, ready to be written back, as we are re-enabling interrupts: HW SW | | | | idpf_tx_splitq_clean_all | | napi_complete_done | | | tx_completion_wb | idpf_vport_intr_update_itr_ena_irq That tx_completion_wb happens before the vector is fully re-enabled. Continuing with this example, it is a UDP stream and the tx_completion_wb is the last one in the flow (there are no rx packets). Because the HW generated the completion before the interrupt is fully enabled, the HW will not fire the interrupt once the timer expires and the write back will not happen. NAPI poll won't be called. We have indicated we're back in interrupt mode but nothing else will trigger the interrupt. Therefore, the completion goes unprocessed, triggering a Tx timeout. To mitigate this, fire a SW triggered interrupt upon exiting wb_on_itr. This interrupt will catch the rogue completion and avoid the timeout. Add logic to set the appropriate bits in the vector's dyn_ctl register. Fixes: 9c4a27d ("idpf: enable WB_ON_ITR") Reviewed-by: Madhu Chittim <[email protected]> Signed-off-by: Joshua Hay <[email protected]> Tested-by: Krishneil Singh <[email protected]> Signed-off-by: Tony Nguyen <[email protected]>
1 parent 93433c1 commit 0c1683c

File tree

1 file changed

+19
-10
lines changed

1 file changed

+19
-10
lines changed

drivers/net/ethernet/intel/idpf/idpf_txrx.c

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3604,21 +3604,31 @@ static void idpf_vport_intr_dis_irq_all(struct idpf_vport *vport)
36043604
/**
36053605
* idpf_vport_intr_buildreg_itr - Enable default interrupt generation settings
36063606
* @q_vector: pointer to q_vector
3607-
* @type: itr index
3608-
* @itr: itr value
36093607
*/
3610-
static u32 idpf_vport_intr_buildreg_itr(struct idpf_q_vector *q_vector,
3611-
const int type, u16 itr)
3608+
static u32 idpf_vport_intr_buildreg_itr(struct idpf_q_vector *q_vector)
36123609
{
3613-
u32 itr_val;
3610+
u32 itr_val = q_vector->intr_reg.dyn_ctl_intena_m;
3611+
int type = IDPF_NO_ITR_UPDATE_IDX;
3612+
u16 itr = 0;
3613+
3614+
if (q_vector->wb_on_itr) {
3615+
/*
3616+
* Trigger a software interrupt when exiting wb_on_itr, to make
3617+
* sure we catch any pending write backs that might have been
3618+
* missed due to interrupt state transition.
3619+
*/
3620+
itr_val |= q_vector->intr_reg.dyn_ctl_swint_trig_m |
3621+
q_vector->intr_reg.dyn_ctl_sw_itridx_ena_m;
3622+
type = IDPF_SW_ITR_UPDATE_IDX;
3623+
itr = IDPF_ITR_20K;
3624+
}
36143625

36153626
itr &= IDPF_ITR_MASK;
36163627
/* Don't clear PBA because that can cause lost interrupts that
36173628
* came in while we were cleaning/polling
36183629
*/
3619-
itr_val = q_vector->intr_reg.dyn_ctl_intena_m |
3620-
(type << q_vector->intr_reg.dyn_ctl_itridx_s) |
3621-
(itr << (q_vector->intr_reg.dyn_ctl_intrvl_s - 1));
3630+
itr_val |= (type << q_vector->intr_reg.dyn_ctl_itridx_s) |
3631+
(itr << (q_vector->intr_reg.dyn_ctl_intrvl_s - 1));
36223632

36233633
return itr_val;
36243634
}
@@ -3716,9 +3726,8 @@ void idpf_vport_intr_update_itr_ena_irq(struct idpf_q_vector *q_vector)
37163726
/* net_dim() updates ITR out-of-band using a work item */
37173727
idpf_net_dim(q_vector);
37183728

3729+
intval = idpf_vport_intr_buildreg_itr(q_vector);
37193730
q_vector->wb_on_itr = false;
3720-
intval = idpf_vport_intr_buildreg_itr(q_vector,
3721-
IDPF_NO_ITR_UPDATE_IDX, 0);
37223731

37233732
writel(intval, q_vector->intr_reg.dyn_ctl);
37243733
}

0 commit comments

Comments
 (0)