ice: Prevent set_channel from changing queues while RDMA active
authorDave Ertman <david.m.ertman@intel.com>
Tue, 24 Jan 2023 17:19:43 +0000 (09:19 -0800)
committerTony Nguyen <anthony.l.nguyen@intel.com>
Fri, 27 Jan 2023 19:32:18 +0000 (11:32 -0800)
The PF controls the set of queues that the RDMA auxiliary_driver requests
resources from.  The set_channel command will alter that pool and trigger a
reconfiguration of the VSI, which breaks RDMA functionality.

Prevent set_channel from executing when RDMA driver bound to auxiliary
device.

Adding a locked variable to pass down the call chain to avoid double
locking the device_lock.

Fixes: 348048e724a0 ("ice: Implement iidc operations")
Signed-off-by: Dave Ertman <david.m.ertman@intel.com>
Tested-by: Gurucharan G <gurucharanx.g@intel.com> (A Contingent worker at Intel)
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
drivers/net/ethernet/intel/ice/ice.h
drivers/net/ethernet/intel/ice/ice_dcb_lib.c
drivers/net/ethernet/intel/ice/ice_dcb_lib.h
drivers/net/ethernet/intel/ice/ice_ethtool.c
drivers/net/ethernet/intel/ice/ice_main.c

index 2f0b604abc5e728da3171105ef340591d060c2a0..713069f809ec43fce6daa9bf360c44ff745f072f 100644 (file)
@@ -880,7 +880,7 @@ void ice_set_ethtool_repr_ops(struct net_device *netdev);
 void ice_set_ethtool_safe_mode_ops(struct net_device *netdev);
 u16 ice_get_avail_txq_count(struct ice_pf *pf);
 u16 ice_get_avail_rxq_count(struct ice_pf *pf);
-int ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx);
+int ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx, bool locked);
 void ice_update_vsi_stats(struct ice_vsi *vsi);
 void ice_update_pf_stats(struct ice_pf *pf);
 void
index 4f24d441c35e257ba397d322f6fa8124b8e7eeef..0a55c552189ab198f95087972bd49bd3bbed59b6 100644 (file)
@@ -441,7 +441,7 @@ int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked)
                goto out;
        }
 
-       ice_pf_dcb_recfg(pf);
+       ice_pf_dcb_recfg(pf, false);
 
 out:
        /* enable previously downed VSIs */
@@ -731,12 +731,13 @@ static int ice_dcb_noncontig_cfg(struct ice_pf *pf)
 /**
  * ice_pf_dcb_recfg - Reconfigure all VEBs and VSIs
  * @pf: pointer to the PF struct
+ * @locked: is adev device lock held
  *
  * Assumed caller has already disabled all VSIs before
  * calling this function. Reconfiguring DCB based on
  * local_dcbx_cfg.
  */
-void ice_pf_dcb_recfg(struct ice_pf *pf)
+void ice_pf_dcb_recfg(struct ice_pf *pf, bool locked)
 {
        struct ice_dcbx_cfg *dcbcfg = &pf->hw.port_info->qos_cfg.local_dcbx_cfg;
        struct iidc_event *event;
@@ -783,14 +784,16 @@ void ice_pf_dcb_recfg(struct ice_pf *pf)
                if (vsi->type == ICE_VSI_PF)
                        ice_dcbnl_set_all(vsi);
        }
-       /* Notify the AUX drivers that TC change is finished */
-       event = kzalloc(sizeof(*event), GFP_KERNEL);
-       if (!event)
-               return;
+       if (!locked) {
+               /* Notify the AUX drivers that TC change is finished */
+               event = kzalloc(sizeof(*event), GFP_KERNEL);
+               if (!event)
+                       return;
 
-       set_bit(IIDC_EVENT_AFTER_TC_CHANGE, event->type);
-       ice_send_event_to_aux(pf, event);
-       kfree(event);
+               set_bit(IIDC_EVENT_AFTER_TC_CHANGE, event->type);
+               ice_send_event_to_aux(pf, event);
+               kfree(event);
+       }
 }
 
 /**
@@ -1044,7 +1047,7 @@ ice_dcb_process_lldp_set_mib_change(struct ice_pf *pf,
        }
 
        /* changes in configuration update VSI */
-       ice_pf_dcb_recfg(pf);
+       ice_pf_dcb_recfg(pf, false);
 
        /* enable previously downed VSIs */
        ice_dcb_ena_dis_vsi(pf, true, true);
