Date: Mon, 20 Jul 2026 20:53:28 +0000 From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Cc: Ariel Ehrenberg <aehrenberg@nvidia.com> Subject: git: 8d518f4b482f - stable/15 - mlx5_ib: do not consume CMD/PAGE_REQUEST events in the DEVX notifier Message-ID: <6a5e8ac8.1de17.3ff79b40@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch stable/15 has been updated by kib: URL: https://cgit.FreeBSD.org/src/commit/?id=8d518f4b482f64449b2bbb36a7c4627e80a3a93a commit 8d518f4b482f64449b2bbb36a7c4627e80a3a93a Author: Ariel Ehrenberg <aehrenberg@nvidia.com> AuthorDate: 2026-06-09 11:20:08 +0000 Commit: Konstantin Belousov <kib@FreeBSD.org> CommitDate: 2026-07-20 20:26:05 +0000 mlx5_ib: do not consume CMD/PAGE_REQUEST events in the DEVX notifier (cherry picked from commit 2e3b3ce881490adcef17905450d0402030975051) --- sys/dev/mlx5/mlx5_core/mlx5_eq.c | 33 ++++++++++++++++++++++++++++++--- sys/dev/mlx5/mlx5_ib/mlx5_ib_devx.c | 35 ++++++++++++++++++++++++++++------- 2 files changed, 58 insertions(+), 10 deletions(-) diff --git a/sys/dev/mlx5/mlx5_core/mlx5_eq.c b/sys/dev/mlx5/mlx5_core/mlx5_eq.c index 1090f8638171..f564b88c48b4 100644 --- a/sys/dev/mlx5/mlx5_core/mlx5_eq.c +++ b/sys/dev/mlx5/mlx5_core/mlx5_eq.c @@ -238,6 +238,10 @@ static int mlx5_eq_int(struct mlx5_core_dev *dev, struct mlx5_eq *eq) u8 port; while ((eqe = next_eqe_sw(eq))) { + bool (*devx_cb)(struct mlx5_core_dev *mdev, + uint8_t event_type, void *data); + bool devx_consumed = false; + /* * Make sure we read EQ entry contents after we've * checked the ownership bit. @@ -247,9 +251,32 @@ static int mlx5_eq_int(struct mlx5_core_dev *dev, struct mlx5_eq *eq) mlx5_core_dbg(eq->dev, "eqn %d, eqe type %s\n", eq->eqn, eqe_type_str(eqe->type)); - if (dev->priv.eq_table.cb != NULL && - dev->priv.eq_table.cb(dev, eqe->type, &eqe->data)) { - /* FALLTHROUGH */ + /* + * The DEVX event notifier can be (un)registered concurrently. + * Fast path: when no notifier is registered (the common case + * with DEVX unused) skip RCU entirely - on FreeBSD LinuxKPI + * rcu_read_lock() pins the thread and starts an epoch section, + * which is not free per EQE. If a notifier appears registered, + * re-load the callback under rcu_read_lock() before calling it. + * The acquire load pairs with the store-release in + * mlx5_ib_devx_init_event_table() so eq_table.dev is visible + * once cb is; the re-check under RCU pairs with synchronize_rcu() + * in mlx5_ib_devx_cleanup_event_table() so the callback only + * ever runs inside an RCU section and none is in flight when the + * notifier (and its event table) is torn down. + */ + devx_cb = smp_load_acquire(&dev->priv.eq_table.cb); + if (devx_cb != NULL) { + rcu_read_lock(); + devx_cb = smp_load_acquire(&dev->priv.eq_table.cb); + if (devx_cb != NULL) + devx_consumed = + devx_cb(dev, eqe->type, &eqe->data); + rcu_read_unlock(); + } + + if (devx_consumed) { + /* event consumed by the DEVX notifier */ } else switch (eqe->type) { case MLX5_EVENT_TYPE_COMP: mlx5_cq_completion(dev, eqe); diff --git a/sys/dev/mlx5/mlx5_ib/mlx5_ib_devx.c b/sys/dev/mlx5/mlx5_ib/mlx5_ib_devx.c index 835a7fd8cfa4..6522a0aa6daf 100644 --- a/sys/dev/mlx5/mlx5_ib/mlx5_ib_devx.c +++ b/sys/dev/mlx5/mlx5_ib/mlx5_ib_devx.c @@ -2357,12 +2357,21 @@ static bool mlx5_devx_event_notifier(struct mlx5_core_dev *mdev, bool is_unaffiliated; u32 obj_id; - /* Explicit filtering to kernel events which may occur frequently */ + /* + * Command completions and page requests must be processed by the + * mlx5_core default EQ handler. Returning true here tells + * mlx5_eq_int() the event was consumed and skips core processing, + * which stalls the firmware command interface and page supply and + * wedges the device. Return false so the core handler runs for + * these frequent kernel events. + */ if (event_type == MLX5_EVENT_TYPE_CMD || event_type == MLX5_EVENT_TYPE_PAGE_REQUEST) - return true; + return false; - dev = mdev->priv.eq_table.dev; + dev = READ_ONCE(mdev->priv.eq_table.dev); + if (dev == NULL) + return false; table = &dev->devx_event_table; is_unaffiliated = is_unaffiliated_event(dev->mdev, event_type); @@ -2401,8 +2410,14 @@ void mlx5_ib_devx_init_event_table(struct mlx5_ib_dev *dev) xa_init_flags(&table->event_xa, 0); mutex_init(&table->event_xa_lock); - dev->mdev->priv.eq_table.dev = dev; - dev->mdev->priv.eq_table.cb = mlx5_devx_event_notifier; + /* + * Publish dev before cb. The EQ interrupt handler loads cb with + * acquire semantics and the notifier then dereferences eq_table.dev, + * so dev must be visible to that handler once cb is observed. + */ + WRITE_ONCE(dev->mdev->priv.eq_table.dev, dev); + smp_store_release(&dev->mdev->priv.eq_table.cb, + mlx5_devx_event_notifier); } void mlx5_ib_devx_cleanup_event_table(struct mlx5_ib_dev *dev) @@ -2413,8 +2428,14 @@ void mlx5_ib_devx_cleanup_event_table(struct mlx5_ib_dev *dev) void *entry; unsigned long id; - dev->mdev->priv.eq_table.cb = NULL; - dev->mdev->priv.eq_table.dev = NULL; + /* + * Stop new dispatch by clearing cb, then wait for any in-flight EQ + * callback to finish its RCU read section before clearing dev and + * tearing down the event table. + */ + WRITE_ONCE(dev->mdev->priv.eq_table.cb, NULL); + synchronize_rcu(); + WRITE_ONCE(dev->mdev->priv.eq_table.dev, NULL); mutex_lock(&dev->devx_event_table.event_xa_lock); xa_for_each(&table->event_xa, id, entry) { event = entry;home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a5e8ac8.1de17.3ff79b40>
