net/mlx4_core: Refactor the catas flow to work per device
authorYishai Hadas <yishaih@mellanox.com>
Sun, 25 Jan 2015 14:59:37 +0000 (16:59 +0200)
committerDavid S. Miller <davem@davemloft.net>
Sun, 25 Jan 2015 22:43:14 +0000 (14:43 -0800)
Using a WQ per device instead of a single global WQ, this allows
independent reset handling per device even when SRIOV is used.

This comes as a pre-patch for supporting chip reset
for both native and SRIOV.

Signed-off-by: Yishai Hadas <yishaih@mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlx4/catas.c
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/mellanox/mlx4/mlx4.h
include/linux/mlx4/device.h

index 1a102c9bac9905f73b903035d86f382e0c9dc743..5bb9aa6e281d63d009cc1c701673946487138ae4 100644 (file)
@@ -40,10 +40,7 @@ enum {
        MLX4_CATAS_POLL_INTERVAL        = 5 * HZ,
 };
 
-static DEFINE_SPINLOCK(catas_lock);
 
-static LIST_HEAD(catas_list);
-static struct work_struct catas_work;
 
 static int internal_err_reset = 1;
 module_param(internal_err_reset, int, 0644);
@@ -77,13 +74,9 @@ static void poll_catas(unsigned long dev_ptr)
                        dump_err_buf(dev);
                        mlx4_dispatch_event(dev, MLX4_DEV_EVENT_CATASTROPHIC_ERROR, 0);
 
-                       if (internal_err_reset) {
-                               spin_lock(&catas_lock);
-                               list_add(&priv->catas_err.list, &catas_list);
-                               spin_unlock(&catas_lock);
-
-                               queue_work(mlx4_wq, &catas_work);
-                       }
+                       if (internal_err_reset)
+                               queue_work(dev->persist->catas_wq,
+                                          &dev->persist->catas_work);
                }
        } else
                mod_timer(&priv->catas_err.timer,
@@ -92,34 +85,23 @@ static void poll_catas(unsigned long dev_ptr)
 
 static void catas_reset(struct work_struct *work)
 {
-       struct mlx4_priv *priv, *tmppriv;
-       struct mlx4_dev *dev;
-       struct mlx4_dev_persistent *persist;
-
-       LIST_HEAD(tlist);
+       struct mlx4_dev_persistent *persist =
+               container_of(work, struct mlx4_dev_persistent,
+                            catas_work);
+       struct pci_dev *pdev = persist->pdev;
        int ret;
 
-       spin_lock_irq(&catas_lock);
-       list_splice_init(&catas_list, &tlist);
-       spin_unlock_irq(&catas_lock);
-
-       list_for_each_entry_safe(priv, tmppriv, &tlist, catas_err.list) {
-               struct pci_dev *pdev = priv->dev.persist->pdev;
-
-               /* If the device is off-line, we cannot reset it */
-               if (pci_channel_offline(pdev))
-                       continue;
+       /* If the device is off-line, we cannot reset it */
+       if (pci_channel_offline(pdev))
+               return;
 
-               ret = mlx4_restart_one(priv->dev.persist->pdev);
-               /* 'priv' now is not valid */
-               if (ret)
-                       pr_err("mlx4 %s: Reset failed (%d)\n",
-                              pci_name(pdev), ret);
-               else {
-                       persist  = pci_get_drvdata(pdev);
-                       mlx4_dbg(persist->dev, "Reset succeeded\n");
-               }
-       }
+       ret = mlx4_restart_one(pdev);
+       /* 'priv' now is not valid */
+       if (ret)
+               pr_err("mlx4 %s: Reset failed (%d)\n",
+                      pci_name(pdev), ret);
+       else
+               mlx4_dbg(persist->dev, "Reset succeeded\n");
 }
 
 void mlx4_start_catas_poll(struct mlx4_dev *dev)
@@ -158,15 +140,26 @@ void mlx4_stop_catas_poll(struct mlx4_dev *dev)
 
        del_timer_sync(&priv->catas_err.timer);
 
-       if (priv->catas_err.map)
+       if (priv->catas_err.map) {
                iounmap(priv->catas_err.map);
+               priv->catas_err.map = NULL;
+       }
+}
 
-       spin_lock_irq(&catas_lock);
-       list_del(&priv->catas_err.list);
-       spin_unlock_irq(&catas_lock);
+int  mlx4_catas_init(struct mlx4_dev *dev)
+{
+       INIT_WORK(&dev->persist->catas_work, catas_reset);
+       dev->persist->catas_wq = create_singlethread_workqueue("mlx4_health");
+       if (!dev->persist->catas_wq)
+               return -ENOMEM;
+
+       return 0;
 }
 
-void  __init mlx4_catas_init(void)
+void mlx4_catas_end(struct mlx4_dev *dev)
 {
-       INIT_WORK(&catas_work, catas_reset);
+       if (dev->persist->catas_wq) {
+               destroy_workqueue(dev->persist->catas_wq);
+               dev->persist->catas_wq = NULL;
+       }
 }
index 2c5a555dff89939d54ee71dbcdb430c1ec112839..a61694cc1476c38f775b11407ab3d4b5e3458b1d 100644 (file)
@@ -3064,11 +3064,19 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data,
                }
        }
 
-       err = mlx4_load_one(pdev, pci_dev_data, total_vfs, nvfs, priv);
+       err = mlx4_catas_init(&priv->dev);
        if (err)
                goto err_release_regions;
+
+       err = mlx4_load_one(pdev, pci_dev_data, total_vfs, nvfs, priv);
+       if (err)
+               goto err_catas;
+
        return 0;
 
+err_catas:
+       mlx4_catas_end(&priv->dev);
+
 err_release_regions:
        pci_release_regions(pdev);
 
@@ -3219,6 +3227,7 @@ static void mlx4_remove_one(struct pci_dev *pdev)
        struct mlx4_priv *priv = mlx4_priv(dev);
 
        mlx4_unload_one(pdev);
+       mlx4_catas_end(dev);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
        kfree(dev->persist);
@@ -3403,7 +3412,6 @@ static int __init mlx4_init(void)
        if (mlx4_verify_params())
                return -EINVAL;
 
-       mlx4_catas_init();
 
        mlx4_wq = create_singlethread_workqueue("mlx4");
        if (!mlx4_wq)
index faa37ab75a9d53f333a77e2d1fa586d799acb840..d41af84f965bf4f84ea6163c4097d9e768b9efd5 100644 (file)
@@ -995,7 +995,8 @@ void __mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn);
 
 void mlx4_start_catas_poll(struct mlx4_dev *dev);
 void mlx4_stop_catas_poll(struct mlx4_dev *dev);
-void mlx4_catas_init(void);
+int mlx4_catas_init(struct mlx4_dev *dev);
+void mlx4_catas_end(struct mlx4_dev *dev);
 int mlx4_restart_one(struct pci_dev *pdev);
 int mlx4_register_device(struct mlx4_dev *dev);
 void mlx4_unregister_device(struct mlx4_dev *dev);
index 8c3837ac1a2de965da6964dc07c41d5d4a78b630..da425d2f37086d3638889c601965e2d6990c9d1f 100644 (file)
@@ -751,6 +751,8 @@ struct mlx4_dev_persistent {
        int                     num_vfs;
        enum mlx4_port_type curr_port_type[MLX4_MAX_PORTS + 1];
        enum mlx4_port_type curr_port_poss_type[MLX4_MAX_PORTS + 1];
+       struct work_struct      catas_work;
+       struct workqueue_struct *catas_wq;
 };
 
 struct mlx4_dev {