Skip to content

Commit 97834eb

Browse files
Erez ShitritSaeed Mahameed
authored andcommitted
net/mlx5: Delay events till ib registration ends
When mlx5_ib registers itself to mlx5_core as an interface, it will call mlx5_add_device which will call mlx5_ib interface add callback, in case the latter successfully returns, only then mlx5_core will add it to the interface list and async events will be forwarded to mlx5_ib. Between mlx5_ib interface add callback and mlx5_core adding the mlx5_ib interface to its devices list, arriving mlx5_core events can be missed by the new mlx5_ib registering interface. In other words: thread 1: mlx5_ib: mlx5_register_interface(dev) thread 1: mlx5_core: mlx5_add_device(dev) thread 1: mlx5_core: ctx = dev->add => (mlx5_ib)->mlx5_ib_add thread 2: mlx5_core_event: **new event arrives, forward to dev_list thread 1: mlx5_core: add_ctx_to_dev_list(ctx) /* previous event was missed by the new interface.*/ It is ok to miss events before dev->add (mlx5_ib)->mlx5_ib_add_device but not after. We fix this race by accumulating the events that come between the ib_register_device (inside mlx5_add_device->(dev->add)) till the adding to the list completes and fire them to the new registering interface after that. Fixes: f1ee87f ("net/mlx5: Organize device list API in one place") Signed-off-by: Erez Shitrit <erezsh@mellanox.com> Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
1 parent e80541e commit 97834eb

File tree

3 files changed

+79
-0
lines changed

3 files changed

+79
-0
lines changed

drivers/net/ethernet/mellanox/mlx5/core/dev.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,70 @@ struct mlx5_device_context {
4545
unsigned long state;
4646
};
4747

48+
struct mlx5_delayed_event {
49+
struct list_head list;
50+
struct mlx5_core_dev *dev;
51+
enum mlx5_dev_event event;
52+
unsigned long param;
53+
};
54+
4855
enum {
4956
MLX5_INTERFACE_ADDED,
5057
MLX5_INTERFACE_ATTACHED,
5158
};
5259

60+
static void add_delayed_event(struct mlx5_priv *priv,
61+
struct mlx5_core_dev *dev,
62+
enum mlx5_dev_event event,
63+
unsigned long param)
64+
{
65+
struct mlx5_delayed_event *delayed_event;
66+
67+
delayed_event = kzalloc(sizeof(*delayed_event), GFP_ATOMIC);
68+
if (!delayed_event) {
69+
mlx5_core_err(dev, "event %d is missed\n", event);
70+
return;
71+
}
72+
73+
mlx5_core_dbg(dev, "Accumulating event %d\n", event);
74+
delayed_event->dev = dev;
75+
delayed_event->event = event;
76+
delayed_event->param = param;
77+
list_add_tail(&delayed_event->list, &priv->waiting_events_list);
78+
}
79+
80+
static void fire_delayed_event_locked(struct mlx5_device_context *dev_ctx,
81+
struct mlx5_core_dev *dev,
82+
struct mlx5_priv *priv)
83+
{
84+
struct mlx5_delayed_event *de;
85+
struct mlx5_delayed_event *n;
86+
87+
/* stop delaying events */
88+
priv->is_accum_events = false;
89+
90+
/* fire all accumulated events before new event comes */
91+
list_for_each_entry_safe(de, n, &priv->waiting_events_list, list) {
92+
dev_ctx->intf->event(dev, dev_ctx->context, de->event, de->param);
93+
list_del(&de->list);
94+
kfree(de);
95+
}
96+
}
97+
98+
static void cleanup_delayed_evets(struct mlx5_priv *priv)
99+
{
100+
struct mlx5_delayed_event *de;
101+
struct mlx5_delayed_event *n;
102+
103+
spin_lock_irq(&priv->ctx_lock);
104+
priv->is_accum_events = false;
105+
list_for_each_entry_safe(de, n, &priv->waiting_events_list, list) {
106+
list_del(&de->list);
107+
kfree(de);
108+
}
109+
spin_unlock_irq(&priv->ctx_lock);
110+
}
111+
53112
void mlx5_add_device(struct mlx5_interface *intf, struct mlx5_priv *priv)
54113
{
55114
struct mlx5_device_context *dev_ctx;
@@ -63,6 +122,12 @@ void mlx5_add_device(struct mlx5_interface *intf, struct mlx5_priv *priv)
63122
return;
64123

65124
dev_ctx->intf = intf;
125+
/* accumulating events that can come after mlx5_ib calls to
126+
* ib_register_device, till adding that interface to the events list.
127+
*/
128+
129+
priv->is_accum_events = true;
130+
66131
dev_ctx->context = intf->add(dev);
67132
set_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state);
68133
if (intf->attach)
@@ -71,6 +136,9 @@ void mlx5_add_device(struct mlx5_interface *intf, struct mlx5_priv *priv)
71136
if (dev_ctx->context) {
72137
spin_lock_irq(&priv->ctx_lock);
73138
list_add_tail(&dev_ctx->list, &priv->ctx_list);
139+
140+
fire_delayed_event_locked(dev_ctx, dev, priv);
141+
74142
#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
75143
if (dev_ctx->intf->pfault) {
76144
if (priv->pfault) {
@@ -84,6 +152,8 @@ void mlx5_add_device(struct mlx5_interface *intf, struct mlx5_priv *priv)
84152
spin_unlock_irq(&priv->ctx_lock);
85153
} else {
86154
kfree(dev_ctx);
155+
/* delete all accumulated events */
156+
cleanup_delayed_evets(priv);
87157
}
88158
}
89159

@@ -341,6 +411,9 @@ void mlx5_core_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event,
341411

342412
spin_lock_irqsave(&priv->ctx_lock, flags);
343413

414+
if (priv->is_accum_events)
415+
add_delayed_event(priv, dev, event, param);
416+
344417
list_for_each_entry(dev_ctx, &priv->ctx_list, list)
345418
if (dev_ctx->intf->event)
346419
dev_ctx->intf->event(dev, dev_ctx->context, event, param);

drivers/net/ethernet/mellanox/mlx5/core/main.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,6 +1343,9 @@ static int init_one(struct pci_dev *pdev,
13431343
mutex_init(&dev->pci_status_mutex);
13441344
mutex_init(&dev->intf_state_mutex);
13451345

1346+
INIT_LIST_HEAD(&priv->waiting_events_list);
1347+
priv->is_accum_events = false;
1348+
13461349
#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
13471350
err = init_srcu_struct(&priv->pfault_srcu);
13481351
if (err) {

include/linux/mlx5/driver.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,9 @@ struct mlx5_priv {
647647
struct list_head ctx_list;
648648
spinlock_t ctx_lock;
649649

650+
struct list_head waiting_events_list;
651+
bool is_accum_events;
652+
650653
struct mlx5_flow_steering *steering;
651654
struct mlx5_mpfs *mpfs;
652655
struct mlx5_eswitch *eswitch;

0 commit comments

Comments
 (0)