ice: Fix bugs in control queue processing
This patch is a consolidation of multiple bug fixes for control queue processing. 1) In ice_clean_adminq_subtask() remove unnecessary reads/writes to registers. The bits PFINT_FW_CTL, PFINT_MBX_CTL and PFINT_SB_CTL are not set when an interrupt arrives, which means that clearing them again can be omitted. 2) Get an accurate value in "pending" by re-reading the control queue head register from the hardware. 3) Fix a corner case involving lost control queue messages by checking for new control messages (using ice_ctrlq_pending) before exiting the cleanup routine. Signed-off-by: Anirudh Venkataramanan <anirudh.venkataramanan@intel.com> Tested-by: Tony Brelinski <tonyx.brelinski@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
parent
b29bc220e2
commit
3d6b640efc
2 changed files with 26 additions and 5 deletions
|
@ -1065,8 +1065,11 @@ ice_clean_rq_elem(struct ice_hw *hw, struct ice_ctl_q_info *cq,
|
|||
|
||||
clean_rq_elem_out:
|
||||
/* Set pending if needed, unlock and return */
|
||||
if (pending)
|
||||
if (pending) {
|
||||
/* re-read HW head to calculate actual pending messages */
|
||||
ntu = (u16)(rd32(hw, cq->rq.head) & cq->rq.head_mask);
|
||||
*pending = (u16)((ntc > ntu ? cq->rq.count : 0) + (ntu - ntc));
|
||||
}
|
||||
clean_rq_elem_err:
|
||||
mutex_unlock(&cq->rq_lock);
|
||||
|
||||
|
|
|
@ -916,6 +916,21 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type)
|
|||
return pending && (i == ICE_DFLT_IRQ_WORK);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_ctrlq_pending - check if there is a difference between ntc and ntu
|
||||
* @hw: pointer to hardware info
|
||||
* @cq: control queue information
|
||||
*
|
||||
* returns true if there are pending messages in a queue, false if there aren't
|
||||
*/
|
||||
static bool ice_ctrlq_pending(struct ice_hw *hw, struct ice_ctl_q_info *cq)
|
||||
{
|
||||
u16 ntu;
|
||||
|
||||
ntu = (u16)(rd32(hw, cq->rq.head) & cq->rq.head_mask);
|
||||
return cq->rq.next_to_clean != ntu;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_clean_adminq_subtask - clean the AdminQ rings
|
||||
* @pf: board private structure
|
||||
|
@ -923,7 +938,6 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type)
|
|||
static void ice_clean_adminq_subtask(struct ice_pf *pf)
|
||||
{
|
||||
struct ice_hw *hw = &pf->hw;
|
||||
u32 val;
|
||||
|
||||
if (!test_bit(__ICE_ADMINQ_EVENT_PENDING, pf->state))
|
||||
return;
|
||||
|
@ -933,9 +947,13 @@ static void ice_clean_adminq_subtask(struct ice_pf *pf)
|
|||
|
||||
clear_bit(__ICE_ADMINQ_EVENT_PENDING, pf->state);
|
||||
|
||||
/* re-enable Admin queue interrupt causes */
|
||||
val = rd32(hw, PFINT_FW_CTL);
|
||||
wr32(hw, PFINT_FW_CTL, (val | PFINT_FW_CTL_CAUSE_ENA_M));
|
||||
/* There might be a situation where new messages arrive to a control
|
||||
* queue between processing the last message and clearing the
|
||||
* EVENT_PENDING bit. So before exiting, check queue head again (using
|
||||
* ice_ctrlq_pending) and process new messages if any.
|
||||
*/
|
||||
if (ice_ctrlq_pending(hw, &hw->adminq))
|
||||
__ice_clean_ctrlq(pf, ICE_CTL_Q_ADMIN);
|
||||
|
||||
ice_flush(hw);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue