Skip site navigation (1)Skip section navigation (2)
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>