| From foo@baz Tue Oct 2 04:59:29 PDT 2018 |
| From: Anirudh Venkataramanan <anirudh.venkataramanan@intel.com> |
| Date: Thu, 9 Aug 2018 06:28:56 -0700 |
| Subject: ice: Fix bugs in control queue processing |
| |
| From: Anirudh Venkataramanan <anirudh.venkataramanan@intel.com> |
| |
| [ Upstream commit 3d6b640efcc1b07709b42dd2e9609401c6f88633 ] |
| |
| 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> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/ethernet/intel/ice/ice_controlq.c | 5 ++++- |
| drivers/net/ethernet/intel/ice/ice_main.c | 26 ++++++++++++++++++++++---- |
| 2 files changed, 26 insertions(+), 5 deletions(-) |
| |
| --- a/drivers/net/ethernet/intel/ice/ice_controlq.c |
| +++ b/drivers/net/ethernet/intel/ice/ice_controlq.c |
| @@ -1065,8 +1065,11 @@ ice_clean_rq_elem(struct ice_hw *hw, str |
| |
| 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); |
| |
| --- a/drivers/net/ethernet/intel/ice/ice_main.c |
| +++ b/drivers/net/ethernet/intel/ice/ice_main.c |
| @@ -917,13 +917,27 @@ static int __ice_clean_ctrlq(struct ice_ |
| } |
| |
| /** |
| + * 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 |
| */ |
| 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(str |
| |
| 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); |
| } |