net/mlx4_core: Avoid repeated calls to pci enable/disable
[cascardo/linux.git] / drivers / net / ethernet / mellanox / mlx4 / main.c
index 5d45aa3..12c77a7 100644 (file)
@@ -3172,6 +3172,34 @@ static int mlx4_check_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap
        return 0;
 }
 
+static int mlx4_pci_enable_device(struct mlx4_dev *dev)
+{
+       struct pci_dev *pdev = dev->persist->pdev;
+       int err = 0;
+
+       mutex_lock(&dev->persist->pci_status_mutex);
+       if (dev->persist->pci_status == MLX4_PCI_STATUS_DISABLED) {
+               err = pci_enable_device(pdev);
+               if (!err)
+                       dev->persist->pci_status = MLX4_PCI_STATUS_ENABLED;
+       }
+       mutex_unlock(&dev->persist->pci_status_mutex);
+
+       return err;
+}
+
+static void mlx4_pci_disable_device(struct mlx4_dev *dev)
+{
+       struct pci_dev *pdev = dev->persist->pdev;
+
+       mutex_lock(&dev->persist->pci_status_mutex);
+       if (dev->persist->pci_status == MLX4_PCI_STATUS_ENABLED) {
+               pci_disable_device(pdev);
+               dev->persist->pci_status = MLX4_PCI_STATUS_DISABLED;
+       }
+       mutex_unlock(&dev->persist->pci_status_mutex);
+}
+
 static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data,
                         int total_vfs, int *nvfs, struct mlx4_priv *priv,
                         int reset_flow)
@@ -3582,7 +3610,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data,
 
        pr_info(DRV_NAME ": Initializing %s\n", pci_name(pdev));
 
-       err = pci_enable_device(pdev);
+       err = mlx4_pci_enable_device(&priv->dev);
        if (err) {
                dev_err(&pdev->dev, "Cannot enable PCI device, aborting\n");
                return err;
@@ -3715,7 +3743,7 @@ err_release_regions:
        pci_release_regions(pdev);
 
 err_disable_pdev:
-       pci_disable_device(pdev);
+       mlx4_pci_disable_device(&priv->dev);
        pci_set_drvdata(pdev, NULL);
        return err;
 }
@@ -3775,6 +3803,7 @@ static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        priv->pci_dev_data = id->driver_data;
        mutex_init(&dev->persist->device_state_mutex);
        mutex_init(&dev->persist->interface_state_mutex);
+       mutex_init(&dev->persist->pci_status_mutex);
 
        ret = devlink_register(devlink, &pdev->dev);
        if (ret)
@@ -3923,7 +3952,7 @@ static void mlx4_remove_one(struct pci_dev *pdev)
        }
 
        pci_release_regions(pdev);
-       pci_disable_device(pdev);
+       mlx4_pci_disable_device(dev);
        devlink_unregister(devlink);
        kfree(dev->persist);
        devlink_free(devlink);
@@ -4042,7 +4071,7 @@ static pci_ers_result_t mlx4_pci_err_detected(struct pci_dev *pdev,
        if (state == pci_channel_io_perm_failure)
                return PCI_ERS_RESULT_DISCONNECT;
 
-       pci_disable_device(pdev);
+       mlx4_pci_disable_device(persist->dev);
        return PCI_ERS_RESULT_NEED_RESET;
 }
 
@@ -4053,7 +4082,7 @@ static pci_ers_result_t mlx4_pci_slot_reset(struct pci_dev *pdev)
        int err;
 
        mlx4_err(dev, "mlx4_pci_slot_reset was called\n");
-       err = pci_enable_device(pdev);
+       err = mlx4_pci_enable_device(dev);
        if (err) {
                mlx4_err(dev, "Can not re-enable device, err=%d\n", err);
                return PCI_ERS_RESULT_DISCONNECT;