Commit 89e0c646 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch '40GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue

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.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents dc84bb19 7ae42ef3
......@@ -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 */
......
......@@ -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++;
fltr->state = IAVF_FDIR_FLTR_ADD_REQUEST;
adapter->aq_required |= IAVF_FLAG_AQ_ADD_FDIR_FILTER;
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);
mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
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;
......
......@@ -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 */
};
......
......@@ -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 = {
......
......@@ -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);
......
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