]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - drivers/net/ethernet/intel/iavf/iavf_main.c
iavf: Rework mutexes for better synchronisation
[mirror_ubuntu-jammy-kernel.git] / drivers / net / ethernet / intel / iavf / iavf_main.c
index 75fab4ea42b618073d32d4e98dd3837d999bda8b..3aa21568686dc135c1144708c6d461cd72c3c05b 100644 (file)
@@ -293,8 +293,9 @@ static irqreturn_t iavf_msix_aq(int irq, void *data)
        rd32(hw, IAVF_VFINT_ICR01);
        rd32(hw, IAVF_VFINT_ICR0_ENA1);
 
-       /* schedule work on the private workqueue */
-       queue_work(iavf_wq, &adapter->adminq_task);
+       if (adapter->state != __IAVF_REMOVE)
+               /* schedule work on the private workqueue */
+               queue_work(iavf_wq, &adapter->adminq_task);
 
        return IRQ_HANDLED;
 }
@@ -1972,8 +1973,12 @@ static void iavf_watchdog_task(struct work_struct *work)
        struct iavf_hw *hw = &adapter->hw;
        u32 reg_val;
 
-       if (!mutex_trylock(&adapter->crit_lock))
+       if (!mutex_trylock(&adapter->crit_lock)) {
+               if (adapter->state == __IAVF_REMOVE)
+                       return;
+
                goto restart_watchdog;
+       }
 
        if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED)
                iavf_change_state(adapter, __IAVF_COMM_FAILED);
@@ -2185,13 +2190,13 @@ static void iavf_reset_task(struct work_struct *work)
        /* When device is being removed it doesn't make sense to run the reset
         * task, just return in such a case.
         */
-       if (mutex_is_locked(&adapter->remove_lock))
-               return;
+       if (!mutex_trylock(&adapter->crit_lock)) {
+               if (adapter->state != __IAVF_REMOVE)
+                       queue_work(iavf_wq, &adapter->reset_task);
 
-       if (iavf_lock_timeout(&adapter->crit_lock, 200)) {
-               schedule_work(&adapter->reset_task);
                return;
        }
+
        while (!mutex_trylock(&adapter->client_lock))
                usleep_range(500, 1000);
        if (CLIENT_ENABLED(adapter)) {
@@ -2401,13 +2406,19 @@ static void iavf_adminq_task(struct work_struct *work)
        if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED)
                goto out;
 
+       if (!mutex_trylock(&adapter->crit_lock)) {
+               if (adapter->state == __IAVF_REMOVE)
+                       return;
+
+               queue_work(iavf_wq, &adapter->adminq_task);
+               goto out;
+       }
+
        event.buf_len = IAVF_MAX_AQ_BUF_SIZE;
        event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL);
        if (!event.msg_buf)
                goto out;
 
-       if (iavf_lock_timeout(&adapter->crit_lock, 200))
-               goto freedom;
        do {
                ret = iavf_clean_arq_element(hw, &event, &pending);
                v_op = (enum virtchnl_ops)le32_to_cpu(event.desc.cookie_high);
@@ -3368,11 +3379,12 @@ static int iavf_close(struct net_device *netdev)
        struct iavf_adapter *adapter = netdev_priv(netdev);
        int status;
 
-       if (adapter->state <= __IAVF_DOWN_PENDING)
-               return 0;
+       mutex_lock(&adapter->crit_lock);
 
-       while (!mutex_trylock(&adapter->crit_lock))
-               usleep_range(500, 1000);
+       if (adapter->state <= __IAVF_DOWN_PENDING) {
+               mutex_unlock(&adapter->crit_lock);
+               return 0;
+       }
 
        set_bit(__IAVF_VSI_DOWN, adapter->vsi.state);
        if (CLIENT_ENABLED(adapter))
@@ -3836,7 +3848,6 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
         */
        mutex_init(&adapter->crit_lock);
        mutex_init(&adapter->client_lock);
-       mutex_init(&adapter->remove_lock);
        mutex_init(&hw->aq.asq_mutex);
        mutex_init(&hw->aq.arq_mutex);
 
@@ -3959,11 +3970,7 @@ static void iavf_remove(struct pci_dev *pdev)
        struct iavf_cloud_filter *cf, *cftmp;
        struct iavf_hw *hw = &adapter->hw;
        int err;
-       /* Indicate we are in remove and not to run reset_task */
-       mutex_lock(&adapter->remove_lock);
-       cancel_work_sync(&adapter->reset_task);
-       cancel_delayed_work_sync(&adapter->watchdog_task);
-       cancel_delayed_work_sync(&adapter->client_task);
+
        if (adapter->netdev_registered) {
                unregister_netdev(netdev);
                adapter->netdev_registered = false;
@@ -3975,6 +3982,10 @@ static void iavf_remove(struct pci_dev *pdev)
                                 err);
        }
 
+       mutex_lock(&adapter->crit_lock);
+       dev_info(&adapter->pdev->dev, "Remove device\n");
+       iavf_change_state(adapter, __IAVF_REMOVE);
+
        iavf_request_reset(adapter);
        msleep(50);
        /* If the FW isn't responding, kick it once, but only once. */
@@ -3982,25 +3993,22 @@ static void iavf_remove(struct pci_dev *pdev)
                iavf_request_reset(adapter);
                msleep(50);
        }
-       if (iavf_lock_timeout(&adapter->crit_lock, 5000))
-               dev_warn(&adapter->pdev->dev, "failed to acquire crit_lock in %s\n", __FUNCTION__);
 
-       dev_info(&adapter->pdev->dev, "Removing device\n");
+       iavf_misc_irq_disable(adapter);
        /* Shut down all the garbage mashers on the detention level */
-       iavf_change_state(adapter, __IAVF_REMOVE);
+       cancel_work_sync(&adapter->reset_task);
+       cancel_delayed_work_sync(&adapter->watchdog_task);
+       cancel_work_sync(&adapter->adminq_task);
+       cancel_delayed_work_sync(&adapter->client_task);
+
        adapter->aq_required = 0;
        adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
        iavf_free_all_tx_resources(adapter);
        iavf_free_all_rx_resources(adapter);
-       iavf_misc_irq_disable(adapter);
        iavf_free_misc_irq(adapter);
        iavf_reset_interrupt_capability(adapter);
        iavf_free_q_vectors(adapter);
 
-       cancel_delayed_work_sync(&adapter->watchdog_task);
-
-       cancel_work_sync(&adapter->adminq_task);
-
        iavf_free_rss(adapter);
 
        if (hw->aq.asq.count)
@@ -4012,8 +4020,6 @@ static void iavf_remove(struct pci_dev *pdev)
        mutex_destroy(&adapter->client_lock);
        mutex_unlock(&adapter->crit_lock);
        mutex_destroy(&adapter->crit_lock);
-       mutex_unlock(&adapter->remove_lock);
-       mutex_destroy(&adapter->remove_lock);
 
        iounmap(hw->hw_addr);
        pci_release_regions(pdev);