index 4c421c842a13fc4fa28b5c168c123786eb2695ca..800879a88c5e7b6f516c9db6c1657e06077064a5 100644 (file)
@@ -23,7 +23,7 @@ u8 ice_dcb_get_tc(struct ice_vsi *vsi, int queue_index);
 int
 ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked);
 int ice_dcb_bwchk(struct ice_pf *pf, struct ice_dcbx_cfg *dcbcfg);
-void ice_pf_dcb_recfg(struct ice_pf *pf);
+void ice_pf_dcb_recfg(struct ice_pf *pf, bool locked);
 void ice_vsi_cfg_dcb_rings(struct ice_vsi *vsi);
 int ice_init_pf_dcb(struct ice_pf *pf, bool locked);
 void ice_update_dcb_stats(struct ice_pf *pf);
@@ -128,7 +128,7 @@ static inline u8 ice_get_pfc_mode(struct ice_pf *pf)
        return 0;
 }
 
-static inline void ice_pf_dcb_recfg(struct ice_pf *pf) { }
+static inline void ice_pf_dcb_recfg(struct ice_pf *pf, bool locked) { }
 static inline void ice_vsi_cfg_dcb_rings(struct ice_vsi *vsi) { }
 static inline void ice_update_dcb_stats(struct ice_pf *pf) { }
 static inline void
index 4191994d8f3ae5f442eb77e06d0c740c3d0342c1..a359f1610fc196dde0b16512741d49a8d55e400a 100644 (file)
@@ -3641,7 +3641,9 @@ static int ice_set_channels(struct net_device *dev, struct ethtool_channels *ch)
        struct ice_vsi *vsi = np->vsi;
        struct ice_pf *pf = vsi->back;
        int new_rx = 0, new_tx = 0;
+       bool locked = false;
        u32 curr_combined;
+       int ret = 0;
 
        /* do not support changing channels in Safe Mode */
        if (ice_is_safe_mode(pf)) {
@@ -3705,15 +3707,33 @@ static int ice_set_channels(struct net_device *dev, struct ethtool_channels *ch)
                return -EINVAL;
        }
 
-       ice_vsi_recfg_qs(vsi, new_rx, new_tx);
+       if (pf->adev) {
+               mutex_lock(&pf->adev_mutex);
+               device_lock(&pf->adev->dev);
+               locked = true;
+               if (pf->adev->dev.driver) {
+                       netdev_err(dev, "Cannot change channels when RDMA is active\n");
+                       ret = -EBUSY;
+                       goto adev_unlock;
+               }
+       }
+
+       ice_vsi_recfg_qs(vsi, new_rx, new_tx, locked);
 
-       if (!netif_is_rxfh_configured(dev))
-               return ice_vsi_set_dflt_rss_lut(vsi, new_rx);
+       if (!netif_is_rxfh_configured(dev)) {
+               ret = ice_vsi_set_dflt_rss_lut(vsi, new_rx);
+               goto adev_unlock;
+       }
 
        /* Update rss_size due to change in Rx queues */
        vsi->rss_size = ice_get_valid_rss_size(&pf->hw, new_rx);
 
-       return 0;
+adev_unlock:
+       if (locked) {
+               device_unlock(&pf->adev->dev);
+               mutex_unlock(&pf->adev_mutex);
+       }
+       return ret;
 }
 
 /**
index 237ede2cffb0aa3a646ffbd3bbedf3db0840e235..5f86e4111fa9bebb8008e3ffb21f200028f8da13 100644 (file)
@@ -4195,12 +4195,13 @@ bool ice_is_wol_supported(struct ice_hw *hw)
  * @vsi: VSI being changed
  * @new_rx: new number of Rx queues
  * @new_tx: new number of Tx queues
+ * @locked: is adev device_lock held
  *
  * Only change the number of queues if new_tx, or new_rx is non-0.
  *
  * Returns 0 on success.
  */
-int ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx)
+int ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx, bool locked)
 {
        struct ice_pf *pf = vsi->back;
        int err = 0, timeout = 50;
@@ -4229,7 +4230,7 @@ int ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx)
 
        ice_vsi_close(vsi);
        ice_vsi_rebuild(vsi, false);
-       ice_pf_dcb_recfg(pf);
+       ice_pf_dcb_recfg(pf, locked);
        ice_vsi_open(vsi);
 done:
        clear_bit(ICE_CFG_BUSY, pf->state);