Commit e63a4401 authored by Wei Yang's avatar Wei Yang Committed by Jiri Slaby

net/mlx4_core: Preserve pci_dev_data after __mlx4_remove_one()

[ Upstream commit befdf897 ]

pci_match_id() just match the static pci_device_id, which may return NULL if
someone binds the driver to a device manually using
/sys/bus/pci/drivers/.../new_id.

This patch wrap up a helper function __mlx4_remove_one() which does the tear
down function but preserve the drv_data. Functions like
mlx4_pci_err_detected() and mlx4_restart_one() will call this one with out
releasing drvdata.

Fixes: 97a5221f "net/mlx4_core: pass pci_device_id.driver_data to __mlx4_init_one during reset".

CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Amir Vadai <amirv@mellanox.com>
CC: Jack Morgenstein <jackm@dev.mellanox.co.il>
CC: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: default avatarWei Yang <weiyang@linux.vnet.ibm.com>
Acked-by: default avatarJack Morgenstein <jackm@dev.mellanox.co.il>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarJiri Slaby <jslaby@suse.cz>
parent e359cc96
...@@ -2134,13 +2134,8 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data) ...@@ -2134,13 +2134,8 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data)
/* Allow large DMA segments, up to the firmware limit of 1 GB */ /* Allow large DMA segments, up to the firmware limit of 1 GB */
dma_set_max_seg_size(&pdev->dev, 1024 * 1024 * 1024); dma_set_max_seg_size(&pdev->dev, 1024 * 1024 * 1024);
priv = kzalloc(sizeof(*priv), GFP_KERNEL); dev = pci_get_drvdata(pdev);
if (!priv) { priv = mlx4_priv(dev);
err = -ENOMEM;
goto err_release_regions;
}
dev = &priv->dev;
dev->pdev = pdev; dev->pdev = pdev;
INIT_LIST_HEAD(&priv->ctx_list); INIT_LIST_HEAD(&priv->ctx_list);
spin_lock_init(&priv->ctx_lock); spin_lock_init(&priv->ctx_lock);
...@@ -2308,8 +2303,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data) ...@@ -2308,8 +2303,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data)
mlx4_sense_init(dev); mlx4_sense_init(dev);
mlx4_start_sense(dev); mlx4_start_sense(dev);
priv->pci_dev_data = pci_dev_data; priv->removed = 0;
pci_set_drvdata(pdev, dev);
return 0; return 0;
...@@ -2375,84 +2369,108 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data) ...@@ -2375,84 +2369,108 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data)
static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{ {
struct mlx4_priv *priv;
struct mlx4_dev *dev;
printk_once(KERN_INFO "%s", mlx4_version); printk_once(KERN_INFO "%s", mlx4_version);
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
dev = &priv->dev;
pci_set_drvdata(pdev, dev);
priv->pci_dev_data = id->driver_data;
return __mlx4_init_one(pdev, id->driver_data); return __mlx4_init_one(pdev, id->driver_data);
} }
static void mlx4_remove_one(struct pci_dev *pdev) static void __mlx4_remove_one(struct pci_dev *pdev)
{ {
struct mlx4_dev *dev = pci_get_drvdata(pdev); struct mlx4_dev *dev = pci_get_drvdata(pdev);
struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_priv *priv = mlx4_priv(dev);
int pci_dev_data;
int p; int p;
if (dev) { if (priv->removed)
/* in SRIOV it is not allowed to unload the pf's return;
* driver while there are alive vf's */
if (mlx4_is_master(dev)) {
if (mlx4_how_many_lives_vf(dev))
printk(KERN_ERR "Removing PF when there are assigned VF's !!!\n");
}
mlx4_stop_sense(dev);
mlx4_unregister_device(dev);
for (p = 1; p <= dev->caps.num_ports; p++) { pci_dev_data = priv->pci_dev_data;
mlx4_cleanup_port_info(&priv->port[p]);
mlx4_CLOSE_PORT(dev, p);
}
if (mlx4_is_master(dev)) /* in SRIOV it is not allowed to unload the pf's
mlx4_free_resource_tracker(dev, * driver while there are alive vf's */
RES_TR_FREE_SLAVES_ONLY); if (mlx4_is_master(dev) && mlx4_how_many_lives_vf(dev))
printk(KERN_ERR "Removing PF when there are assigned VF's !!!\n");
mlx4_cleanup_counters_table(dev); mlx4_stop_sense(dev);
mlx4_cleanup_qp_table(dev); mlx4_unregister_device(dev);
mlx4_cleanup_srq_table(dev);
mlx4_cleanup_cq_table(dev);
mlx4_cmd_use_polling(dev);
mlx4_cleanup_eq_table(dev);
mlx4_cleanup_mcg_table(dev);
mlx4_cleanup_mr_table(dev);
mlx4_cleanup_xrcd_table(dev);
mlx4_cleanup_pd_table(dev);
if (mlx4_is_master(dev)) for (p = 1; p <= dev->caps.num_ports; p++) {
mlx4_free_resource_tracker(dev, mlx4_cleanup_port_info(&priv->port[p]);
RES_TR_FREE_STRUCTS_ONLY); mlx4_CLOSE_PORT(dev, p);
}
iounmap(priv->kar);
mlx4_uar_free(dev, &priv->driver_uar);
mlx4_cleanup_uar_table(dev);
if (!mlx4_is_slave(dev))
mlx4_clear_steering(dev);
mlx4_free_eq_table(dev);
if (mlx4_is_master(dev))
mlx4_multi_func_cleanup(dev);
mlx4_close_hca(dev);
if (mlx4_is_slave(dev))
mlx4_multi_func_cleanup(dev);
mlx4_cmd_cleanup(dev);
if (dev->flags & MLX4_FLAG_MSI_X)
pci_disable_msix(pdev);
if (dev->flags & MLX4_FLAG_SRIOV) {
mlx4_warn(dev, "Disabling SR-IOV\n");
pci_disable_sriov(pdev);
}
if (!mlx4_is_slave(dev)) if (mlx4_is_master(dev))
mlx4_free_ownership(dev); mlx4_free_resource_tracker(dev,
RES_TR_FREE_SLAVES_ONLY);
mlx4_cleanup_counters_table(dev);
mlx4_cleanup_qp_table(dev);
mlx4_cleanup_srq_table(dev);
mlx4_cleanup_cq_table(dev);
mlx4_cmd_use_polling(dev);
mlx4_cleanup_eq_table(dev);
mlx4_cleanup_mcg_table(dev);
mlx4_cleanup_mr_table(dev);
mlx4_cleanup_xrcd_table(dev);
mlx4_cleanup_pd_table(dev);
kfree(dev->caps.qp0_tunnel); if (mlx4_is_master(dev))
kfree(dev->caps.qp0_proxy); mlx4_free_resource_tracker(dev,
kfree(dev->caps.qp1_tunnel); RES_TR_FREE_STRUCTS_ONLY);
kfree(dev->caps.qp1_proxy);
kfree(priv); iounmap(priv->kar);
pci_release_regions(pdev); mlx4_uar_free(dev, &priv->driver_uar);
pci_disable_device(pdev); mlx4_cleanup_uar_table(dev);
pci_set_drvdata(pdev, NULL); if (!mlx4_is_slave(dev))
mlx4_clear_steering(dev);
mlx4_free_eq_table(dev);
if (mlx4_is_master(dev))
mlx4_multi_func_cleanup(dev);
mlx4_close_hca(dev);
if (mlx4_is_slave(dev))
mlx4_multi_func_cleanup(dev);
mlx4_cmd_cleanup(dev);
if (dev->flags & MLX4_FLAG_MSI_X)
pci_disable_msix(pdev);
if (dev->flags & MLX4_FLAG_SRIOV) {
mlx4_warn(dev, "Disabling SR-IOV\n");
pci_disable_sriov(pdev);
} }
if (!mlx4_is_slave(dev))
mlx4_free_ownership(dev);
kfree(dev->caps.qp0_tunnel);
kfree(dev->caps.qp0_proxy);
kfree(dev->caps.qp1_tunnel);
kfree(dev->caps.qp1_proxy);
pci_release_regions(pdev);
pci_disable_device(pdev);
memset(priv, 0, sizeof(*priv));
priv->pci_dev_data = pci_dev_data;
priv->removed = 1;
}
static void mlx4_remove_one(struct pci_dev *pdev)
{
struct mlx4_dev *dev = pci_get_drvdata(pdev);
struct mlx4_priv *priv = mlx4_priv(dev);
__mlx4_remove_one(pdev);
kfree(priv);
pci_set_drvdata(pdev, NULL);
} }
int mlx4_restart_one(struct pci_dev *pdev) int mlx4_restart_one(struct pci_dev *pdev)
...@@ -2462,7 +2480,7 @@ int mlx4_restart_one(struct pci_dev *pdev) ...@@ -2462,7 +2480,7 @@ int mlx4_restart_one(struct pci_dev *pdev)
int pci_dev_data; int pci_dev_data;
pci_dev_data = priv->pci_dev_data; pci_dev_data = priv->pci_dev_data;
mlx4_remove_one(pdev); __mlx4_remove_one(pdev);
return __mlx4_init_one(pdev, pci_dev_data); return __mlx4_init_one(pdev, pci_dev_data);
} }
...@@ -2517,7 +2535,7 @@ MODULE_DEVICE_TABLE(pci, mlx4_pci_table); ...@@ -2517,7 +2535,7 @@ MODULE_DEVICE_TABLE(pci, mlx4_pci_table);
static pci_ers_result_t mlx4_pci_err_detected(struct pci_dev *pdev, static pci_ers_result_t mlx4_pci_err_detected(struct pci_dev *pdev,
pci_channel_state_t state) pci_channel_state_t state)
{ {
mlx4_remove_one(pdev); __mlx4_remove_one(pdev);
return state == pci_channel_io_perm_failure ? return state == pci_channel_io_perm_failure ?
PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET; PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET;
...@@ -2525,11 +2543,11 @@ static pci_ers_result_t mlx4_pci_err_detected(struct pci_dev *pdev, ...@@ -2525,11 +2543,11 @@ static pci_ers_result_t mlx4_pci_err_detected(struct pci_dev *pdev,
static pci_ers_result_t mlx4_pci_slot_reset(struct pci_dev *pdev) static pci_ers_result_t mlx4_pci_slot_reset(struct pci_dev *pdev)
{ {
const struct pci_device_id *id; struct mlx4_dev *dev = pci_get_drvdata(pdev);
int ret; struct mlx4_priv *priv = mlx4_priv(dev);
int ret;
id = pci_match_id(mlx4_pci_table, pdev); ret = __mlx4_init_one(pdev, priv->pci_dev_data);
ret = __mlx4_init_one(pdev, id->driver_data);
return ret ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED; return ret ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
} }
......
...@@ -774,6 +774,7 @@ struct mlx4_priv { ...@@ -774,6 +774,7 @@ struct mlx4_priv {
spinlock_t ctx_lock; spinlock_t ctx_lock;
int pci_dev_data; int pci_dev_data;
int removed;
struct list_head pgdir_list; struct list_head pgdir_list;
struct mutex pgdir_mutex; struct mutex pgdir_mutex;
......
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