]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ice: fix VF interrupts cleanup
authorDawid Osuchowski <dawid.osuchowski@linux.intel.com>
Thu, 14 May 2026 16:35:55 +0000 (18:35 +0200)
committerTony Nguyen <anthony.l.nguyen@intel.com>
Tue, 28 Jul 2026 18:23:01 +0000 (11:23 -0700)
When a virtual function sends an IRQ map command, the PF will set up
interrupts according to that request. However, because these interrupts are
never reset, the next time Virtual Function initializes, the interrupts are
still enabled for a given VF, which leads to performance degradation in
certain cases due to interrupts being unexpectedly enabled and thus causing
interrupt floods.

Cc: stable@vger.kernel.org
Fixes: 1071a8358a28 ("ice: Implement virtchnl commands for AVF support")
Suggested-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Dawid Osuchowski <dawid.osuchowski@linux.intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Tested-by: Patryk Holda <patryk.holda@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
drivers/net/ethernet/intel/ice/ice_vf_lib.c
drivers/net/ethernet/intel/ice/ice_vf_lib_private.h
drivers/net/ethernet/intel/ice/virt/queues.c

index 9052e71e9c99e35b5a7a40a824b019a376b4833c..a54cb2b8d3c760f612b32e95acc66d5ab461f646 100644 (file)
@@ -848,6 +848,30 @@ static void ice_notify_vf_reset(struct ice_vf *vf)
                              NULL);
 }
 
+/**
+ * ice_reset_interrupts - clear all queue interrupt configuration for a VSI
+ * @vsi: the VSI whose interrupt registers should be cleared
+ *
+ * Zero the QINT_RQCTL and QINT_TQCTL registers for all allocated queues
+ * in the VSI. This clears the entire register including MSIX_INDX, ITR_INDX,
+ * CAUSE_ENA and NEXTQ fields, unlike ice_vf_dis_rxq_interrupt() which only
+ * clears the CAUSE_ENA bit.
+ */
+void ice_reset_interrupts(struct ice_vsi *vsi)
+{
+       struct ice_pf *pf = vsi->back;
+       struct ice_hw *hw = &pf->hw;
+       int i;
+
+       ice_for_each_alloc_rxq(vsi, i)
+               wr32(hw, QINT_RQCTL(vsi->rxq_map[i]), 0);
+
+       ice_for_each_alloc_txq(vsi, i)
+               wr32(hw, QINT_TQCTL(vsi->txq_map[i]), 0);
+
+       ice_flush(hw);
+}
+
 /**
  * ice_reset_vf - Reset a particular VF
  * @vf: pointer to the VF structure
@@ -919,6 +943,9 @@ int ice_reset_vf(struct ice_vf *vf, u32 flags)
 
        ice_dis_vf_qs(vf);
 
+       /* cleanup interrupt registers */
+       ice_reset_interrupts(vsi);
+
        /* Call Disable LAN Tx queue AQ whether or not queues are
         * enabled. This is needed for successful completion of VFR.
         */
index 5392b04049862148dcf7d67fe672863d22df5418..321d29c25b7c1822e89106305d4bc23c554d91ae 100644 (file)
@@ -26,6 +26,7 @@
 void ice_initialize_vf_entry(struct ice_vf *vf);
 void ice_deinitialize_vf_entry(struct ice_vf *vf);
 void ice_dis_vf_qs(struct ice_vf *vf);
+void ice_reset_interrupts(struct ice_vsi *vsi);
 int ice_check_vf_init(struct ice_vf *vf);
 enum virtchnl_status_code ice_err_to_virt_err(int err);
 struct ice_port_info *ice_vf_get_port_info(struct ice_vf *vf);
index 31be2f76181c07415b54f9fd04b489a5d488b51d..431c9c546b04fd1793c5518fd9e7144350e326bc 100644 (file)
@@ -224,6 +224,24 @@ void ice_vf_ena_rxq_interrupt(struct ice_vsi *vsi, u32 q_idx)
        wr32(hw, QINT_RQCTL(pfq), reg | QINT_RQCTL_CAUSE_ENA_M);
 }
 
+/**
+ * ice_vf_dis_rxq_interrupt - disable Rx queue interrupt via QINT_RQCTL
+ * @vsi: VSI of the VF to configure
+ * @q_idx: VF queue index used to determine the queue in the PF's space
+ */
+static void ice_vf_dis_rxq_interrupt(struct ice_vsi *vsi, u32 q_idx)
+{
+       struct ice_hw *hw = &vsi->back->hw;
+       u32 pfq = vsi->rxq_map[q_idx];
+       u32 reg;
+
+       reg = rd32(hw, QINT_RQCTL(pfq));
+       reg &= ~QINT_RQCTL_CAUSE_ENA_M;
+       wr32(hw, QINT_RQCTL(pfq), reg);
+
+       ice_flush(hw);
+}
+
 /**
  * ice_vc_ena_qs_msg
  * @vf: pointer to the VF info
@@ -416,6 +434,8 @@ int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg)
                        goto error_param;
                }
 
+               for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF)
+                       ice_vf_dis_rxq_interrupt(vsi, vf_q_id);
                bitmap_zero(vf->rxq_ena, ICE_MAX_RSS_QS_PER_VF);
        } else if (q_map) {
                for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) {
@@ -436,6 +456,7 @@ int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg)
                                goto error_param;
                        }
 
+                       ice_vf_dis_rxq_interrupt(vsi, vf_q_id);
                        /* Clear enabled queues flag */
                        clear_bit(vf_q_id, vf->rxq_ena);
                }