Commit 89e0c646 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files
Tony Nguyen says:

====================
Intel Wired LAN Driver Updates 2023-12-12 (iavf)

This series contains updates to iavf driver only.

Piotr reworks Flow Director states to deal with issues in restoring
filters.

Slawomir fixes shutdown processing as it was missing needed calls.

* '40GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue:
  iavf: Fix iavf_shutdown to call iavf_remove instead iavf_close
  iavf: Handle ntuple on/off based on new state machines for flow director
  iavf: Introduce new state machines for flow director
====================

Link: https://lore.kernel.org/r/20231212203613.513423-1-anthony.l.nguyen@intel.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents dc84bb19 7ae42ef3
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -292,6 +292,7 @@ struct iavf_adapter {
#define IAVF_FLAG_QUEUES_DISABLED		BIT(17)
#define IAVF_FLAG_SETUP_NETDEV_FEATURES		BIT(18)
#define IAVF_FLAG_REINIT_MSIX_NEEDED		BIT(20)
#define IAVF_FLAG_FDIR_ENABLED			BIT(21)
/* duplicates for common code */
#define IAVF_FLAG_DCB_ENABLED			0
	/* flags for admin queue service task */
+18 −9
Original line number Diff line number Diff line
@@ -1061,7 +1061,7 @@ iavf_get_ethtool_fdir_entry(struct iavf_adapter *adapter,
	struct iavf_fdir_fltr *rule = NULL;
	int ret = 0;

	if (!FDIR_FLTR_SUPPORT(adapter))
	if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))
		return -EOPNOTSUPP;

	spin_lock_bh(&adapter->fdir_fltr_lock);
@@ -1203,7 +1203,7 @@ iavf_get_fdir_fltr_ids(struct iavf_adapter *adapter, struct ethtool_rxnfc *cmd,
	unsigned int cnt = 0;
	int val = 0;

	if (!FDIR_FLTR_SUPPORT(adapter))
	if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))
		return -EOPNOTSUPP;

	cmd->data = IAVF_MAX_FDIR_FILTERS;
@@ -1395,7 +1395,7 @@ static int iavf_add_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
	int count = 50;
	int err;

	if (!FDIR_FLTR_SUPPORT(adapter))
	if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))
		return -EOPNOTSUPP;

	if (fsp->flow_type & FLOW_MAC_EXT)
@@ -1436,12 +1436,16 @@ static int iavf_add_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
	spin_lock_bh(&adapter->fdir_fltr_lock);
	iavf_fdir_list_add_fltr(adapter, fltr);
	adapter->fdir_active_fltr++;
	if (adapter->link_up) {
		fltr->state = IAVF_FDIR_FLTR_ADD_REQUEST;
		adapter->aq_required |= IAVF_FLAG_AQ_ADD_FDIR_FILTER;
	} else {
		fltr->state = IAVF_FDIR_FLTR_INACTIVE;
	}
	spin_unlock_bh(&adapter->fdir_fltr_lock);

	if (adapter->link_up)
		mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);

ret:
	if (err && fltr)
		kfree(fltr);
@@ -1463,7 +1467,7 @@ static int iavf_del_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
	struct iavf_fdir_fltr *fltr = NULL;
	int err = 0;

	if (!FDIR_FLTR_SUPPORT(adapter))
	if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))
		return -EOPNOTSUPP;

	spin_lock_bh(&adapter->fdir_fltr_lock);
@@ -1472,6 +1476,11 @@ static int iavf_del_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
		if (fltr->state == IAVF_FDIR_FLTR_ACTIVE) {
			fltr->state = IAVF_FDIR_FLTR_DEL_REQUEST;
			adapter->aq_required |= IAVF_FLAG_AQ_DEL_FDIR_FILTER;
		} else if (fltr->state == IAVF_FDIR_FLTR_INACTIVE) {
			list_del(&fltr->list);
			kfree(fltr);
			adapter->fdir_active_fltr--;
			fltr = NULL;
		} else {
			err = -EBUSY;
		}
@@ -1780,7 +1789,7 @@ static int iavf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
		ret = 0;
		break;
	case ETHTOOL_GRXCLSRLCNT:
		if (!FDIR_FLTR_SUPPORT(adapter))
		if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))
			break;
		spin_lock_bh(&adapter->fdir_fltr_lock);
		cmd->rule_cnt = adapter->fdir_active_fltr;
+14 −1
Original line number Diff line number Diff line
@@ -6,12 +6,25 @@

struct iavf_adapter;

