@@ -255,6 +255,7 @@ struct iavf_adapter {
struct workqueue_struct *wq;
struct work_struct reset_task;
struct work_struct adminq_task;
+ struct work_struct set_interrupt_capability;
struct delayed_work client_task;
wait_queue_head_t down_waitqueue;
wait_queue_head_t reset_waitqueue;
@@ -1707,11 +1707,38 @@ static int iavf_set_interrupt_capability(struct iavf_adapter *adapter)
err = iavf_acquire_msix_vectors(adapter, v_budget);
out:
- netif_set_real_num_rx_queues(adapter->netdev, pairs);
- netif_set_real_num_tx_queues(adapter->netdev, pairs);
+ if (rtnl_trylock()) {
+ netif_set_real_num_rx_queues(adapter->netdev, pairs);
+ netif_set_real_num_tx_queues(adapter->netdev, pairs);
+ rtnl_unlock();
+ } else {
+ schedule_work(&adapter->set_interrupt_capability);
+ }
+
return err;
}
+/**
+ * iavf_delayed_set_interrupt_capability - schedule the update of the netdev
+ * @work: pointer to work_struct containing our data
+ **/
+static void iavf_delayed_set_interrupt_capability(struct work_struct *work)
+{
+ struct iavf_adapter *adapter;
+ int pairs;
+
+ rtnl_lock();
+ adapter = container_of(work, struct iavf_adapter,
+ set_interrupt_capability);
+ pairs = adapter->num_active_queues;
+
+ if (adapter->netdev_registered) {
+ netif_set_real_num_rx_queues(adapter->netdev, pairs);
+ netif_set_real_num_tx_queues(adapter->netdev, pairs);
+ }
+ rtnl_unlock();
+}
+
/**
* iavf_config_rss_aq - Configure RSS keys and lut by using AQ commands
* @adapter: board private structure
@@ -1926,10 +1953,8 @@ int iavf_init_interrupt_scheme(struct iavf_adapter *adapter)
"Unable to allocate memory for queues\n");
goto err_alloc_queues;
}
-
- rtnl_lock();
err = iavf_set_interrupt_capability(adapter);
- rtnl_unlock();
+
if (err) {
dev_err(&adapter->pdev->dev,
"Unable to setup interrupt capabilities\n");
@@ -4979,6 +5004,8 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
INIT_WORK(&adapter->reset_task, iavf_reset_task);
INIT_WORK(&adapter->adminq_task, iavf_adminq_task);
+ INIT_WORK(&adapter->set_interrupt_capability,
+ iavf_delayed_set_interrupt_capability);
INIT_DELAYED_WORK(&adapter->watchdog_task, iavf_watchdog_task);
INIT_DELAYED_WORK(&adapter->client_task, iavf_client_task);
queue_delayed_work(adapter->wq, &adapter->watchdog_task,
@@ -5152,6 +5179,7 @@ static void iavf_remove(struct pci_dev *pdev)
cancel_work_sync(&adapter->reset_task);
cancel_delayed_work_sync(&adapter->watchdog_task);
cancel_work_sync(&adapter->adminq_task);
+ cancel_work_sync(&adapter->set_interrupt_capability);
cancel_delayed_work_sync(&adapter->client_task);
adapter->aq_required = 0;