Commit 7f5acea7 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-07-17 (iavf)

This series contains updates to iavf driver only.

Ding Hui fixes use-after-free issue by calling netif_napi_del() for all
allocated q_vectors. He also resolves out-of-bounds issue by not
updating to new values when timeout is encountered.

Marcin and Ahmed change the way resets are handled so that the callback
operating under the RTNL lock will wait for the reset to finish, the
rtnl_lock sensitive functions in reset flow will schedule the netdev update
for later in order to remove circular dependency with the critical lock.

* '40GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue:
  iavf: fix reset task race with iavf_remove()
  iavf: fix a deadlock caused by rtnl and driver's lock circular dependencies
  Revert "iavf: Do not restart Tx queues after reset task failure"
  Revert "iavf: Detach device during reset task"
  iavf: Wait for reset in callbacks which trigger it
  iavf: use internal state to free traffic IRQs
  iavf: Fix out-of-bounds when setting channels on remove
  iavf: Fix use-after-free in free_netdev
====================

Link: https://lore.kernel.org/r/20230717175205.3217774-1-anthony.l.nguyen@intel.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents e9b2bd96 c34743da
...@@ -255,8 +255,10 @@ struct iavf_adapter { ...@@ -255,8 +255,10 @@ struct iavf_adapter {
struct workqueue_struct *wq; struct workqueue_struct *wq;
struct work_struct reset_task; struct work_struct reset_task;
struct work_struct adminq_task; struct work_struct adminq_task;
struct work_struct finish_config;
struct delayed_work client_task; struct delayed_work client_task;
wait_queue_head_t down_waitqueue; wait_queue_head_t down_waitqueue;
wait_queue_head_t reset_waitqueue;
wait_queue_head_t vc_waitqueue; wait_queue_head_t vc_waitqueue;
struct iavf_q_vector *q_vectors; struct iavf_q_vector *q_vectors;
struct list_head vlan_filter_list; struct list_head vlan_filter_list;
...@@ -518,8 +520,9 @@ int iavf_up(struct iavf_adapter *adapter); ...@@ -518,8 +520,9 @@ int iavf_up(struct iavf_adapter *adapter);
void iavf_down(struct iavf_adapter *adapter); void iavf_down(struct iavf_adapter *adapter);
int iavf_process_config(struct iavf_adapter *adapter); int iavf_process_config(struct iavf_adapter *adapter);
int iavf_parse_vf_resource_msg(struct iavf_adapter *adapter); int iavf_parse_vf_resource_msg(struct iavf_adapter *adapter);
void iavf_schedule_reset(struct iavf_adapter *adapter); void iavf_schedule_reset(struct iavf_adapter *adapter, u64 flags);
void iavf_schedule_request_stats(struct iavf_adapter *adapter); void iavf_schedule_request_stats(struct iavf_adapter *adapter);
void iavf_schedule_finish_config(struct iavf_adapter *adapter);
void iavf_reset(struct iavf_adapter *adapter); void iavf_reset(struct iavf_adapter *adapter);
void iavf_set_ethtool_ops(struct net_device *netdev); void iavf_set_ethtool_ops(struct net_device *netdev);
void iavf_update_stats(struct iavf_adapter *adapter); void iavf_update_stats(struct iavf_adapter *adapter);
...@@ -582,4 +585,5 @@ void iavf_add_adv_rss_cfg(struct iavf_adapter *adapter); ...@@ -582,4 +585,5 @@ void iavf_add_adv_rss_cfg(struct iavf_adapter *adapter);
void iavf_del_adv_rss_cfg(struct iavf_adapter *adapter); void iavf_del_adv_rss_cfg(struct iavf_adapter *adapter);
struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter, struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter,
const u8 *macaddr); const u8 *macaddr);
int iavf_wait_for_reset(struct iavf_adapter *adapter);
#endif /* _IAVF_H_ */ #endif /* _IAVF_H_ */
...@@ -484,6 +484,7 @@ static int iavf_set_priv_flags(struct net_device *netdev, u32 flags) ...@@ -484,6 +484,7 @@ static int iavf_set_priv_flags(struct net_device *netdev, u32 flags)
{ {
struct iavf_adapter *adapter = netdev_priv(netdev); struct iavf_adapter *adapter = netdev_priv(netdev);
u32 orig_flags, new_flags, changed_flags; u32 orig_flags, new_flags, changed_flags;
int ret = 0;
u32 i; u32 i;
orig_flags = READ_ONCE(adapter->flags); orig_flags = READ_ONCE(adapter->flags);
...@@ -531,12 +532,14 @@ static int iavf_set_priv_flags(struct net_device *netdev, u32 flags) ...@@ -531,12 +532,14 @@ static int iavf_set_priv_flags(struct net_device *netdev, u32 flags)
/* issue a reset to force legacy-rx change to take effect */ /* issue a reset to force legacy-rx change to take effect */
if (changed_flags & IAVF_FLAG_LEGACY_RX) { if (changed_flags & IAVF_FLAG_LEGACY_RX) {
if (netif_running(netdev)) { if (netif_running(netdev)) {
adapter->flags |= IAVF_FLAG_RESET_NEEDED; iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
queue_work(adapter->wq, &adapter->reset_task); ret = iavf_wait_for_reset(adapter);
if (ret)
netdev_warn(netdev, "Changing private flags timeout or interrupted waiting for reset");
} }
} }
return 0; return ret;
} }
/** /**
...@@ -627,6 +630,7 @@ static int iavf_set_ringparam(struct net_device *netdev, ...@@ -627,6 +630,7 @@ static int iavf_set_ringparam(struct net_device *netdev,
{ {
struct iavf_adapter *adapter = netdev_priv(netdev); struct iavf_adapter *adapter = netdev_priv(netdev);
u32 new_rx_count, new_tx_count; u32 new_rx_count, new_tx_count;
int ret = 0;
if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
return -EINVAL; return -EINVAL;
...@@ -671,11 +675,13 @@ static int iavf_set_ringparam(struct net_device *netdev, ...@@ -671,11 +675,13 @@ static int iavf_set_ringparam(struct net_device *netdev,
} }
if (netif_running(netdev)) { if (netif_running(netdev)) {
adapter->flags |= IAVF_FLAG_RESET_NEEDED; iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
queue_work(adapter->wq, &adapter->reset_task); ret = iavf_wait_for_reset(adapter);
if (ret)
netdev_warn(netdev, "Changing ring parameters timeout or interrupted waiting for reset");
} }
return 0; return ret;
} }
/** /**
...@@ -1830,7 +1836,7 @@ static int iavf_set_channels(struct net_device *netdev, ...@@ -1830,7 +1836,7 @@ static int iavf_set_channels(struct net_device *netdev,
{ {
struct iavf_adapter *adapter = netdev_priv(netdev); struct iavf_adapter *adapter = netdev_priv(netdev);
u32 num_req = ch->combined_count; u32 num_req = ch->combined_count;
int i; int ret = 0;
if ((adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ) && if ((adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ) &&
adapter->num_tc) { adapter->num_tc) {
...@@ -1852,22 +1858,13 @@ static int iavf_set_channels(struct net_device *netdev, ...@@ -1852,22 +1858,13 @@ static int iavf_set_channels(struct net_device *netdev,
adapter->num_req_queues = num_req; adapter->num_req_queues = num_req;
adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED; adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED;
iavf_schedule_reset(adapter); iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
/* wait for the reset is done */ ret = iavf_wait_for_reset(adapter);
for (i = 0; i < IAVF_RESET_WAIT_COMPLETE_COUNT; i++) { if (ret)
msleep(IAVF_RESET_WAIT_MS); netdev_warn(netdev, "Changing channel count timeout or interrupted waiting for reset");
if (adapter->flags & IAVF_FLAG_RESET_PENDING)
continue;
break;
}
if (i == IAVF_RESET_WAIT_COMPLETE_COUNT) {
adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
adapter->num_active_queues = num_req;
return -EOPNOTSUPP;
}
return 0; return ret;
} }
/** /**
......
This diff is collapsed.
...@@ -1961,9 +1961,8 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, ...@@ -1961,9 +1961,8 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
case VIRTCHNL_EVENT_RESET_IMPENDING: case VIRTCHNL_EVENT_RESET_IMPENDING:
dev_info(&adapter->pdev->dev, "Reset indication received from the PF\n"); dev_info(&adapter->pdev->dev, "Reset indication received from the PF\n");
if (!(adapter->flags & IAVF_FLAG_RESET_PENDING)) { if (!(adapter->flags & IAVF_FLAG_RESET_PENDING)) {
adapter->flags |= IAVF_FLAG_RESET_PENDING;
dev_info(&adapter->pdev->dev, "Scheduling reset task\n"); dev_info(&adapter->pdev->dev, "Scheduling reset task\n");
queue_work(adapter->wq, &adapter->reset_task); iavf_schedule_reset(adapter, IAVF_FLAG_RESET_PENDING);
} }
break; break;
default: default:
...@@ -2237,6 +2236,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, ...@@ -2237,6 +2236,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
iavf_process_config(adapter); iavf_process_config(adapter);
adapter->flags |= IAVF_FLAG_SETUP_NETDEV_FEATURES; adapter->flags |= IAVF_FLAG_SETUP_NETDEV_FEATURES;
iavf_schedule_finish_config(adapter);
iavf_set_queue_vlan_tag_loc(adapter); iavf_set_queue_vlan_tag_loc(adapter);
...@@ -2285,6 +2285,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, ...@@ -2285,6 +2285,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
case VIRTCHNL_OP_ENABLE_QUEUES: case VIRTCHNL_OP_ENABLE_QUEUES:
/* enable transmits */ /* enable transmits */
iavf_irq_enable(adapter, true); iavf_irq_enable(adapter, true);
wake_up(&adapter->reset_waitqueue);
adapter->flags &= ~IAVF_FLAG_QUEUES_DISABLED; adapter->flags &= ~IAVF_FLAG_QUEUES_DISABLED;
break; break;
case VIRTCHNL_OP_DISABLE_QUEUES: case VIRTCHNL_OP_DISABLE_QUEUES:
......
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