[PATCH net-next v3 09/12] net: mctp: usblib: Implement transmit-side packet spanning
From: Jeremy Kerr <jk@codeconstruct.com.au>
Date: 2026-07-08 09:59:50
Also in:
linux-usb
Subsystem:
management component transport protocol (mctp), networking drivers, the rest, usb subsystem · Maintainers:
Jeremy Kerr, Matt Johnston, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds, Greg Kroah-Hartman
Add support for packet spanning as defined in DSP0283 v1.1. With the existing v1.0 implementation of multi-packet transfers, all we need here is to adjust the buffer sizes to suit v1.1. Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au> --- drivers/net/mctp/mctp-usb.c | 2 +- drivers/net/mctp/mctp-usblib.c | 28 +++++++++++++++++++--------- include/linux/usb/mctp-usb.h | 4 +++- 3 files changed, 23 insertions(+), 11 deletions(-)
diff --git a/drivers/net/mctp/mctp-usb.c b/drivers/net/mctp/mctp-usb.c
index 644e7f88ce8b..0507307c875f 100644
--- a/drivers/net/mctp/mctp-usb.c
+++ b/drivers/net/mctp/mctp-usb.c@@ -321,7 +321,7 @@ static int mctp_usb_probe(struct usb_interface *intf, usb_set_intfdata(intf, dev); mctp_usblib_rx_init(&dev->rx, le16_to_cpu(ep_in->wMaxPacketSize), false); - mctp_usblib_tx_init(&dev->tx, &tx_ops, dev); + mctp_usblib_tx_init(&dev->tx, &tx_ops, dev, false); init_usb_anchor(&dev->tx_anchor); dev->ep_in = ep_in->bEndpointAddress;
diff --git a/drivers/net/mctp/mctp-usblib.c b/drivers/net/mctp/mctp-usblib.c
index dad876c4da68..4131be31db1a 100644
--- a/drivers/net/mctp/mctp-usblib.c
+++ b/drivers/net/mctp/mctp-usblib.c@@ -239,7 +239,7 @@ EXPORT_SYMBOL_GPL(mctp_usblib_rx_cancel); struct mctp_usblib_tx_ctx { struct mctp_usblib_tx *tx; struct sk_buff_head skbs; - unsigned int len; + unsigned int buf_len, len; enum mctp_usblib_tx_buf_type { TX_SINGLE, TX_FLAT,
@@ -249,18 +249,19 @@ struct mctp_usblib_tx_ctx { void mctp_usblib_tx_init(struct mctp_usblib_tx *tx, const struct mctp_usblib_tx_ops *ops, - void *priv) + void *priv, bool span) { memset(tx, 0, sizeof(*tx)); tx->ops = *ops; tx->priv = priv; + tx->span = span; spin_lock_init(&tx->lock); } EXPORT_SYMBOL_GPL(mctp_usblib_tx_init); static int mctp_usblib_tx_avail(struct mctp_usblib_tx_ctx *ctx) { - return ctx->buf_type == TX_SINGLE ? 0 : MCTP_USB_1_0_XFER_SIZE - ctx->len; + return ctx->buf_type == TX_SINGLE ? 0 : ctx->buf_len - ctx->len; } static bool mctp_usblib_tx_should_send(struct mctp_usblib_tx_ctx *ctx)
@@ -349,6 +350,12 @@ void mctp_usblib_tx_fini(struct mctp_usblib_tx *tx) } EXPORT_SYMBOL_GPL(mctp_usblib_tx_fini); +/* Max size of a spanned TX. Since we allocate a separate span buffer, limit + * the tx-time allocations to 4k. Larger packets will be sent as single + * transfers. + */ +static const unsigned int TX_SPAN_MAX = 4096 - sizeof(struct mctp_usblib_tx_ctx); + static struct mctp_usblib_tx_ctx * mctp_usblib_tx_ctx_create(struct mctp_usblib_tx *tx, struct sk_buff *skb, bool single)
@@ -357,11 +364,11 @@ mctp_usblib_tx_ctx_create(struct mctp_usblib_tx *tx, struct sk_buff *skb, struct mctp_usblib_tx_ctx *ctx; size_t sz = 0; - if (single) { + if (single || skb->len > TX_SPAN_MAX) { type = TX_SINGLE; } else { type = TX_FLAT; - sz = MCTP_USB_1_0_XFER_SIZE; + sz = tx->span ? TX_SPAN_MAX : MCTP_USB_1_0_XFER_SIZE; } ctx = kzalloc_flex(*ctx, buf, sz, GFP_ATOMIC);
@@ -370,6 +377,7 @@ mctp_usblib_tx_ctx_create(struct mctp_usblib_tx *tx, struct sk_buff *skb, ctx->tx = tx; ctx->buf_type = type; + ctx->buf_len = sz; ctx->len = skb->len; skb_queue_head_init(&ctx->skbs); __skb_queue_tail(&ctx->skbs, skb);
@@ -434,15 +442,17 @@ EXPORT_SYMBOL_GPL(mctp_usblib_tx_send_complete); * * On error, populates @reason. */ -static int mctp_usblib_tx_skb_prepare(struct sk_buff *skb, +static int mctp_usblib_tx_skb_prepare(struct sk_buff *skb, bool span, enum skb_drop_reason *reason) { + unsigned long plen, max_len; struct mctp_usb_hdr *hdr; - unsigned long plen; int rc; + max_len = span ? MCTP_USB_1_1_PKTLEN_MAX : MCTP_USB_1_0_PKTLEN_MAX; + plen = skb->len; - if (plen + sizeof(*hdr) > MCTP_USB_1_0_PKTLEN_MAX) { + if (plen + sizeof(*hdr) > max_len) { *reason = SKB_DROP_REASON_PKT_TOO_BIG; return -EMSGSIZE; }
@@ -481,7 +491,7 @@ int mctp_usblib_tx_push(struct net_device *dev, unsigned long flags; int try = 1, rc; - rc = mctp_usblib_tx_skb_prepare(skb, &reason); + rc = mctp_usblib_tx_skb_prepare(skb, tx->span, &reason); if (rc) { mctp_usblib_tx_stats_single_drop(dev); kfree_skb_reason(skb, reason);
diff --git a/include/linux/usb/mctp-usb.h b/include/linux/usb/mctp-usb.h
index c8fe22d7f68e..35cc2cc15f9a 100644
--- a/include/linux/usb/mctp-usb.h
+++ b/include/linux/usb/mctp-usb.h@@ -81,6 +81,7 @@ struct mctp_usblib_tx_ops { struct mctp_usblib_tx { struct mctp_usblib_tx_ops ops; void *priv; + bool span; /* protects access to cur_ctx */ spinlock_t lock; /* context to which we are adding packets, cleared on send */
@@ -88,7 +89,8 @@ struct mctp_usblib_tx { }; void mctp_usblib_tx_init(struct mctp_usblib_tx *tx, - const struct mctp_usblib_tx_ops *ops, void *priv); + const struct mctp_usblib_tx_ops *ops, void *priv, + bool span); void mctp_usblib_tx_fini(struct mctp_usblib_tx *tx); void *mctp_usblib_tx_ctx_priv(struct mctp_usblib_tx_ctx *tx_ctx);
--
2.47.3