/* State of Flow Director filter */
/* State of Flow Director filter
 *
 * *_REQUEST states are used to mark filter to be sent to PF driver to perform
 * an action (either add or delete filter). *_PENDING states are an indication
 * that request was sent to PF and the driver is waiting for response.
 *
 * Both DELETE and DISABLE states are being used to delete a filter in PF.
 * The difference is that after a successful response filter in DEL_PENDING
 * state is being deleted from VF driver as well and filter in DIS_PENDING state
 * is being changed to INACTIVE state.
 */
enum iavf_fdir_fltr_state_t {
	IAVF_FDIR_FLTR_ADD_REQUEST,	/* User requests to add filter */
	IAVF_FDIR_FLTR_ADD_PENDING,	/* Filter pending add by the PF */
	IAVF_FDIR_FLTR_DEL_REQUEST,	/* User requests to delete filter */
	IAVF_FDIR_FLTR_DEL_PENDING,	/* Filter pending delete by the PF */
	IAVF_FDIR_FLTR_DIS_REQUEST,	/* Filter scheduled to be disabled */
	IAVF_FDIR_FLTR_DIS_PENDING,	/* Filter pending disable by the PF */
	IAVF_FDIR_FLTR_INACTIVE,	/* Filter inactive on link down */
	IAVF_FDIR_FLTR_ACTIVE,		/* Filter is active */
};

+119 −60
Original line number Diff line number Diff line
@@ -276,27 +276,6 @@ void iavf_free_virt_mem(struct iavf_hw *hw, struct iavf_virt_mem *mem)
	kfree(mem->va);
}

/**
 * iavf_lock_timeout - try to lock mutex but give up after timeout
 * @lock: mutex that should be locked
 * @msecs: timeout in msecs
 *
 * Returns 0 on success, negative on failure
 **/
static int iavf_lock_timeout(struct mutex *lock, unsigned int msecs)
{
	unsigned int wait, delay = 10;

	for (wait = 0; wait < msecs; wait += delay) {
		if (mutex_trylock(lock))
			return 0;

		msleep(delay);
	}

	return -1;
}

/**
 * iavf_schedule_reset - Set the flags and schedule a reset event
 * @adapter: board private structure
@@ -1353,18 +1332,20 @@ static void iavf_clear_cloud_filters(struct iavf_adapter *adapter)
 **/
static void iavf_clear_fdir_filters(struct iavf_adapter *adapter)
{
	struct iavf_fdir_fltr *fdir, *fdirtmp;
	struct iavf_fdir_fltr *fdir;

	/* remove all Flow Director filters */
	spin_lock_bh(&adapter->fdir_fltr_lock);
	list_for_each_entry_safe(fdir, fdirtmp, &adapter->fdir_list_head,
				 list) {
	list_for_each_entry(fdir, &adapter->fdir_list_head, list) {
		if (fdir->state == IAVF_FDIR_FLTR_ADD_REQUEST) {
			list_del(&fdir->list);
			kfree(fdir);
			adapter->fdir_active_fltr--;
		} else {
			fdir->state = IAVF_FDIR_FLTR_DEL_REQUEST;
			/* Cancel a request, keep filter as inactive */
			fdir->state = IAVF_FDIR_FLTR_INACTIVE;
		} else if (fdir->state == IAVF_FDIR_FLTR_ADD_PENDING ||
			 fdir->state == IAVF_FDIR_FLTR_ACTIVE) {
			/* Disable filters which are active or have a pending
			 * request to PF to be added
			 */
			fdir->state = IAVF_FDIR_FLTR_DIS_REQUEST;
		}
	}
	spin_unlock_bh(&adapter->fdir_fltr_lock);
@@ -4112,6 +4093,33 @@ static int iavf_setup_tc(struct net_device *netdev, enum tc_setup_type type,
	}
}

/**
 * iavf_restore_fdir_filters
 * @adapter: board private structure
 *
 * Restore existing FDIR filters when VF netdev comes back up.
 **/
static void iavf_restore_fdir_filters(struct iavf_adapter *adapter)
{
	struct iavf_fdir_fltr *f;

	spin_lock_bh(&adapter->fdir_fltr_lock);
	list_for_each_entry(f, &adapter->fdir_list_head, list) {
		if (f->state == IAVF_FDIR_FLTR_DIS_REQUEST) {
			/* Cancel a request, keep filter as active */
			f->state = IAVF_FDIR_FLTR_ACTIVE;
		} else if (f->state == IAVF_FDIR_FLTR_DIS_PENDING ||
			   f->state == IAVF_FDIR_FLTR_INACTIVE) {
			/* Add filters which are inactive or have a pending
			 * request to PF to be deleted
			 */
			f->state = IAVF_FDIR_FLTR_ADD_REQUEST;
			adapter->aq_required |= IAVF_FLAG_AQ_ADD_FDIR_FILTER;
		}
	}
	spin_unlock_bh(&adapter->fdir_fltr_lock);
}

/**
 * iavf_open - Called when a network interface is made active
 * @netdev: network interface device structure
@@ -4179,8 +4187,9 @@ static int iavf_open(struct net_device *netdev)

	spin_unlock_bh(&adapter->mac_vlan_list_lock);

	/* Restore VLAN filters that were removed with IFF_DOWN */
	/* Restore filters that were removed with IFF_DOWN */
	iavf_restore_filters(adapter);
	iavf_restore_fdir_filters(adapter);

	iavf_configure(adapter);

@@ -4311,6 +4320,49 @@ static int iavf_change_mtu(struct net_device *netdev, int new_mtu)
	return ret;
}

/**
 * iavf_disable_fdir - disable Flow Director and clear existing filters
 * @adapter: board private structure
 **/
static void iavf_disable_fdir(struct iavf_adapter *adapter)
{
	struct iavf_fdir_fltr *fdir, *fdirtmp;
	bool del_filters = false;

	adapter->flags &= ~IAVF_FLAG_FDIR_ENABLED;

	/* remove all Flow Director filters */
	spin_lock_bh(&adapter->fdir_fltr_lock);
	list_for_each_entry_safe(fdir, fdirtmp, &adapter->fdir_list_head,
				 list) {
		if (fdir->state == IAVF_FDIR_FLTR_ADD_REQUEST ||
		    fdir->state == IAVF_FDIR_FLTR_INACTIVE) {
			/* Delete filters not registered in PF */
			list_del(&fdir->list);
			kfree(fdir);
			adapter->fdir_active_fltr--;
		} else if (fdir->state == IAVF_FDIR_FLTR_ADD_PENDING ||
			   fdir->state == IAVF_FDIR_FLTR_DIS_REQUEST ||
			   fdir->state == IAVF_FDIR_FLTR_ACTIVE) {
			/* Filters registered in PF, schedule their deletion */
			fdir->state = IAVF_FDIR_FLTR_DEL_REQUEST;
			del_filters = true;
		} else if (fdir->state == IAVF_FDIR_FLTR_DIS_PENDING) {
			/* Request to delete filter already sent to PF, change
			 * state to DEL_PENDING to delete filter after PF's
			 * response, not set as INACTIVE
			 */
			fdir->state = IAVF_FDIR_FLTR_DEL_PENDING;
		}
	}
	spin_unlock_bh(&adapter->fdir_fltr_lock);

	if (del_filters) {
		adapter->aq_required |= IAVF_FLAG_AQ_DEL_FDIR_FILTER;
		mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
	}
}

#define NETIF_VLAN_OFFLOAD_FEATURES	(NETIF_F_HW_VLAN_CTAG_RX | \
					 NETIF_F_HW_VLAN_CTAG_TX | \
					 NETIF_F_HW_VLAN_STAG_RX | \
@@ -4336,6 +4388,13 @@ static int iavf_set_features(struct net_device *netdev,
	    ((netdev->features & NETIF_F_RXFCS) ^ (features & NETIF_F_RXFCS)))
		iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);

	if ((netdev->features & NETIF_F_NTUPLE) ^ (features & NETIF_F_NTUPLE)) {
		if (features & NETIF_F_NTUPLE)
			adapter->flags |= IAVF_FLAG_FDIR_ENABLED;
		else
			iavf_disable_fdir(adapter);
	}

	return 0;
}

@@ -4685,6 +4744,9 @@ static netdev_features_t iavf_fix_features(struct net_device *netdev,

	features = iavf_fix_netdev_vlan_features(adapter, features);

	if (!FDIR_FLTR_SUPPORT(adapter))
		features &= ~NETIF_F_NTUPLE;

	return iavf_fix_strip_features(adapter, features);
}

@@ -4802,6 +4864,12 @@ int iavf_process_config(struct iavf_adapter *adapter)
	if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN)
		netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;

	if (FDIR_FLTR_SUPPORT(adapter)) {
		netdev->hw_features |= NETIF_F_NTUPLE;
		netdev->features |= NETIF_F_NTUPLE;
		adapter->flags |= IAVF_FLAG_FDIR_ENABLED;
	}

	netdev->priv_flags |= IFF_UNICAST_FLT;

	/* Do not turn on offloads when they are requested to be turned off.
@@ -4825,34 +4893,6 @@ int iavf_process_config(struct iavf_adapter *adapter)
	return 0;
}

/**
 * iavf_shutdown - Shutdown the device in preparation for a reboot
 * @pdev: pci device structure
 **/
static void iavf_shutdown(struct pci_dev *pdev)
{
	struct iavf_adapter *adapter = iavf_pdev_to_adapter(pdev);
	struct net_device *netdev = adapter->netdev;

	netif_device_detach(netdev);

	if (netif_running(netdev))
		iavf_close(netdev);

	if (iavf_lock_timeout(&adapter->crit_lock, 5000))
		dev_warn(&adapter->pdev->dev, "%s: failed to acquire crit_lock\n", __func__);
	/* Prevent the watchdog from running. */
	iavf_change_state(adapter, __IAVF_REMOVE);
	adapter->aq_required = 0;
	mutex_unlock(&adapter->crit_lock);

#ifdef CONFIG_PM
	pci_save_state(pdev);

#endif
	pci_disable_device(pdev);
}

/**
 * iavf_probe - Device Initialization Routine
 * @pdev: PCI device information struct
@@ -5063,16 +5103,21 @@ static int __maybe_unused iavf_resume(struct device *dev_d)
 **/
static void iavf_remove(struct pci_dev *pdev)
{
	struct iavf_adapter *adapter = iavf_pdev_to_adapter(pdev);
	struct iavf_fdir_fltr *fdir, *fdirtmp;
	struct iavf_vlan_filter *vlf, *vlftmp;
	struct iavf_cloud_filter *cf, *cftmp;
	struct iavf_adv_rss *rss, *rsstmp;
	struct iavf_mac_filter *f, *ftmp;
	struct iavf_adapter *adapter;
	struct net_device *netdev;
	struct iavf_hw *hw;

	netdev = adapter->netdev;
	/* Don't proceed with remove if netdev is already freed */
	netdev = pci_get_drvdata(pdev);
	if (!netdev)
		return;

	adapter = iavf_pdev_to_adapter(pdev);
	hw = &adapter->hw;

	if (test_and_set_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section))
@@ -5184,11 +5229,25 @@ static void iavf_remove(struct pci_dev *pdev)

	destroy_workqueue(adapter->wq);

	pci_set_drvdata(pdev, NULL);

	free_netdev(netdev);

	pci_disable_device(pdev);
}

/**
 * iavf_shutdown - Shutdown the device in preparation for a reboot
 * @pdev: pci device structure
 **/
static void iavf_shutdown(struct pci_dev *pdev)
{
	iavf_remove(pdev);

	if (system_state == SYSTEM_POWER_OFF)
		pci_set_power_state(pdev, PCI_D3hot);
}

static SIMPLE_DEV_PM_OPS(iavf_pm_ops, iavf_suspend, iavf_resume);

static struct pci_driver iavf_driver = {
+67 −4
Original line number Diff line number Diff line
@@ -1735,8 +1735,8 @@ void iavf_add_fdir_filter(struct iavf_adapter *adapter)
 **/
void iavf_del_fdir_filter(struct iavf_adapter *adapter)
{
	struct virtchnl_fdir_del f = {};
	struct iavf_fdir_fltr *fdir;
	struct virtchnl_fdir_del f;
	bool process_fltr = false;
	int len;

@@ -1753,11 +1753,16 @@ void iavf_del_fdir_filter(struct iavf_adapter *adapter)
	list_for_each_entry(fdir, &adapter->fdir_list_head, list) {
		if (fdir->state == IAVF_FDIR_FLTR_DEL_REQUEST) {
			process_fltr = true;
			memset(&f, 0, len);
			f.vsi_id = fdir->vc_add_msg.vsi_id;
			f.flow_id = fdir->flow_id;
			fdir->state = IAVF_FDIR_FLTR_DEL_PENDING;
			break;
		} else if (fdir->state == IAVF_FDIR_FLTR_DIS_REQUEST) {
			process_fltr = true;
			f.vsi_id = fdir->vc_add_msg.vsi_id;
			f.flow_id = fdir->flow_id;
			fdir->state = IAVF_FDIR_FLTR_DIS_PENDING;
			break;
		}
	}
	spin_unlock_bh(&adapter->fdir_fltr_lock);
@@ -1901,6 +1906,48 @@ static void iavf_netdev_features_vlan_strip_set(struct net_device *netdev,
		netdev->features &= ~NETIF_F_HW_VLAN_CTAG_RX;
}

/**
 * iavf_activate_fdir_filters - Reactivate all FDIR filters after a reset
 * @adapter: private adapter structure
 *
 * Called after a reset to re-add all FDIR filters and delete some of them
 * if they were pending to be deleted.
 */
static void iavf_activate_fdir_filters(struct iavf_adapter *adapter)
{
	struct iavf_fdir_fltr *f, *ftmp;
	bool add_filters = false;

	spin_lock_bh(&adapter->fdir_fltr_lock);
	list_for_each_entry_safe(f, ftmp, &adapter->fdir_list_head, list) {
		if (f->state == IAVF_FDIR_FLTR_ADD_REQUEST ||
		    f->state == IAVF_FDIR_FLTR_ADD_PENDING ||
		    f->state == IAVF_FDIR_FLTR_ACTIVE) {
			/* All filters and requests have been removed in PF,
			 * restore them
			 */
			f->state = IAVF_FDIR_FLTR_ADD_REQUEST;
			add_filters = true;
		} else if (f->state == IAVF_FDIR_FLTR_DIS_REQUEST ||
			   f->state == IAVF_FDIR_FLTR_DIS_PENDING) {
			/* Link down state, leave filters as inactive */
			f->state = IAVF_FDIR_FLTR_INACTIVE;
		} else if (f->state == IAVF_FDIR_FLTR_DEL_REQUEST ||
			   f->state == IAVF_FDIR_FLTR_DEL_PENDING) {
			/* Delete filters that were pending to be deleted, the
			 * list on PF is already cleared after a reset
			 */
			list_del(&f->list);
			kfree(f);
			adapter->fdir_active_fltr--;
		}
	}
	spin_unlock_bh(&adapter->fdir_fltr_lock);

	if (add_filters)
		adapter->aq_required |= IAVF_FLAG_AQ_ADD_FDIR_FILTER;
}

/**
 * iavf_virtchnl_completion
 * @adapter: adapter structure
@@ -2078,7 +2125,8 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
			spin_lock_bh(&adapter->fdir_fltr_lock);
			list_for_each_entry(fdir, &adapter->fdir_list_head,
					    list) {
				if (fdir->state == IAVF_FDIR_FLTR_DEL_PENDING) {
				if (fdir->state == IAVF_FDIR_FLTR_DEL_PENDING ||
				    fdir->state == IAVF_FDIR_FLTR_DIS_PENDING) {
					fdir->state = IAVF_FDIR_FLTR_ACTIVE;
					dev_info(&adapter->pdev->dev, "Failed to del Flow Director filter, error %s\n",
						 iavf_stat_str(&adapter->hw,
@@ -2214,6 +2262,8 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,

		spin_unlock_bh(&adapter->mac_vlan_list_lock);

		iavf_activate_fdir_filters(adapter);

		iavf_parse_vf_resource_msg(adapter);

		/* negotiated VIRTCHNL_VF_OFFLOAD_VLAN_V2, so wait for the
@@ -2390,7 +2440,9 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
		list_for_each_entry_safe(fdir, fdir_tmp, &adapter->fdir_list_head,
					 list) {
			if (fdir->state == IAVF_FDIR_FLTR_DEL_PENDING) {
				if (del_fltr->status == VIRTCHNL_FDIR_SUCCESS) {
				if (del_fltr->status == VIRTCHNL_FDIR_SUCCESS ||
				    del_fltr->status ==
				    VIRTCHNL_FDIR_FAILURE_RULE_NONEXIST) {
					dev_info(&adapter->pdev->dev, "Flow Director filter with location %u is deleted\n",
						 fdir->loc);
					list_del(&fdir->list);
@@ -2402,6 +2454,17 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
						 del_fltr->status);
					iavf_print_fdir_fltr(adapter, fdir);
				}
			} else if (fdir->state == IAVF_FDIR_FLTR_DIS_PENDING) {
				if (del_fltr->status == VIRTCHNL_FDIR_SUCCESS ||
				    del_fltr->status ==
				    VIRTCHNL_FDIR_FAILURE_RULE_NONEXIST) {
					fdir->state = IAVF_FDIR_FLTR_INACTIVE;
				} else {
					fdir->state = IAVF_FDIR_FLTR_ACTIVE;
					dev_info(&adapter->pdev->dev, "Failed to disable Flow Director filter with status: %d\n",
						 del_fltr->status);
					iavf_print_fdir_fltr(adapter, fdir);
				}
			}
		}
		spin_unlock_bh(&adapter->fdir_fltr_lock);