Commit 3d6b640e authored by Anirudh Venkataramanan's avatar Anirudh Venkataramanan Committed by Jeff Kirsher

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: default avatarAnirudh Venkataramanan <anirudh.venkataramanan@intel.com>
Tested-by: default avatarTony Brelinski <tonyx.brelinski@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent b29bc220
...@@ -1065,8 +1065,11 @@ ice_clean_rq_elem(struct ice_hw *hw, struct ice_ctl_q_info *cq, ...@@ -1065,8 +1065,11 @@ ice_clean_rq_elem(struct ice_hw *hw, struct ice_ctl_q_info *cq,
clean_rq_elem_out: clean_rq_elem_out:
/* Set pending if needed, unlock and return */ /* 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)); *pending = (u16)((ntc > ntu ? cq->rq.count : 0) + (ntu - ntc));
}
clean_rq_elem_err: clean_rq_elem_err:
mutex_unlock(&cq->rq_lock); mutex_unlock(&cq->rq_lock);
......
...@@ -916,6 +916,21 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type) ...@@ -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); 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 * ice_clean_adminq_subtask - clean the AdminQ rings
* @pf: board private structure * @pf: board private structure
...@@ -923,7 +938,6 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type) ...@@ -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) static void ice_clean_adminq_subtask(struct ice_pf *pf)
{ {
struct ice_hw *hw = &pf->hw; struct ice_hw *hw = &pf->hw;
u32 val;
if (!test_bit(__ICE_ADMINQ_EVENT_PENDING, pf->state)) if (!test_bit(__ICE_ADMINQ_EVENT_PENDING, pf->state))
return; return;
...@@ -933,9 +947,13 @@ static void ice_clean_adminq_subtask(struct ice_pf *pf) ...@@ -933,9 +947,13 @@ static void ice_clean_adminq_subtask(struct ice_pf *pf)
clear_bit(__ICE_ADMINQ_EVENT_PENDING, pf->state); clear_bit(__ICE_ADMINQ_EVENT_PENDING, pf->state);
/* re-enable Admin queue interrupt causes */ /* There might be a situation where new messages arrive to a control
val = rd32(hw, PFINT_FW_CTL); * queue between processing the last message and clearing the
wr32(hw, PFINT_FW_CTL, (val | PFINT_FW_CTL_CAUSE_ENA_M)); * 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); ice_flush(hw);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment