Commit ac6ea6e8 authored by Eli Cohen's avatar Eli Cohen Committed by David S. Miller

net/mlx5_core: Use private health thread for each device

Use a single threaded work queue for each device in the system instead of
using one thread for any device. This is required so we can concurrently
process system error handling for all the devices that need that.
Signed-off-by: default avatarEli Cohen <eli@mellanox.com>
Signed-off-by: default avatarOr Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0144a95e
...@@ -57,31 +57,16 @@ enum { ...@@ -57,31 +57,16 @@ enum {
MLX5_HEALTH_SYNDR_HIGH_TEMP = 0x10 MLX5_HEALTH_SYNDR_HIGH_TEMP = 0x10
}; };
static DEFINE_SPINLOCK(health_lock);
static LIST_HEAD(health_list);
static struct work_struct health_work;
static void health_care(struct work_struct *work) static void health_care(struct work_struct *work)
{ {
struct mlx5_core_health *health, *n; struct mlx5_core_health *health;
struct mlx5_core_dev *dev; struct mlx5_core_dev *dev;
struct mlx5_priv *priv; struct mlx5_priv *priv;
LIST_HEAD(tlist);
spin_lock_irq(&health_lock);
list_splice_init(&health_list, &tlist);
spin_unlock_irq(&health_lock);
list_for_each_entry_safe(health, n, &tlist, list) { health = container_of(work, struct mlx5_core_health, work);
priv = container_of(health, struct mlx5_priv, health); priv = container_of(health, struct mlx5_priv, health);
dev = container_of(priv, struct mlx5_core_dev, priv); dev = container_of(priv, struct mlx5_core_dev, priv);
mlx5_core_warn(dev, "handling bad device here\n"); mlx5_core_warn(dev, "handling bad device here\n");
/* nothing yet */
spin_lock_irq(&health_lock);
list_del_init(&health->list);
spin_unlock_irq(&health_lock);
}
} }
static const char *hsynd_str(u8 synd) static const char *hsynd_str(u8 synd)
...@@ -168,11 +153,7 @@ static void poll_health(unsigned long data) ...@@ -168,11 +153,7 @@ static void poll_health(unsigned long data)
if (health->miss_counter == MAX_MISSES) { if (health->miss_counter == MAX_MISSES) {
mlx5_core_err(dev, "device's health compromised\n"); mlx5_core_err(dev, "device's health compromised\n");
print_health_info(dev); print_health_info(dev);
spin_lock_irq(&health_lock); queue_work(health->wq, &health->work);
list_add_tail(&health->list, &health_list);
spin_unlock_irq(&health_lock);
queue_work(mlx5_core_wq, &health_work);
} else { } else {
get_random_bytes(&next, sizeof(next)); get_random_bytes(&next, sizeof(next));
next %= HZ; next %= HZ;
...@@ -185,7 +166,6 @@ void mlx5_start_health_poll(struct mlx5_core_dev *dev) ...@@ -185,7 +166,6 @@ void mlx5_start_health_poll(struct mlx5_core_dev *dev)
{ {
struct mlx5_core_health *health = &dev->priv.health; struct mlx5_core_health *health = &dev->priv.health;
INIT_LIST_HEAD(&health->list);
init_timer(&health->timer); init_timer(&health->timer);
health->health = &dev->iseg->health; health->health = &dev->iseg->health;
health->health_counter = &dev->iseg->health_counter; health->health_counter = &dev->iseg->health_counter;
...@@ -201,18 +181,33 @@ void mlx5_stop_health_poll(struct mlx5_core_dev *dev) ...@@ -201,18 +181,33 @@ void mlx5_stop_health_poll(struct mlx5_core_dev *dev)
struct mlx5_core_health *health = &dev->priv.health; struct mlx5_core_health *health = &dev->priv.health;
del_timer_sync(&health->timer); del_timer_sync(&health->timer);
spin_lock_irq(&health_lock);
if (!list_empty(&health->list))
list_del_init(&health->list);
spin_unlock_irq(&health_lock);
} }
void mlx5_health_cleanup(void) void mlx5_health_cleanup(struct mlx5_core_dev *dev)
{ {
struct mlx5_core_health *health = &dev->priv.health;
destroy_workqueue(health->wq);
} }
void __init mlx5_health_init(void) int mlx5_health_init(struct mlx5_core_dev *dev)
{ {
INIT_WORK(&health_work, health_care); struct mlx5_core_health *health;
char *name;
health = &dev->priv.health;
name = kmalloc(64, GFP_KERNEL);
if (!name)
return -ENOMEM;
strcpy(name, "mlx5_health");
strcat(name, dev_name(&dev->pdev->dev));
health->wq = create_singlethread_workqueue(name);
kfree(name);
if (!health->wq)
return -ENOMEM;
INIT_WORK(&health->work, health_care);
return 0;
} }
...@@ -62,7 +62,6 @@ static int prof_sel = MLX5_DEFAULT_PROF; ...@@ -62,7 +62,6 @@ static int prof_sel = MLX5_DEFAULT_PROF;
module_param_named(prof_sel, prof_sel, int, 0444); module_param_named(prof_sel, prof_sel, int, 0444);
MODULE_PARM_DESC(prof_sel, "profile selector. Valid range 0 - 2"); MODULE_PARM_DESC(prof_sel, "profile selector. Valid range 0 - 2");
struct workqueue_struct *mlx5_core_wq;
static LIST_HEAD(intf_list); static LIST_HEAD(intf_list);
static LIST_HEAD(dev_list); static LIST_HEAD(dev_list);
static DEFINE_MUTEX(intf_mutex); static DEFINE_MUTEX(intf_mutex);
...@@ -1046,6 +1045,7 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv) ...@@ -1046,6 +1045,7 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv)
static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv) static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv)
{ {
int err;
mlx5_unregister_device(dev); mlx5_unregister_device(dev);
mlx5_cleanup_mr_table(dev); mlx5_cleanup_mr_table(dev);
...@@ -1060,9 +1060,10 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv) ...@@ -1060,9 +1060,10 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv)
mlx5_eq_cleanup(dev); mlx5_eq_cleanup(dev);
mlx5_disable_msix(dev); mlx5_disable_msix(dev);
mlx5_stop_health_poll(dev); mlx5_stop_health_poll(dev);
if (mlx5_cmd_teardown_hca(dev)) { err = mlx5_cmd_teardown_hca(dev);
if (err) {
dev_err(&dev->pdev->dev, "tear_down_hca failed, skip cleanup\n"); dev_err(&dev->pdev->dev, "tear_down_hca failed, skip cleanup\n");
return 1; goto out;
} }
mlx5_pagealloc_stop(dev); mlx5_pagealloc_stop(dev);
mlx5_reclaim_startup_pages(dev); mlx5_reclaim_startup_pages(dev);
...@@ -1070,11 +1071,12 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv) ...@@ -1070,11 +1071,12 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv)
mlx5_pagealloc_cleanup(dev); mlx5_pagealloc_cleanup(dev);
mlx5_cmd_cleanup(dev); mlx5_cmd_cleanup(dev);
return 0; out:
return err;
} }
static void mlx5_core_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event, static void mlx5_core_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event,
unsigned long param) unsigned long param)
{ {
struct mlx5_priv *priv = &dev->priv; struct mlx5_priv *priv = &dev->priv;
struct mlx5_device_context *dev_ctx; struct mlx5_device_context *dev_ctx;
...@@ -1129,14 +1131,22 @@ static int init_one(struct pci_dev *pdev, ...@@ -1129,14 +1131,22 @@ static int init_one(struct pci_dev *pdev,
goto clean_dev; goto clean_dev;
} }
err = mlx5_health_init(dev);
if (err) {
dev_err(&pdev->dev, "mlx5_health_init failed with error code %d\n", err);
goto close_pci;
}
err = mlx5_load_one(dev, priv); err = mlx5_load_one(dev, priv);
if (err) { if (err) {
dev_err(&pdev->dev, "mlx5_load_one failed with error code %d\n", err); dev_err(&pdev->dev, "mlx5_load_one failed with error code %d\n", err);
goto close_pci; goto clean_health;
} }
return 0; return 0;
clean_health:
mlx5_health_cleanup(dev);
close_pci: close_pci:
mlx5_pci_close(dev, priv); mlx5_pci_close(dev, priv);
clean_dev: clean_dev:
...@@ -1153,8 +1163,10 @@ static void remove_one(struct pci_dev *pdev) ...@@ -1153,8 +1163,10 @@ static void remove_one(struct pci_dev *pdev)
if (mlx5_unload_one(dev, priv)) { if (mlx5_unload_one(dev, priv)) {
dev_err(&dev->pdev->dev, "mlx5_unload_one failed\n"); dev_err(&dev->pdev->dev, "mlx5_unload_one failed\n");
mlx5_health_cleanup(dev);
return; return;
} }
mlx5_health_cleanup(dev);
mlx5_pci_close(dev, priv); mlx5_pci_close(dev, priv);
pci_set_drvdata(pdev, NULL); pci_set_drvdata(pdev, NULL);
kfree(dev); kfree(dev);
...@@ -1184,16 +1196,10 @@ static int __init init(void) ...@@ -1184,16 +1196,10 @@ static int __init init(void)
int err; int err;
mlx5_register_debugfs(); mlx5_register_debugfs();
mlx5_core_wq = create_singlethread_workqueue("mlx5_core_wq");
if (!mlx5_core_wq) {
err = -ENOMEM;
goto err_debug;
}
mlx5_health_init();
err = pci_register_driver(&mlx5_core_driver); err = pci_register_driver(&mlx5_core_driver);
if (err) if (err)
goto err_health; goto err_debug;
#ifdef CONFIG_MLX5_CORE_EN #ifdef CONFIG_MLX5_CORE_EN
mlx5e_init(); mlx5e_init();
...@@ -1201,9 +1207,6 @@ static int __init init(void) ...@@ -1201,9 +1207,6 @@ static int __init init(void)
return 0; return 0;
err_health:
mlx5_health_cleanup();
destroy_workqueue(mlx5_core_wq);
err_debug: err_debug:
mlx5_unregister_debugfs(); mlx5_unregister_debugfs();
return err; return err;
...@@ -1215,8 +1218,6 @@ static void __exit cleanup(void) ...@@ -1215,8 +1218,6 @@ static void __exit cleanup(void)
mlx5e_cleanup(); mlx5e_cleanup();
#endif #endif
pci_unregister_driver(&mlx5_core_driver); pci_unregister_driver(&mlx5_core_driver);
mlx5_health_cleanup();
destroy_workqueue(mlx5_core_wq);
mlx5_unregister_debugfs(); mlx5_unregister_debugfs();
} }
......
...@@ -391,9 +391,10 @@ struct mlx5_core_health { ...@@ -391,9 +391,10 @@ struct mlx5_core_health {
struct health_buffer __iomem *health; struct health_buffer __iomem *health;
__be32 __iomem *health_counter; __be32 __iomem *health_counter;
struct timer_list timer; struct timer_list timer;
struct list_head list;
u32 prev; u32 prev;
int miss_counter; int miss_counter;
struct workqueue_struct *wq;
struct work_struct work;
}; };
struct mlx5_cq_table { struct mlx5_cq_table {
...@@ -676,8 +677,8 @@ int mlx5_alloc_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari); ...@@ -676,8 +677,8 @@ int mlx5_alloc_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari);
int mlx5_free_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari); int mlx5_free_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari);
int mlx5_alloc_map_uar(struct mlx5_core_dev *mdev, struct mlx5_uar *uar); int mlx5_alloc_map_uar(struct mlx5_core_dev *mdev, struct mlx5_uar *uar);
void mlx5_unmap_free_uar(struct mlx5_core_dev *mdev, struct mlx5_uar *uar); void mlx5_unmap_free_uar(struct mlx5_core_dev *mdev, struct mlx5_uar *uar);
void mlx5_health_cleanup(void); void mlx5_health_cleanup(struct mlx5_core_dev *dev);
void __init mlx5_health_init(void); int mlx5_health_init(struct mlx5_core_dev *dev);
void mlx5_start_health_poll(struct mlx5_core_dev *dev); void mlx5_start_health_poll(struct mlx5_core_dev *dev);
void mlx5_stop_health_poll(struct mlx5_core_dev *dev); void mlx5_stop_health_poll(struct mlx5_core_dev *dev);
int mlx5_buf_alloc_node(struct mlx5_core_dev *dev, int size, int mlx5_buf_alloc_node(struct mlx5_core_dev *dev, int size,
......
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