xref: /linux/drivers/net/mctp/mctp-usblib.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
1b8564b19SJeremy Kerr // SPDX-License-Identifier: GPL-2.0
2b8564b19SJeremy Kerr /*
3b8564b19SJeremy Kerr  * mctp-usblib.c - MCTP-over-USB (DMTF DSP0283) transport helper library
4b8564b19SJeremy Kerr  *
5b8564b19SJeremy Kerr  * DSP0283 is available at:
6d52fc7f0SJeremy Kerr  * https://www.dmtf.org/sites/default/files/standards/documents/DSP0283_1.1.0.pdf
7b8564b19SJeremy Kerr  *
8b8564b19SJeremy Kerr  * Copyright (C) 2024-2026 Code Construct Pty Ltd
9b8564b19SJeremy Kerr  */
10b8564b19SJeremy Kerr 
11b8564b19SJeremy Kerr #include <linux/module.h>
12b8564b19SJeremy Kerr #include <linux/netdevice.h>
13b8564b19SJeremy Kerr #include <linux/skbuff.h>
14d52fc7f0SJeremy Kerr #include <linux/usb/ch9.h>
15b8564b19SJeremy Kerr #include <linux/usb/mctp-usb.h>
16b8564b19SJeremy Kerr #include <net/mctp.h>
17b8564b19SJeremy Kerr 
mctp_usblib_rx_init(struct mctp_usblib_rx * rx,u16 ep_pktlen,bool span)18d52fc7f0SJeremy Kerr int mctp_usblib_rx_init(struct mctp_usblib_rx *rx, u16 ep_pktlen, bool span)
19b8564b19SJeremy Kerr {
20d52fc7f0SJeremy Kerr 	if (!ep_pktlen)
21d52fc7f0SJeremy Kerr 		return -EINVAL;
22d52fc7f0SJeremy Kerr 
23d52fc7f0SJeremy Kerr 	if (ep_pktlen & ~USB_ENDPOINT_MAXP_MASK)
24d52fc7f0SJeremy Kerr 		return -EINVAL;
25d52fc7f0SJeremy Kerr 
26b8564b19SJeremy Kerr 	memset(rx, 0, sizeof(*rx));
27d52fc7f0SJeremy Kerr 	rx->span = span;
28d52fc7f0SJeremy Kerr 	rx->ep_pktlen = ep_pktlen;
29d52fc7f0SJeremy Kerr 
30d52fc7f0SJeremy Kerr 	return 0;
31b8564b19SJeremy Kerr }
32b8564b19SJeremy Kerr EXPORT_SYMBOL_GPL(mctp_usblib_rx_init);
33b8564b19SJeremy Kerr 
mctp_usblib_rx_fini(struct mctp_usblib_rx * rx)34b8564b19SJeremy Kerr void mctp_usblib_rx_fini(struct mctp_usblib_rx *rx)
35b8564b19SJeremy Kerr {
36b8564b19SJeremy Kerr 	kfree_skb(rx->skb);
37b8564b19SJeremy Kerr }
38b8564b19SJeremy Kerr EXPORT_SYMBOL_GPL(mctp_usblib_rx_fini);
39b8564b19SJeremy Kerr 
40b8564b19SJeremy Kerr /*
41b8564b19SJeremy Kerr  * Prepare a transfer buffer for future completion; *bufp and *lenp will
42b8564b19SJeremy Kerr  * be populated on success.
43b8564b19SJeremy Kerr  */
mctp_usblib_rx_prepare(struct net_device * netdev,struct mctp_usblib_rx * rx,void ** bufp,size_t * lenp,gfp_t gfp)44b8564b19SJeremy Kerr int mctp_usblib_rx_prepare(struct net_device *netdev,
45b8564b19SJeremy Kerr 			   struct mctp_usblib_rx *rx,
46b8564b19SJeremy Kerr 			   void **bufp, size_t *lenp, gfp_t gfp)
47b8564b19SJeremy Kerr {
48d52fc7f0SJeremy Kerr 	struct sk_buff *skb = rx->skb;
49d52fc7f0SJeremy Kerr 	unsigned int len = 0;
50b8564b19SJeremy Kerr 
51d52fc7f0SJeremy Kerr 	if (skb && skb->len >= MCTP_USB_1_1_PKTLEN_MAX) {
52d52fc7f0SJeremy Kerr 		/* something must have gone terribly wrong. clear and restart */
53d52fc7f0SJeremy Kerr 		mctp_usblib_rx_cancel(rx);
54d52fc7f0SJeremy Kerr 		skb = NULL;
55d52fc7f0SJeremy Kerr 	}
56d52fc7f0SJeremy Kerr 
57d52fc7f0SJeremy Kerr 	len = rx->span ? roundup(MCTP_USB_1_1_PKTLEN_MAX, rx->ep_pktlen)
58d52fc7f0SJeremy Kerr 		: MCTP_USB_1_0_XFER_SIZE;
59d52fc7f0SJeremy Kerr 
60d52fc7f0SJeremy Kerr 	if (!skb) {
61b8564b19SJeremy Kerr 		skb = __netdev_alloc_skb(netdev, len, gfp);
62b8564b19SJeremy Kerr 		if (!skb)
63b8564b19SJeremy Kerr 			return -ENOMEM;
64b8564b19SJeremy Kerr 
65d52fc7f0SJeremy Kerr 	} else if (skb->cloned || skb_tailroom(skb) < rx->ep_pktlen) {
66d52fc7f0SJeremy Kerr 		/* We always need to realloc if ->cloned, as we cannot
67d52fc7f0SJeremy Kerr 		 * resubmit the (now-shared) skb buffer for possible DMA.
68d52fc7f0SJeremy Kerr 		 *
69d52fc7f0SJeremy Kerr 		 * Otherwise (if we have an un-cloned SKB): just ensure we
70d52fc7f0SJeremy Kerr 		 * have sufficient space to prevent babble. Since we allocated
71d52fc7f0SJeremy Kerr 		 * for max size in the last prepare (and have not consumed any
72d52fc7f0SJeremy Kerr 		 * of that space for a prior MCTP packet, because !cloned), we
73d52fc7f0SJeremy Kerr 		 * have sufficient data to finish the current MCTP packet.
74d52fc7f0SJeremy Kerr 		 */
75d52fc7f0SJeremy Kerr 		struct sk_buff *skb2;
76d52fc7f0SJeremy Kerr 
77d52fc7f0SJeremy Kerr 		skb2 = skb_copy_expand(skb, 0, len, gfp);
78d52fc7f0SJeremy Kerr 		if (!skb2)
79d52fc7f0SJeremy Kerr 			return -ENOMEM;
80d52fc7f0SJeremy Kerr 		dev_kfree_skb_any(skb);
81d52fc7f0SJeremy Kerr 		skb = skb2;
82d52fc7f0SJeremy Kerr 	}
83d52fc7f0SJeremy Kerr 
84b8564b19SJeremy Kerr 	rx->skb = skb;
85b8564b19SJeremy Kerr 
86d52fc7f0SJeremy Kerr 	/* Spanning mode allows ZLPs, so we don't require exactly one
87d52fc7f0SJeremy Kerr 	 * transfer packet. If we have extra tailroom, may as well use it,
88d52fc7f0SJeremy Kerr 	 * and we have ensured that the tailroom >= ep_pktlen.
89d52fc7f0SJeremy Kerr 	 */
90d52fc7f0SJeremy Kerr 	if (rx->span)
91d52fc7f0SJeremy Kerr 		len = rounddown(skb_tailroom(skb), rx->ep_pktlen);
92d52fc7f0SJeremy Kerr 
93b8564b19SJeremy Kerr 	*bufp = skb_tail_pointer(skb);
94b8564b19SJeremy Kerr 	*lenp = len;
95b8564b19SJeremy Kerr 
96b8564b19SJeremy Kerr 	return 0;
97b8564b19SJeremy Kerr }
98b8564b19SJeremy Kerr EXPORT_SYMBOL_GPL(mctp_usblib_rx_prepare);
99b8564b19SJeremy Kerr 
mctp_usblib_rx(struct net_device * netdev,struct sk_buff * skb)100b8564b19SJeremy Kerr static void mctp_usblib_rx(struct net_device *netdev, struct sk_buff *skb)
101b8564b19SJeremy Kerr {
102b8564b19SJeremy Kerr 	struct pcpu_dstats *dstats = this_cpu_ptr(netdev->dstats);
103b8564b19SJeremy Kerr 	struct mctp_skb_cb *cb;
104b8564b19SJeremy Kerr 	unsigned long flags;
105b8564b19SJeremy Kerr 
106d52fc7f0SJeremy Kerr 	skb_reset_mac_header(skb);
107d52fc7f0SJeremy Kerr 	skb_pull(skb, sizeof(struct mctp_usb_hdr));
108d52fc7f0SJeremy Kerr 
109b8564b19SJeremy Kerr 	/* we're called from an URB completion handler, and cannot assume local
110b8564b19SJeremy Kerr 	 * irqs are always disabled
111b8564b19SJeremy Kerr 	 */
112b8564b19SJeremy Kerr 	flags = u64_stats_update_begin_irqsave(&dstats->syncp);
113b8564b19SJeremy Kerr 	u64_stats_inc(&dstats->rx_packets);
114b8564b19SJeremy Kerr 	u64_stats_add(&dstats->rx_bytes, skb->len);
115b8564b19SJeremy Kerr 	u64_stats_update_end_irqrestore(&dstats->syncp, flags);
116b8564b19SJeremy Kerr 
117b8564b19SJeremy Kerr 	skb->protocol = htons(ETH_P_MCTP);
118b8564b19SJeremy Kerr 	skb_reset_network_header(skb);
119b8564b19SJeremy Kerr 	cb = __mctp_cb(skb);
120b8564b19SJeremy Kerr 	cb->halen = 0;
121b8564b19SJeremy Kerr 	netif_rx(skb);
122b8564b19SJeremy Kerr }
123b8564b19SJeremy Kerr 
mctp_usblib_rx_stats_single_drop(struct net_device * dev)124b8564b19SJeremy Kerr static void mctp_usblib_rx_stats_single_drop(struct net_device *dev)
125b8564b19SJeremy Kerr {
126b8564b19SJeremy Kerr 	struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats);
127b8564b19SJeremy Kerr 	unsigned long flags;
128b8564b19SJeremy Kerr 
129b8564b19SJeremy Kerr 	flags = u64_stats_update_begin_irqsave(&dstats->syncp);
130b8564b19SJeremy Kerr 	u64_stats_inc(&dstats->rx_drops);
131b8564b19SJeremy Kerr 	u64_stats_update_end_irqrestore(&dstats->syncp, flags);
132b8564b19SJeremy Kerr }
133b8564b19SJeremy Kerr 
134b8564b19SJeremy Kerr /*
135b8564b19SJeremy Kerr  * Receive a USB completion of @len bytes of incoming data. We will then split
136b8564b19SJeremy Kerr  * this into packets and netif_rx() each. Intended to be called in atomic
137b8564b19SJeremy Kerr  * contexts - ie., URB completion.
138b8564b19SJeremy Kerr  *
139b8564b19SJeremy Kerr  * Assumes @netdev uses dstats.
140b8564b19SJeremy Kerr  */
mctp_usblib_rx_complete(struct net_device * netdev,struct mctp_usblib_rx * rx,size_t len)141b8564b19SJeremy Kerr int mctp_usblib_rx_complete(struct net_device *netdev,
142b8564b19SJeremy Kerr 			    struct mctp_usblib_rx *rx, size_t len)
143b8564b19SJeremy Kerr {
144b8564b19SJeremy Kerr 	struct sk_buff *skb = rx->skb;
145b8564b19SJeremy Kerr 	int rc = 0;
146b8564b19SJeremy Kerr 
147b8564b19SJeremy Kerr 	__skb_put(skb, len);
148b8564b19SJeremy Kerr 
149d52fc7f0SJeremy Kerr 	for (;;) {
150b8564b19SJeremy Kerr 		struct mctp_usb_hdr *hdr;
151d52fc7f0SJeremy Kerr 		struct sk_buff *skb2;
152d52fc7f0SJeremy Kerr 		/* length of MCTP packet, including USB header */
153d52fc7f0SJeremy Kerr 		u16 pkt_len;
154b8564b19SJeremy Kerr 
155d52fc7f0SJeremy Kerr 		/* no header yet, resubmit for the rest of the packet */
156d52fc7f0SJeremy Kerr 		if (skb->len < sizeof(*hdr)) {
157d52fc7f0SJeremy Kerr 			if (!rx->span) {
158d52fc7f0SJeremy Kerr 				netdev_dbg(netdev,
159d52fc7f0SJeremy Kerr 					   "rx: tiny xfer (%d) in non-span mode",
160d52fc7f0SJeremy Kerr 					   skb->len);
161b8564b19SJeremy Kerr 				rc = -ENOMSG;
162d52fc7f0SJeremy Kerr 				goto err_reset;
163d52fc7f0SJeremy Kerr 			}
164b8564b19SJeremy Kerr 			break;
165b8564b19SJeremy Kerr 		}
166b8564b19SJeremy Kerr 
167d52fc7f0SJeremy Kerr 		hdr = (struct mctp_usb_hdr *)skb->data;
168d52fc7f0SJeremy Kerr 
169b8564b19SJeremy Kerr 		if (be16_to_cpu(hdr->id) != MCTP_USB_DMTF_ID) {
170d52fc7f0SJeremy Kerr 			/* By resetting here, will start the next IN transfer
171d52fc7f0SJeremy Kerr 			 * at the beginning of the new skb. This will mean
172d52fc7f0SJeremy Kerr 			 * we re-sync when we next see a spanned packet aligned
173d52fc7f0SJeremy Kerr 			 * with the start of a transfer.
174d52fc7f0SJeremy Kerr 			 *
175d52fc7f0SJeremy Kerr 			 * In non-spanning mode, this just means we'll drop
176d52fc7f0SJeremy Kerr 			 * the current transfer only
177d52fc7f0SJeremy Kerr 			 */
178b8564b19SJeremy Kerr 			netdev_dbg(netdev, "rx: invalid id %04x\n",
179b8564b19SJeremy Kerr 				   be16_to_cpu(hdr->id));
180b8564b19SJeremy Kerr 			rc = -EPROTO;
181d52fc7f0SJeremy Kerr 			goto err_reset;
182b8564b19SJeremy Kerr 		}
183b8564b19SJeremy Kerr 
184d52fc7f0SJeremy Kerr 		pkt_len = be16_to_cpu(hdr->len);
185d52fc7f0SJeremy Kerr 		/* v1.1, with span enabled, has a 13-bit length */
186d52fc7f0SJeremy Kerr 		pkt_len &= rx->span ?
187d52fc7f0SJeremy Kerr 			MCTP_USB_1_1_PKTLEN_MAX : MCTP_USB_1_0_PKTLEN_MAX;
188d52fc7f0SJeremy Kerr 		if (pkt_len < sizeof(*hdr) + sizeof(struct mctp_hdr)) {
189d52fc7f0SJeremy Kerr 			netdev_dbg(netdev, "rx: invalid len %d\n", pkt_len);
190b8564b19SJeremy Kerr 			rc = -EPROTO;
191d52fc7f0SJeremy Kerr 			goto err_reset;
192b8564b19SJeremy Kerr 		}
193b8564b19SJeremy Kerr 
194d52fc7f0SJeremy Kerr 		/* span continues to the next transfer, resubmit */
195b8564b19SJeremy Kerr 		if (pkt_len > skb->len) {
196d52fc7f0SJeremy Kerr 			if (!rx->span) {
197b8564b19SJeremy Kerr 				netdev_dbg(netdev,
198d52fc7f0SJeremy Kerr 					   "rx: short xfer (%d vs %d) in non-span mode",
199d52fc7f0SJeremy Kerr 					   pkt_len, skb->len);
200d52fc7f0SJeremy Kerr 				rc = -EPROTO;
201d52fc7f0SJeremy Kerr 				goto err_reset;
202d52fc7f0SJeremy Kerr 			}
203b8564b19SJeremy Kerr 			break;
204b8564b19SJeremy Kerr 		}
205b8564b19SJeremy Kerr 
206d52fc7f0SJeremy Kerr 		/* we have (exactly) a complete packet, RX it directly */
207d52fc7f0SJeremy Kerr 		if (pkt_len == skb->len) {
208d52fc7f0SJeremy Kerr 			mctp_usblib_rx(netdev, skb);
209d52fc7f0SJeremy Kerr 			rx->skb = NULL;
210d52fc7f0SJeremy Kerr 			break;
211d52fc7f0SJeremy Kerr 		}
212d52fc7f0SJeremy Kerr 
213d52fc7f0SJeremy Kerr 		/* more packets follow - RX a clone so that we can continue
214d52fc7f0SJeremy Kerr 		 * processing the current SKB, which may be the start of a
215d52fc7f0SJeremy Kerr 		 * span.
216b8564b19SJeremy Kerr 		 */
217b8564b19SJeremy Kerr 		skb2 = skb_clone(skb, GFP_ATOMIC);
218b8564b19SJeremy Kerr 		if (skb2) {
219d52fc7f0SJeremy Kerr 			skb_trim(skb2, pkt_len);
220d52fc7f0SJeremy Kerr 			mctp_usblib_rx(netdev, skb2);
221b8564b19SJeremy Kerr 		} else {
222b8564b19SJeremy Kerr 			mctp_usblib_rx_stats_single_drop(netdev);
223b8564b19SJeremy Kerr 		}
224d52fc7f0SJeremy Kerr 		skb_pull(skb, pkt_len);
225b8564b19SJeremy Kerr 	}
226b8564b19SJeremy Kerr 
227d52fc7f0SJeremy Kerr 	return 0;
228b8564b19SJeremy Kerr 
229d52fc7f0SJeremy Kerr err_reset:
230d52fc7f0SJeremy Kerr 	dev_kfree_skb_any(rx->skb);
231b8564b19SJeremy Kerr 	rx->skb = NULL;
232b8564b19SJeremy Kerr 	return rc;
233b8564b19SJeremy Kerr }
234b8564b19SJeremy Kerr EXPORT_SYMBOL_GPL(mctp_usblib_rx_complete);
235b8564b19SJeremy Kerr 
236b8564b19SJeremy Kerr /*
237b8564b19SJeremy Kerr  * Cancel a rx context; subsequent prepare/complete calls will not be a
238b8564b19SJeremy Kerr  * continuation of any data already received.
239b8564b19SJeremy Kerr  */
mctp_usblib_rx_cancel(struct mctp_usblib_rx * rx)240b8564b19SJeremy Kerr void mctp_usblib_rx_cancel(struct mctp_usblib_rx *rx)
241b8564b19SJeremy Kerr {
242b8564b19SJeremy Kerr 	dev_kfree_skb_any(rx->skb);
243b8564b19SJeremy Kerr 	rx->skb = NULL;
244b8564b19SJeremy Kerr }
245b8564b19SJeremy Kerr EXPORT_SYMBOL_GPL(mctp_usblib_rx_cancel);
246b8564b19SJeremy Kerr 
247aadf5ed0SJeremy Kerr /* transmit context: encapsulates one transfer */
248aadf5ed0SJeremy Kerr struct mctp_usblib_tx_ctx {
249aadf5ed0SJeremy Kerr 	struct mctp_usblib_tx *tx;
25076a58ffdSJeremy Kerr 	struct sk_buff_head skbs;
251081ac93cSJeremy Kerr 	unsigned int buf_len, len;
252aadf5ed0SJeremy Kerr 	enum mctp_usblib_tx_buf_type {
253aadf5ed0SJeremy Kerr 		TX_SINGLE,
25476a58ffdSJeremy Kerr 		TX_FLAT,
255aadf5ed0SJeremy Kerr 	} buf_type;
25676a58ffdSJeremy Kerr 	u8 buf[] ____cacheline_aligned;
257aadf5ed0SJeremy Kerr };
258aadf5ed0SJeremy Kerr 
mctp_usblib_tx_init(struct mctp_usblib_tx * tx,const struct mctp_usblib_tx_ops * ops,void * priv,bool span)259aadf5ed0SJeremy Kerr void mctp_usblib_tx_init(struct mctp_usblib_tx *tx,
260aadf5ed0SJeremy Kerr 			 const struct mctp_usblib_tx_ops *ops,
261081ac93cSJeremy Kerr 			 void *priv, bool span)
262aadf5ed0SJeremy Kerr {
263aadf5ed0SJeremy Kerr 	memset(tx, 0, sizeof(*tx));
264aadf5ed0SJeremy Kerr 	tx->ops = *ops;
265aadf5ed0SJeremy Kerr 	tx->priv = priv;
266081ac93cSJeremy Kerr 	tx->span = span;
26776a58ffdSJeremy Kerr 	spin_lock_init(&tx->lock);
268aadf5ed0SJeremy Kerr }
269aadf5ed0SJeremy Kerr EXPORT_SYMBOL_GPL(mctp_usblib_tx_init);
270aadf5ed0SJeremy Kerr 
mctp_usblib_tx_avail(struct mctp_usblib_tx_ctx * ctx)27176a58ffdSJeremy Kerr static int mctp_usblib_tx_avail(struct mctp_usblib_tx_ctx *ctx)
272aadf5ed0SJeremy Kerr {
273081ac93cSJeremy Kerr 	return ctx->buf_type == TX_SINGLE ? 0 : ctx->buf_len - ctx->len;
274aadf5ed0SJeremy Kerr }
27576a58ffdSJeremy Kerr 
mctp_usblib_tx_should_send(struct mctp_usblib_tx_ctx * ctx)27676a58ffdSJeremy Kerr static bool mctp_usblib_tx_should_send(struct mctp_usblib_tx_ctx *ctx)
27776a58ffdSJeremy Kerr {
27876a58ffdSJeremy Kerr 	/* Use the baseline length (ie, BTU) as an approximate
27976a58ffdSJeremy Kerr 	 * "reasonably-sized" packet we could expect. If there is
28076a58ffdSJeremy Kerr 	 * insufficient capacity for that, then send.
28176a58ffdSJeremy Kerr 	 */
28276a58ffdSJeremy Kerr 	const size_t pkt_len = MCTP_USB_BTU + sizeof(struct mctp_usb_hdr);
28376a58ffdSJeremy Kerr 
28476a58ffdSJeremy Kerr 	return mctp_usblib_tx_avail(ctx) < pkt_len;
28576a58ffdSJeremy Kerr }
28676a58ffdSJeremy Kerr 
28776a58ffdSJeremy Kerr /*
28876a58ffdSJeremy Kerr  * Returns zero on success, non-zero on failure - indicating that the new skb
28976a58ffdSJeremy Kerr  * could not be appended. So, errors reported here to the TX path will result
29076a58ffdSJeremy Kerr  * in the TX being transmitted.
29176a58ffdSJeremy Kerr  */
mctp_usblib_tx_append(struct mctp_usblib_tx_ctx * ctx,struct sk_buff * skb)29276a58ffdSJeremy Kerr static int mctp_usblib_tx_append(struct mctp_usblib_tx_ctx *ctx,
29376a58ffdSJeremy Kerr 				 struct sk_buff *skb)
29476a58ffdSJeremy Kerr {
29576a58ffdSJeremy Kerr 	if (ctx->buf_type == TX_SINGLE)
29676a58ffdSJeremy Kerr 		return -EINVAL;
29776a58ffdSJeremy Kerr 
29876a58ffdSJeremy Kerr 	if (mctp_usblib_tx_avail(ctx) < skb->len)
29976a58ffdSJeremy Kerr 		return -ENOBUFS;
30076a58ffdSJeremy Kerr 
30176a58ffdSJeremy Kerr 	__skb_queue_tail(&ctx->skbs, skb);
30276a58ffdSJeremy Kerr 
30376a58ffdSJeremy Kerr 	ctx->len += skb->len;
30476a58ffdSJeremy Kerr 
30576a58ffdSJeremy Kerr 	return 0;
30676a58ffdSJeremy Kerr }
30776a58ffdSJeremy Kerr 
mctp_usblib_tx_send(struct mctp_usblib_tx_ctx * ctx)30876a58ffdSJeremy Kerr static int mctp_usblib_tx_send(struct mctp_usblib_tx_ctx *ctx)
30976a58ffdSJeremy Kerr {
31076a58ffdSJeremy Kerr 	void *buf;
31176a58ffdSJeremy Kerr 
31276a58ffdSJeremy Kerr 	/* If we have a qlen of 1, we only ended up packing a single skb,
31376a58ffdSJeremy Kerr 	 * despite allocating for multiple. Skip the copy and send directly
31476a58ffdSJeremy Kerr 	 * from the skb data.
31576a58ffdSJeremy Kerr 	 */
31676a58ffdSJeremy Kerr 	if (ctx->buf_type == TX_SINGLE || ctx->skbs.qlen == 1) {
31776a58ffdSJeremy Kerr 		buf = ctx->skbs.next->data;
31876a58ffdSJeremy Kerr 
31976a58ffdSJeremy Kerr 	} else if (ctx->buf_type == TX_FLAT) {
32076a58ffdSJeremy Kerr 		struct sk_buff *skb;
32176a58ffdSJeremy Kerr 		size_t pos = 0;
32276a58ffdSJeremy Kerr 
32376a58ffdSJeremy Kerr 		skb_queue_walk(&ctx->skbs, skb) {
32476a58ffdSJeremy Kerr 			skb_copy_bits(skb, 0, ctx->buf + pos, skb->len);
32576a58ffdSJeremy Kerr 			pos += skb->len;
32676a58ffdSJeremy Kerr 		}
32776a58ffdSJeremy Kerr 
32876a58ffdSJeremy Kerr 		buf = ctx->buf;
32976a58ffdSJeremy Kerr 	} else {
33076a58ffdSJeremy Kerr 		return -EINVAL;
33176a58ffdSJeremy Kerr 	}
33276a58ffdSJeremy Kerr 
33376a58ffdSJeremy Kerr 	return ctx->tx->ops.send(ctx, buf, ctx->len);
33476a58ffdSJeremy Kerr }
33576a58ffdSJeremy Kerr 
mctp_usblib_tx_ctx_free(struct mctp_usblib_tx_ctx * ctx,enum skb_drop_reason reason)33676a58ffdSJeremy Kerr static void mctp_usblib_tx_ctx_free(struct mctp_usblib_tx_ctx *ctx,
33776a58ffdSJeremy Kerr 				    enum skb_drop_reason reason)
33876a58ffdSJeremy Kerr {
33976a58ffdSJeremy Kerr 	struct sk_buff *skb;
34076a58ffdSJeremy Kerr 
34176a58ffdSJeremy Kerr 	if (!ctx)
34276a58ffdSJeremy Kerr 		return;
34376a58ffdSJeremy Kerr 
34476a58ffdSJeremy Kerr 	while ((skb = __skb_dequeue(&ctx->skbs)) != NULL)
34576a58ffdSJeremy Kerr 		dev_kfree_skb_any_reason(skb, reason);
34676a58ffdSJeremy Kerr 	kfree(ctx);
34776a58ffdSJeremy Kerr }
348aadf5ed0SJeremy Kerr 
mctp_usblib_tx_ctx_priv(struct mctp_usblib_tx_ctx * tx_ctx)349aadf5ed0SJeremy Kerr void *mctp_usblib_tx_ctx_priv(struct mctp_usblib_tx_ctx *tx_ctx)
350aadf5ed0SJeremy Kerr {
351aadf5ed0SJeremy Kerr 	return tx_ctx->tx->priv;
352aadf5ed0SJeremy Kerr }
353aadf5ed0SJeremy Kerr EXPORT_SYMBOL_GPL(mctp_usblib_tx_ctx_priv);
354aadf5ed0SJeremy Kerr 
35576a58ffdSJeremy Kerr /* caller must ensure the tx & completion path is quiesced */
mctp_usblib_tx_fini(struct mctp_usblib_tx * tx)35676a58ffdSJeremy Kerr void mctp_usblib_tx_fini(struct mctp_usblib_tx *tx)
357aadf5ed0SJeremy Kerr {
35876a58ffdSJeremy Kerr 	mctp_usblib_tx_ctx_free(tx->cur_ctx, SKB_DROP_REASON_NOT_SPECIFIED);
35976a58ffdSJeremy Kerr }
36076a58ffdSJeremy Kerr EXPORT_SYMBOL_GPL(mctp_usblib_tx_fini);
361aadf5ed0SJeremy Kerr 
362081ac93cSJeremy Kerr /* Max size of a spanned TX. Since we allocate a separate span buffer, limit
363081ac93cSJeremy Kerr  * the tx-time allocations to 4k. Larger packets will be sent as single
364081ac93cSJeremy Kerr  * transfers.
365081ac93cSJeremy Kerr  */
366081ac93cSJeremy Kerr static const unsigned int TX_SPAN_MAX = 4096 - sizeof(struct mctp_usblib_tx_ctx);
367081ac93cSJeremy Kerr 
36876a58ffdSJeremy Kerr static struct mctp_usblib_tx_ctx *
mctp_usblib_tx_ctx_create(struct mctp_usblib_tx * tx,struct sk_buff * skb,bool single)36976a58ffdSJeremy Kerr mctp_usblib_tx_ctx_create(struct mctp_usblib_tx *tx, struct sk_buff *skb,
37076a58ffdSJeremy Kerr 			  bool single)
37176a58ffdSJeremy Kerr {
37276a58ffdSJeremy Kerr 	enum mctp_usblib_tx_buf_type type;
37376a58ffdSJeremy Kerr 	struct mctp_usblib_tx_ctx *ctx;
37476a58ffdSJeremy Kerr 	size_t sz = 0;
37576a58ffdSJeremy Kerr 
376081ac93cSJeremy Kerr 	if (single || skb->len > TX_SPAN_MAX) {
37776a58ffdSJeremy Kerr 		type = TX_SINGLE;
37876a58ffdSJeremy Kerr 	} else {
37976a58ffdSJeremy Kerr 		type = TX_FLAT;
380081ac93cSJeremy Kerr 		sz = tx->span ? TX_SPAN_MAX : MCTP_USB_1_0_XFER_SIZE;
38176a58ffdSJeremy Kerr 	}
38276a58ffdSJeremy Kerr 
38376a58ffdSJeremy Kerr 	ctx = kzalloc_flex(*ctx, buf, sz, GFP_ATOMIC);
384aadf5ed0SJeremy Kerr 	if (!ctx)
385aadf5ed0SJeremy Kerr 		return NULL;
386aadf5ed0SJeremy Kerr 
387aadf5ed0SJeremy Kerr 	ctx->tx = tx;
38876a58ffdSJeremy Kerr 	ctx->buf_type = type;
389081ac93cSJeremy Kerr 	ctx->buf_len = sz;
39076a58ffdSJeremy Kerr 	ctx->len = skb->len;
39176a58ffdSJeremy Kerr 	skb_queue_head_init(&ctx->skbs);
39276a58ffdSJeremy Kerr 	__skb_queue_tail(&ctx->skbs, skb);
393aadf5ed0SJeremy Kerr 
394aadf5ed0SJeremy Kerr 	return ctx;
395aadf5ed0SJeremy Kerr }
396aadf5ed0SJeremy Kerr 
mctp_usblib_tx_stats_update(struct mctp_usblib_tx_ctx * ctx,struct net_device * dev,bool ok)397aadf5ed0SJeremy Kerr static void mctp_usblib_tx_stats_update(struct mctp_usblib_tx_ctx *ctx,
398aadf5ed0SJeremy Kerr 					struct net_device *dev,
399aadf5ed0SJeremy Kerr 					bool ok)
400aadf5ed0SJeremy Kerr {
401aadf5ed0SJeremy Kerr 	struct pcpu_dstats *dstats = get_cpu_ptr(dev->dstats);
402aadf5ed0SJeremy Kerr 	unsigned long flags;
403aadf5ed0SJeremy Kerr 
404aadf5ed0SJeremy Kerr 	flags = u64_stats_update_begin_irqsave(&dstats->syncp);
405aadf5ed0SJeremy Kerr 	if (ok) {
406aadf5ed0SJeremy Kerr 		/* Only include the network-layer data in tx stats; we know
407aadf5ed0SJeremy Kerr 		 * that there is a 4-byte header pushed to all skbs in
408aadf5ed0SJeremy Kerr 		 * tx_skb_prepare()
409aadf5ed0SJeremy Kerr 		 */
41076a58ffdSJeremy Kerr 		u64 n = ctx->skbs.qlen;
41176a58ffdSJeremy Kerr 		s64 len = ctx->len - (n * sizeof(struct mctp_usb_hdr));
412aadf5ed0SJeremy Kerr 
41376a58ffdSJeremy Kerr 		u64_stats_add(&dstats->tx_packets, n);
414aadf5ed0SJeremy Kerr 		u64_stats_add(&dstats->tx_bytes, len);
415aadf5ed0SJeremy Kerr 	} else {
41676a58ffdSJeremy Kerr 		u64_stats_add(&dstats->tx_drops, ctx->skbs.qlen);
417aadf5ed0SJeremy Kerr 	}
418aadf5ed0SJeremy Kerr 	u64_stats_update_end_irqrestore(&dstats->syncp, flags);
419aadf5ed0SJeremy Kerr 	put_cpu_ptr(dev->dstats);
420aadf5ed0SJeremy Kerr }
421aadf5ed0SJeremy Kerr 
mctp_usblib_tx_stats_single_drop(struct net_device * dev)422aadf5ed0SJeremy Kerr static void mctp_usblib_tx_stats_single_drop(struct net_device *dev)
423aadf5ed0SJeremy Kerr {
424aadf5ed0SJeremy Kerr 	struct pcpu_dstats *dstats = get_cpu_ptr(dev->dstats);
425aadf5ed0SJeremy Kerr 	unsigned long flags;
426aadf5ed0SJeremy Kerr 
427aadf5ed0SJeremy Kerr 	flags = u64_stats_update_begin_irqsave(&dstats->syncp);
428aadf5ed0SJeremy Kerr 	u64_stats_inc(&dstats->tx_drops);
429aadf5ed0SJeremy Kerr 	u64_stats_update_end_irqrestore(&dstats->syncp, flags);
430aadf5ed0SJeremy Kerr 	put_cpu_ptr(dev->dstats);
431aadf5ed0SJeremy Kerr }
432aadf5ed0SJeremy Kerr 
433aadf5ed0SJeremy Kerr /*
434aadf5ed0SJeremy Kerr  * Completion for the ->send() op. This will update netdev stats and
435aadf5ed0SJeremy Kerr  * free the tx context.
436aadf5ed0SJeremy Kerr  *
437aadf5ed0SJeremy Kerr  * Likely called from (atomic) URB completion context.
438aadf5ed0SJeremy Kerr  */
mctp_usblib_tx_send_complete(struct mctp_usblib_tx_ctx * tx_ctx,struct net_device * dev,bool ok)439aadf5ed0SJeremy Kerr void mctp_usblib_tx_send_complete(struct mctp_usblib_tx_ctx *tx_ctx,
440aadf5ed0SJeremy Kerr 				  struct net_device *dev, bool ok)
441aadf5ed0SJeremy Kerr {
442aadf5ed0SJeremy Kerr 	enum skb_drop_reason reason =
443aadf5ed0SJeremy Kerr 		ok ? SKB_CONSUMED : SKB_DROP_REASON_NOT_SPECIFIED;
444aadf5ed0SJeremy Kerr 
445aadf5ed0SJeremy Kerr 	mctp_usblib_tx_stats_update(tx_ctx, dev, ok);
446aadf5ed0SJeremy Kerr 	mctp_usblib_tx_ctx_free(tx_ctx, reason);
447aadf5ed0SJeremy Kerr }
448aadf5ed0SJeremy Kerr EXPORT_SYMBOL_GPL(mctp_usblib_tx_send_complete);
449aadf5ed0SJeremy Kerr 
450aadf5ed0SJeremy Kerr /* Prepare a skb for push()
451aadf5ed0SJeremy Kerr  *
452aadf5ed0SJeremy Kerr  * On error, populates @reason.
453aadf5ed0SJeremy Kerr  */
mctp_usblib_tx_skb_prepare(struct sk_buff * skb,bool span,enum skb_drop_reason * reason)454081ac93cSJeremy Kerr static int mctp_usblib_tx_skb_prepare(struct sk_buff *skb, bool span,
455aadf5ed0SJeremy Kerr 				      enum skb_drop_reason *reason)
456aadf5ed0SJeremy Kerr {
457081ac93cSJeremy Kerr 	unsigned long plen, max_len;
458aadf5ed0SJeremy Kerr 	struct mctp_usb_hdr *hdr;
459aadf5ed0SJeremy Kerr 	int rc;
460aadf5ed0SJeremy Kerr 
461081ac93cSJeremy Kerr 	max_len = span ? MCTP_USB_1_1_PKTLEN_MAX : MCTP_USB_1_0_PKTLEN_MAX;
462081ac93cSJeremy Kerr 
463aadf5ed0SJeremy Kerr 	plen = skb->len;
464081ac93cSJeremy Kerr 	if (plen + sizeof(*hdr) > max_len) {
465aadf5ed0SJeremy Kerr 		*reason = SKB_DROP_REASON_PKT_TOO_BIG;
466aadf5ed0SJeremy Kerr 		return -EMSGSIZE;
467aadf5ed0SJeremy Kerr 	}
468aadf5ed0SJeremy Kerr 
469aadf5ed0SJeremy Kerr 	rc = skb_cow_head(skb, sizeof(*hdr));
470aadf5ed0SJeremy Kerr 	if (rc) {
471aadf5ed0SJeremy Kerr 		*reason = SKB_DROP_REASON_NOMEM;
472aadf5ed0SJeremy Kerr 		return rc;
473aadf5ed0SJeremy Kerr 	}
474aadf5ed0SJeremy Kerr 
475aadf5ed0SJeremy Kerr 	hdr = skb_push(skb, sizeof(*hdr));
476aadf5ed0SJeremy Kerr 	if (!hdr) {
477aadf5ed0SJeremy Kerr 		*reason = SKB_DROP_REASON_NOMEM;
478aadf5ed0SJeremy Kerr 		return -ENOMEM;
479aadf5ed0SJeremy Kerr 	}
480aadf5ed0SJeremy Kerr 
481aadf5ed0SJeremy Kerr 	hdr->id = cpu_to_be16(MCTP_USB_DMTF_ID);
482f5bf226fSJeremy Kerr 	hdr->len = cpu_to_be16(plen + sizeof(*hdr));
483aadf5ed0SJeremy Kerr 
484aadf5ed0SJeremy Kerr 	return 0;
485aadf5ed0SJeremy Kerr }
486aadf5ed0SJeremy Kerr 
487aadf5ed0SJeremy Kerr /*
48876a58ffdSJeremy Kerr  * Push a new skb to the transfer. May result in zero or more calls to
48976a58ffdSJeremy Kerr  * ops->send().
490aadf5ed0SJeremy Kerr  *
491aadf5ed0SJeremy Kerr  * Takes ownership of @skb, including on error.
492aadf5ed0SJeremy Kerr  */
mctp_usblib_tx_push(struct net_device * dev,struct mctp_usblib_tx * tx,struct sk_buff * skb,bool more)493aadf5ed0SJeremy Kerr int mctp_usblib_tx_push(struct net_device *dev,
494aadf5ed0SJeremy Kerr 			struct mctp_usblib_tx *tx,
495aadf5ed0SJeremy Kerr 			struct sk_buff *skb, bool more)
496aadf5ed0SJeremy Kerr {
49776a58ffdSJeremy Kerr 	struct mctp_usblib_tx_ctx *ctx, *send_ctx = NULL;
498aadf5ed0SJeremy Kerr 	enum skb_drop_reason reason;
49976a58ffdSJeremy Kerr 	const int max_tries = 3;
50076a58ffdSJeremy Kerr 	unsigned long flags;
50176a58ffdSJeremy Kerr 	int try = 1, rc;
502aadf5ed0SJeremy Kerr 
503081ac93cSJeremy Kerr 	rc = mctp_usblib_tx_skb_prepare(skb, tx->span, &reason);
50476a58ffdSJeremy Kerr 	if (rc) {
50576a58ffdSJeremy Kerr 		mctp_usblib_tx_stats_single_drop(dev);
50676a58ffdSJeremy Kerr 		kfree_skb_reason(skb, reason);
50776a58ffdSJeremy Kerr 		/* we may still need to proceed, in case an existing ctx
50876a58ffdSJeremy Kerr 		 * is now sendable (ie.: !more).
50976a58ffdSJeremy Kerr 		 */
51076a58ffdSJeremy Kerr 		skb = NULL;
51176a58ffdSJeremy Kerr 	}
51276a58ffdSJeremy Kerr 
51376a58ffdSJeremy Kerr 	reason = SKB_DROP_REASON_NOT_SPECIFIED;
51476a58ffdSJeremy Kerr retry:
51576a58ffdSJeremy Kerr 	/* Try and queue to the current context. We exit this critical section
51676a58ffdSJeremy Kerr 	 * with a few bits of state:
51776a58ffdSJeremy Kerr 	 *  - send_ctx: indicating a prior context that needs to be sent
51876a58ffdSJeremy Kerr 	 *  - skb: indicating that a skb still needs to be queued/sent
51976a58ffdSJeremy Kerr 	 */
52076a58ffdSJeremy Kerr 	spin_lock_irqsave(&tx->lock, flags);
52176a58ffdSJeremy Kerr 	ctx = tx->cur_ctx;
52276a58ffdSJeremy Kerr 	if (ctx) {
52376a58ffdSJeremy Kerr 		if (skb) {
52476a58ffdSJeremy Kerr 			rc = mctp_usblib_tx_append(ctx, skb);
52576a58ffdSJeremy Kerr 			if (rc) {
52676a58ffdSJeremy Kerr 				/* can't append to the pending tx - detach for
52776a58ffdSJeremy Kerr 				 * sending, and we'll create a new tx below.
52876a58ffdSJeremy Kerr 				 */
52976a58ffdSJeremy Kerr 				swap(tx->cur_ctx, send_ctx);
53076a58ffdSJeremy Kerr 			} else {
53176a58ffdSJeremy Kerr 				/* we have queued */
53276a58ffdSJeremy Kerr 				skb = NULL;
53376a58ffdSJeremy Kerr 				if (!more || mctp_usblib_tx_should_send(ctx))
53476a58ffdSJeremy Kerr 					swap(tx->cur_ctx, send_ctx);
53576a58ffdSJeremy Kerr 			}
53676a58ffdSJeremy Kerr 		} else if (!more) {
53776a58ffdSJeremy Kerr 			swap(tx->cur_ctx, send_ctx);
53876a58ffdSJeremy Kerr 		}
53976a58ffdSJeremy Kerr 	}
54076a58ffdSJeremy Kerr 	spin_unlock_irqrestore(&tx->lock, flags);
54176a58ffdSJeremy Kerr 
54276a58ffdSJeremy Kerr 	if (send_ctx) {
54376a58ffdSJeremy Kerr 		rc = mctp_usblib_tx_send(send_ctx);
54476a58ffdSJeremy Kerr 		if (rc) {
54576a58ffdSJeremy Kerr 			mctp_usblib_tx_stats_update(send_ctx, dev, false);
54676a58ffdSJeremy Kerr 			mctp_usblib_tx_ctx_free(send_ctx, reason);
54776a58ffdSJeremy Kerr 		}
54876a58ffdSJeremy Kerr 		send_ctx = NULL;
54976a58ffdSJeremy Kerr 	}
55076a58ffdSJeremy Kerr 
55176a58ffdSJeremy Kerr 	/* we have either queued, or the prepare failed; nothing more to do */
552aadf5ed0SJeremy Kerr 	if (!skb)
553aadf5ed0SJeremy Kerr 		return 0;
554aadf5ed0SJeremy Kerr 
55576a58ffdSJeremy Kerr 	ctx = mctp_usblib_tx_ctx_create(tx, skb, !more);
556aadf5ed0SJeremy Kerr 	if (!ctx) {
55776a58ffdSJeremy Kerr 		netdev_dbg(dev, "TX context create failed\n");
55876a58ffdSJeremy Kerr 		mctp_usblib_tx_stats_single_drop(dev);
55976a58ffdSJeremy Kerr 		kfree_skb(skb);
56076a58ffdSJeremy Kerr 		return -ENOMEM;
561aadf5ed0SJeremy Kerr 	}
562aadf5ed0SJeremy Kerr 
56376a58ffdSJeremy Kerr 	/* if we're ready to send now, no need to enqueue */
56476a58ffdSJeremy Kerr 	if (!more || mctp_usblib_tx_should_send(ctx)) {
565aadf5ed0SJeremy Kerr 		rc = mctp_usblib_tx_send(ctx);
566aadf5ed0SJeremy Kerr 		if (rc) {
567aadf5ed0SJeremy Kerr 			mctp_usblib_tx_stats_update(ctx, dev, false);
56876a58ffdSJeremy Kerr 			mctp_usblib_tx_ctx_free(ctx, reason);
56976a58ffdSJeremy Kerr 		}
57076a58ffdSJeremy Kerr 		return 0;
571aadf5ed0SJeremy Kerr 	}
572aadf5ed0SJeremy Kerr 
57376a58ffdSJeremy Kerr 	spin_lock_irqsave(&tx->lock, flags);
57476a58ffdSJeremy Kerr 	if (!tx->cur_ctx) {
57576a58ffdSJeremy Kerr 		tx->cur_ctx = ctx;
57676a58ffdSJeremy Kerr 		ctx = NULL;
57776a58ffdSJeremy Kerr 	}
57876a58ffdSJeremy Kerr 	spin_unlock_irqrestore(&tx->lock, flags);
579aadf5ed0SJeremy Kerr 
58076a58ffdSJeremy Kerr 	/* we may have lost the race with a concurrent tx; shouldn't happen, as
58176a58ffdSJeremy Kerr 	 * ndo_start_xmit should be serialised over one queue, but try again
58276a58ffdSJeremy Kerr 	 * from the top, as we may be able to queue the skb to that context.
58376a58ffdSJeremy Kerr 	 */
58476a58ffdSJeremy Kerr 	if (ctx) {
58576a58ffdSJeremy Kerr 		/* unlink the new (sole) skb, we don't want it freed with ctx */
58676a58ffdSJeremy Kerr 		__skb_queue_head_init(&ctx->skbs);
58776a58ffdSJeremy Kerr 		mctp_usblib_tx_ctx_free(ctx, reason);
58876a58ffdSJeremy Kerr 		if (++try > max_tries) {
58976a58ffdSJeremy Kerr 			kfree_skb(skb);
590aadf5ed0SJeremy Kerr 			mctp_usblib_tx_stats_single_drop(dev);
59176a58ffdSJeremy Kerr 			return -EBUSY;
59276a58ffdSJeremy Kerr 		}
59376a58ffdSJeremy Kerr 		goto retry;
59476a58ffdSJeremy Kerr 	}
59576a58ffdSJeremy Kerr 
59676a58ffdSJeremy Kerr 	return 0;
597aadf5ed0SJeremy Kerr }
598aadf5ed0SJeremy Kerr EXPORT_SYMBOL_GPL(mctp_usblib_tx_push);
599aadf5ed0SJeremy Kerr 
600aadf5ed0SJeremy Kerr /* Cancel a tx: any un-sent context is released. */
mctp_usblib_tx_cancel(struct mctp_usblib_tx * tx,struct net_device * dev,enum skb_drop_reason reason)601aadf5ed0SJeremy Kerr void mctp_usblib_tx_cancel(struct mctp_usblib_tx *tx, struct net_device *dev,
602aadf5ed0SJeremy Kerr 			   enum skb_drop_reason reason)
603aadf5ed0SJeremy Kerr {
60476a58ffdSJeremy Kerr 	struct mctp_usblib_tx_ctx *ctx = NULL;
60576a58ffdSJeremy Kerr 	unsigned long flags;
60676a58ffdSJeremy Kerr 
60776a58ffdSJeremy Kerr 	spin_lock_irqsave(&tx->lock, flags);
60876a58ffdSJeremy Kerr 	swap(tx->cur_ctx, ctx);
60976a58ffdSJeremy Kerr 	spin_unlock_irqrestore(&tx->lock, flags);
61076a58ffdSJeremy Kerr 
61176a58ffdSJeremy Kerr 	if (!ctx)
61276a58ffdSJeremy Kerr 		return;
61376a58ffdSJeremy Kerr 
61476a58ffdSJeremy Kerr 	mctp_usblib_tx_stats_update(ctx, dev, false);
61576a58ffdSJeremy Kerr 	mctp_usblib_tx_ctx_free(ctx, reason);
616aadf5ed0SJeremy Kerr }
617aadf5ed0SJeremy Kerr EXPORT_SYMBOL_GPL(mctp_usblib_tx_cancel);
618aadf5ed0SJeremy Kerr 
619b8564b19SJeremy Kerr MODULE_LICENSE("GPL");
620b8564b19SJeremy Kerr MODULE_AUTHOR("Jeremy Kerr <jk@codeconstruct.com.au>");
621b8564b19SJeremy Kerr MODULE_DESCRIPTION("MCTP USB transport library");
622*e84c0edbSJeremy Kerr 
623*e84c0edbSJeremy Kerr #if IS_ENABLED(CONFIG_MCTP_TRANSPORT_USBLIB_TEST)
624*e84c0edbSJeremy Kerr #include "mctp-usblib-test.c"
625*e84c0edbSJeremy Kerr #endif
626