From: Koichiro Den <den@valinux.co.jp>
To: Jon Mason <jdmason@kudzu.us>, Dave Jiang <dave.jiang@intel.com>,
Allen Hubbe <allenbh@gmail.com>,
Andrew Lunn <andrew+netdev@lunn.ch>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>
Cc: ntb@lists.linux.dev, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH net-next v4 04/10] NTB: ntb_transport: Keep local QP link requests separate
Date: Mon, 14 Sep 2026 17:48:32 +0900 [thread overview]
Message-ID: <20260914084838.2158249-5-den@valinux.co.jp> (raw)
In-Reply-To: <20260914084838.2158249-1-den@valinux.co.jp>
The QP_LINKS handshake is a smart way for both sides to converge on
link-up without peer SPAD reads (MRd). But copying the peer's bitmap
back mixes up local requests and peer readiness when multiple QPs are
used.
When QPs are shut down back-to-back, each update reads the local
scratchpad and can restore a bit just cleared in the peer scratchpad.
Likewise, a peer's QP1 worker can echo our QP0 request before its own
QP0 worker runs, making us report QP0 up too early.
Keep our up requests in a bitmap in ntb_transport_ctx. Serialize bitmap
updates and peer writes under one lock. Clear it on transport cleanup
so each QP advertises itself again after reconnecting.
This bitmap handling dates back to commit fce8a7bb5b4b ("PCI-Express
Non-Transparent Bridge Support"), but ntb_netdev multi-queue support
exposed the problem in practice, hence the Fixes tag below.
Fixes: 24d9e73c7e00 ("net: ntb_netdev: Support ethtool channels for multi-queue")
Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
Changes in v4:
- New patch for a pre-existing issue found while preparing v4.
drivers/ntb/ntb_transport.c | 30 ++++++++++++++++++++++++------
1 file changed, 24 insertions(+), 6 deletions(-)
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index b69e8ac8047d..0b47285ef48b 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -244,6 +244,9 @@ struct ntb_transport_ctx {
unsigned int qp_count;
u64 qp_bitmap;
u64 qp_bitmap_free;
+ /* Serialize request updates and peer writes. */
+ spinlock_t up_request_lock;
+ u32 up_request;
bool use_msi;
unsigned int msi_spad_offset;
@@ -976,6 +979,9 @@ static void ntb_transport_link_cleanup(struct ntb_transport_ctx *nt)
if (!nt->link_is_up)
cancel_delayed_work_sync(&nt->link_work);
+ scoped_guard(spinlock, &nt->up_request_lock)
+ nt->up_request = 0;
+
for (i = 0; i < nt->mw_count; i++)
ntb_free_mw(nt, i);
@@ -1113,6 +1119,21 @@ static void ntb_transport_link_work(struct work_struct *work)
msecs_to_jiffies(NTB_LINK_DOWN_TIMEOUT));
}
+static void ntb_qp_up_request(struct ntb_transport_qp *qp, bool up)
+{
+ struct ntb_transport_ctx *nt = qp->transport;
+
+ guard(spinlock)(&nt->up_request_lock);
+
+ if (up)
+ nt->up_request |= BIT(qp->qp_num);
+ else
+ nt->up_request &= ~BIT(qp->qp_num);
+
+ /* Update the peer's view of our requests. */
+ ntb_peer_spad_write(nt->ndev, PIDX, QP_LINKS, nt->up_request);
+}
+
static void ntb_qp_link_work(struct work_struct *work)
{
struct ntb_transport_qp *qp = container_of(work,
@@ -1126,7 +1147,7 @@ static void ntb_qp_link_work(struct work_struct *work)
val = ntb_spad_read(nt->ndev, QP_LINKS);
- ntb_peer_spad_write(nt->ndev, PIDX, QP_LINKS, val | BIT(qp->qp_num));
+ ntb_qp_up_request(qp, true);
/* query remote spad for qp ready bits */
dev_dbg_ratelimited(&pdev->dev, "Remote QP link status = %x\n", val);
@@ -1361,6 +1382,7 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
goto err2;
}
+ spin_lock_init(&nt->up_request_lock);
mutex_init(&nt->link_event_lock);
INIT_DELAYED_WORK(&nt->link_work, ntb_transport_link_work);
INIT_WORK(&nt->link_cleanup, ntb_transport_link_cleanup_work);
@@ -2412,16 +2434,12 @@ EXPORT_SYMBOL_GPL(ntb_transport_link_up);
*/
void ntb_transport_link_down(struct ntb_transport_qp *qp)
{
- int val;
-
if (!qp)
return;
qp->client_ready = false;
- val = ntb_spad_read(qp->ndev, QP_LINKS);
-
- ntb_peer_spad_write(qp->ndev, PIDX, QP_LINKS, val & ~BIT(qp->qp_num));
+ ntb_qp_up_request(qp, false);
if (qp->link_is_up)
ntb_send_link_down(qp);
--
2.51.0
next prev parent reply other threads:[~2026-09-14 8:48 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-14 8:48 [PATCH net-next v4 00/10] net: ntb_netdev: Preserve checksum offload across NTB Koichiro Den
2026-09-14 8:48 ` [PATCH net-next v4 01/10] NTB: ntb_transport: Order RX descriptor reads after completion Koichiro Den
2026-09-19 0:36 ` Joe Damato
2026-09-19 12:37 ` Koichiro Den
2026-09-14 8:48 ` [PATCH net-next v4 02/10] NTB: ntb_transport: Use little-endian shared fields Koichiro Den
2026-09-19 0:54 ` Joe Damato
2026-09-19 13:06 ` Koichiro Den
2026-09-14 8:48 ` [PATCH net-next v4 03/10] NTB: ntb_transport: Order RX entry completion Koichiro Den
2026-09-19 1:10 ` Joe Damato
2026-09-19 12:53 ` Koichiro Den
2026-09-14 8:48 ` Koichiro Den [this message]
2026-09-17 20:49 ` [PATCH net-next v4 04/10] NTB: ntb_transport: Keep local QP link requests separate netdev-bot+sashiko
2026-09-14 8:48 ` [PATCH net-next v4 05/10] NTB: ntb_transport: Exchange client capabilities at link-up Koichiro Den
2026-09-17 20:49 ` netdev-bot+sashiko
2026-09-14 8:48 ` [PATCH net-next v4 06/10] NTB: ntb_transport: Add per-payload client metadata Koichiro Den
2026-09-14 8:48 ` [PATCH net-next v4 07/10] net: ntb_netdev: Reject short RX frames Koichiro Den
2026-09-19 1:14 ` Joe Damato
2026-09-14 8:48 ` [PATCH net-next v4 08/10] net: ntb_netdev: Factor out RX statistics update Koichiro Den
2026-09-14 8:48 ` [PATCH net-next v4 09/10] net: ntb_netdev: Introduce an optional packet header, ntb_netdev_hdr Koichiro Den
2026-09-17 20:49 ` netdev-bot+sashiko
2026-09-14 8:48 ` [PATCH net-next v4 10/10] net: ntb_netdev: Preserve CHECKSUM_PARTIAL across NTB Koichiro Den
2026-09-17 20:49 ` netdev-bot+sashiko
2026-10-09 5:10 ` [PATCH net-next v4 00/10] net: ntb_netdev: Preserve checksum offload " Koichiro Den
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260914084838.2158249-5-den@valinux.co.jp \
--to=den@valinux.co.jp \
--cc=allenbh@gmail.com \
--cc=andrew+netdev@lunn.ch \
--cc=dave.jiang@intel.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=jdmason@kudzu.us \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=ntb@lists.linux.dev \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox