xref: /openbmc/linux/drivers/net/usb/cdc_ncm.c (revision eb47c274)
1900d495aSAlexey Orishko /*
2900d495aSAlexey Orishko  * cdc_ncm.c
3900d495aSAlexey Orishko  *
4c84ff1d6SAlexey Orishko  * Copyright (C) ST-Ericsson 2010-2012
5900d495aSAlexey Orishko  * Contact: Alexey Orishko <alexey.orishko@stericsson.com>
6900d495aSAlexey Orishko  * Original author: Hans Petter Selasky <hans.petter.selasky@stericsson.com>
7900d495aSAlexey Orishko  *
8900d495aSAlexey Orishko  * USB Host Driver for Network Control Model (NCM)
922401ff1SEnrico Mioso  * http://www.usb.org/developers/docs/devclass_docs/NCM10_012011.zip
10900d495aSAlexey Orishko  *
11900d495aSAlexey Orishko  * The NCM encoding, decoding and initialization logic
12900d495aSAlexey Orishko  * derives from FreeBSD 8.x. if_cdce.c and if_cdcereg.h
13900d495aSAlexey Orishko  *
14900d495aSAlexey Orishko  * This software is available to you under a choice of one of two
15900d495aSAlexey Orishko  * licenses. You may choose this file to be licensed under the terms
16900d495aSAlexey Orishko  * of the GNU General Public License (GPL) Version 2 or the 2-clause
17900d495aSAlexey Orishko  * BSD license listed below:
18900d495aSAlexey Orishko  *
19900d495aSAlexey Orishko  * Redistribution and use in source and binary forms, with or without
20900d495aSAlexey Orishko  * modification, are permitted provided that the following conditions
21900d495aSAlexey Orishko  * are met:
22900d495aSAlexey Orishko  * 1. Redistributions of source code must retain the above copyright
23900d495aSAlexey Orishko  *    notice, this list of conditions and the following disclaimer.
24900d495aSAlexey Orishko  * 2. Redistributions in binary form must reproduce the above copyright
25900d495aSAlexey Orishko  *    notice, this list of conditions and the following disclaimer in the
26900d495aSAlexey Orishko  *    documentation and/or other materials provided with the distribution.
27900d495aSAlexey Orishko  *
28900d495aSAlexey Orishko  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
29900d495aSAlexey Orishko  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30900d495aSAlexey Orishko  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31900d495aSAlexey Orishko  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
32900d495aSAlexey Orishko  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33900d495aSAlexey Orishko  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34900d495aSAlexey Orishko  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35900d495aSAlexey Orishko  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36900d495aSAlexey Orishko  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37900d495aSAlexey Orishko  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38900d495aSAlexey Orishko  * SUCH DAMAGE.
39900d495aSAlexey Orishko  */
40900d495aSAlexey Orishko 
41900d495aSAlexey Orishko #include <linux/module.h>
42900d495aSAlexey Orishko #include <linux/netdevice.h>
43900d495aSAlexey Orishko #include <linux/ctype.h>
441dfddff5SBjørn Mork #include <linux/etherdevice.h>
45900d495aSAlexey Orishko #include <linux/ethtool.h>
46900d495aSAlexey Orishko #include <linux/workqueue.h>
47900d495aSAlexey Orishko #include <linux/mii.h>
48900d495aSAlexey Orishko #include <linux/crc32.h>
49900d495aSAlexey Orishko #include <linux/usb.h>
50c84ff1d6SAlexey Orishko #include <linux/hrtimer.h>
51900d495aSAlexey Orishko #include <linux/atomic.h>
52900d495aSAlexey Orishko #include <linux/usb/usbnet.h>
53900d495aSAlexey Orishko #include <linux/usb/cdc.h>
54c91ce3b6SBjørn Mork #include <linux/usb/cdc_ncm.h>
55900d495aSAlexey Orishko 
561e8bbe6cSBjørn Mork #if IS_ENABLED(CONFIG_USB_NET_CDC_MBIM)
571e8bbe6cSBjørn Mork static bool prefer_mbim = true;
581e8bbe6cSBjørn Mork #else
591e8bbe6cSBjørn Mork static bool prefer_mbim;
601e8bbe6cSBjørn Mork #endif
61d61e4038SJoe Perches module_param(prefer_mbim, bool, 0644);
621e8bbe6cSBjørn Mork MODULE_PARM_DESC(prefer_mbim, "Prefer MBIM setting on dual NCM/MBIM functions");
631e8bbe6cSBjørn Mork 
644f4e5436SEmil Renner Berthing static void cdc_ncm_txpath_bh(struct tasklet_struct *t);
65c84ff1d6SAlexey Orishko static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx);
66c84ff1d6SAlexey Orishko static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *hr_timer);
67900d495aSAlexey Orishko static struct usb_driver cdc_ncm_driver;
68900d495aSAlexey Orishko 
69beeecd42SBjørn Mork struct cdc_ncm_stats {
70beeecd42SBjørn Mork 	char stat_string[ETH_GSTRING_LEN];
71beeecd42SBjørn Mork 	int sizeof_stat;
72beeecd42SBjørn Mork 	int stat_offset;
73beeecd42SBjørn Mork };
74beeecd42SBjørn Mork 
75beeecd42SBjørn Mork #define CDC_NCM_STAT(str, m) { \
76beeecd42SBjørn Mork 		.stat_string = str, \
77beeecd42SBjørn Mork 		.sizeof_stat = sizeof(((struct cdc_ncm_ctx *)0)->m), \
78beeecd42SBjørn Mork 		.stat_offset = offsetof(struct cdc_ncm_ctx, m) }
79beeecd42SBjørn Mork #define CDC_NCM_SIMPLE_STAT(m)	CDC_NCM_STAT(__stringify(m), m)
80beeecd42SBjørn Mork 
81beeecd42SBjørn Mork static const struct cdc_ncm_stats cdc_ncm_gstrings_stats[] = {
82beeecd42SBjørn Mork 	CDC_NCM_SIMPLE_STAT(tx_reason_ntb_full),
83beeecd42SBjørn Mork 	CDC_NCM_SIMPLE_STAT(tx_reason_ndp_full),
84beeecd42SBjørn Mork 	CDC_NCM_SIMPLE_STAT(tx_reason_timeout),
85beeecd42SBjørn Mork 	CDC_NCM_SIMPLE_STAT(tx_reason_max_datagram),
86beeecd42SBjørn Mork 	CDC_NCM_SIMPLE_STAT(tx_overhead),
87beeecd42SBjørn Mork 	CDC_NCM_SIMPLE_STAT(tx_ntbs),
88beeecd42SBjørn Mork 	CDC_NCM_SIMPLE_STAT(rx_overhead),
89beeecd42SBjørn Mork 	CDC_NCM_SIMPLE_STAT(rx_ntbs),
90beeecd42SBjørn Mork };
91beeecd42SBjørn Mork 
92e1069bbfSJim Baxter #define CDC_NCM_LOW_MEM_MAX_CNT 10
93e1069bbfSJim Baxter 
94beeecd42SBjørn Mork static int cdc_ncm_get_sset_count(struct net_device __always_unused *netdev, int sset)
95beeecd42SBjørn Mork {
96beeecd42SBjørn Mork 	switch (sset) {
97beeecd42SBjørn Mork 	case ETH_SS_STATS:
98beeecd42SBjørn Mork 		return ARRAY_SIZE(cdc_ncm_gstrings_stats);
99beeecd42SBjørn Mork 	default:
100beeecd42SBjørn Mork 		return -EOPNOTSUPP;
101beeecd42SBjørn Mork 	}
102beeecd42SBjørn Mork }
103beeecd42SBjørn Mork 
104beeecd42SBjørn Mork static void cdc_ncm_get_ethtool_stats(struct net_device *netdev,
105beeecd42SBjørn Mork 				    struct ethtool_stats __always_unused *stats,
106beeecd42SBjørn Mork 				    u64 *data)
107beeecd42SBjørn Mork {
108beeecd42SBjørn Mork 	struct usbnet *dev = netdev_priv(netdev);
109beeecd42SBjørn Mork 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
110beeecd42SBjørn Mork 	int i;
111beeecd42SBjørn Mork 	char *p = NULL;
112beeecd42SBjørn Mork 
113beeecd42SBjørn Mork 	for (i = 0; i < ARRAY_SIZE(cdc_ncm_gstrings_stats); i++) {
114beeecd42SBjørn Mork 		p = (char *)ctx + cdc_ncm_gstrings_stats[i].stat_offset;
115beeecd42SBjørn Mork 		data[i] = (cdc_ncm_gstrings_stats[i].sizeof_stat == sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
116beeecd42SBjørn Mork 	}
117beeecd42SBjørn Mork }
118beeecd42SBjørn Mork 
119beeecd42SBjørn Mork static void cdc_ncm_get_strings(struct net_device __always_unused *netdev, u32 stringset, u8 *data)
120beeecd42SBjørn Mork {
121beeecd42SBjørn Mork 	u8 *p = data;
122beeecd42SBjørn Mork 	int i;
123beeecd42SBjørn Mork 
124beeecd42SBjørn Mork 	switch (stringset) {
125beeecd42SBjørn Mork 	case ETH_SS_STATS:
126beeecd42SBjørn Mork 		for (i = 0; i < ARRAY_SIZE(cdc_ncm_gstrings_stats); i++) {
127beeecd42SBjørn Mork 			memcpy(p, cdc_ncm_gstrings_stats[i].stat_string, ETH_GSTRING_LEN);
128beeecd42SBjørn Mork 			p += ETH_GSTRING_LEN;
129beeecd42SBjørn Mork 		}
130beeecd42SBjørn Mork 	}
131beeecd42SBjørn Mork }
132beeecd42SBjørn Mork 
1336c4e548fSBjørn Mork static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx);
1346c4e548fSBjørn Mork 
1356c4e548fSBjørn Mork static const struct ethtool_ops cdc_ncm_ethtool_ops = {
1366c4e548fSBjørn Mork 	.get_link		= usbnet_get_link,
1376c4e548fSBjørn Mork 	.nway_reset		= usbnet_nway_reset,
1386c4e548fSBjørn Mork 	.get_drvinfo		= usbnet_get_drvinfo,
1396c4e548fSBjørn Mork 	.get_msglevel		= usbnet_get_msglevel,
1406c4e548fSBjørn Mork 	.set_msglevel		= usbnet_set_msglevel,
1416c4e548fSBjørn Mork 	.get_ts_info		= ethtool_op_get_ts_info,
142beeecd42SBjørn Mork 	.get_sset_count		= cdc_ncm_get_sset_count,
143beeecd42SBjørn Mork 	.get_strings		= cdc_ncm_get_strings,
144beeecd42SBjørn Mork 	.get_ethtool_stats	= cdc_ncm_get_ethtool_stats,
145*eb47c274SOliver Neukum 	.get_link_ksettings	= usbnet_get_link_ksettings_internal,
146*eb47c274SOliver Neukum 	.set_link_ksettings	= NULL,
1476c4e548fSBjørn Mork };
1486c4e548fSBjørn Mork 
149289507d3SBjørn Mork static u32 cdc_ncm_check_rx_max(struct usbnet *dev, u32 new_rx)
1505aa73d5dSBjørn Mork {
1515aa73d5dSBjørn Mork 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
1525aa73d5dSBjørn Mork 	u32 val, max, min;
1535aa73d5dSBjørn Mork 
1545aa73d5dSBjørn Mork 	/* clamp new_rx to sane values */
1555aa73d5dSBjørn Mork 	min = USB_CDC_NCM_NTB_MIN_IN_SIZE;
1565aa73d5dSBjørn Mork 	max = min_t(u32, CDC_NCM_NTB_MAX_SIZE_RX, le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize));
1575aa73d5dSBjørn Mork 
1585aa73d5dSBjørn Mork 	/* dwNtbInMaxSize spec violation? Use MIN size for both limits */
1595aa73d5dSBjørn Mork 	if (max < min) {
1605aa73d5dSBjørn Mork 		dev_warn(&dev->intf->dev, "dwNtbInMaxSize=%u is too small. Using %u\n",
1615aa73d5dSBjørn Mork 			 le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize), min);
1625aa73d5dSBjørn Mork 		max = min;
1635aa73d5dSBjørn Mork 	}
1645aa73d5dSBjørn Mork 
1655aa73d5dSBjørn Mork 	val = clamp_t(u32, new_rx, min, max);
166289507d3SBjørn Mork 	if (val != new_rx)
167289507d3SBjørn Mork 		dev_dbg(&dev->intf->dev, "rx_max must be in the [%u, %u] range\n", min, max);
168289507d3SBjørn Mork 
169289507d3SBjørn Mork 	return val;
1705aa73d5dSBjørn Mork }
1715aa73d5dSBjørn Mork 
172289507d3SBjørn Mork static u32 cdc_ncm_check_tx_max(struct usbnet *dev, u32 new_tx)
173289507d3SBjørn Mork {
174289507d3SBjørn Mork 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
175289507d3SBjørn Mork 	u32 val, max, min;
176289507d3SBjørn Mork 
177289507d3SBjørn Mork 	/* clamp new_tx to sane values */
1780fa81b30SAlexander Bersenev 	if (ctx->is_ndp16)
179289507d3SBjørn Mork 		min = ctx->max_datagram_size + ctx->max_ndp_size + sizeof(struct usb_cdc_ncm_nth16);
1800fa81b30SAlexander Bersenev 	else
1810fa81b30SAlexander Bersenev 		min = ctx->max_datagram_size + ctx->max_ndp_size + sizeof(struct usb_cdc_ncm_nth32);
1820fa81b30SAlexander Bersenev 
183289507d3SBjørn Mork 	max = min_t(u32, CDC_NCM_NTB_MAX_SIZE_TX, le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize));
184289507d3SBjørn Mork 
185289507d3SBjørn Mork 	/* some devices set dwNtbOutMaxSize too low for the above default */
186289507d3SBjørn Mork 	min = min(min, max);
187289507d3SBjørn Mork 
188289507d3SBjørn Mork 	val = clamp_t(u32, new_tx, min, max);
189289507d3SBjørn Mork 	if (val != new_tx)
190289507d3SBjørn Mork 		dev_dbg(&dev->intf->dev, "tx_max must be in the [%u, %u] range\n", min, max);
191289507d3SBjørn Mork 
192289507d3SBjørn Mork 	return val;
193289507d3SBjørn Mork }
194289507d3SBjørn Mork 
19539eb7e0eSBjørn Mork static ssize_t cdc_ncm_show_min_tx_pkt(struct device *d, struct device_attribute *attr, char *buf)
19639eb7e0eSBjørn Mork {
19739eb7e0eSBjørn Mork 	struct usbnet *dev = netdev_priv(to_net_dev(d));
19839eb7e0eSBjørn Mork 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
19939eb7e0eSBjørn Mork 
20039eb7e0eSBjørn Mork 	return sprintf(buf, "%u\n", ctx->min_tx_pkt);
20139eb7e0eSBjørn Mork }
20239eb7e0eSBjørn Mork 
203289507d3SBjørn Mork static ssize_t cdc_ncm_show_rx_max(struct device *d, struct device_attribute *attr, char *buf)
204289507d3SBjørn Mork {
205289507d3SBjørn Mork 	struct usbnet *dev = netdev_priv(to_net_dev(d));
206289507d3SBjørn Mork 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
207289507d3SBjørn Mork 
208289507d3SBjørn Mork 	return sprintf(buf, "%u\n", ctx->rx_max);
209289507d3SBjørn Mork }
210289507d3SBjørn Mork 
211289507d3SBjørn Mork static ssize_t cdc_ncm_show_tx_max(struct device *d, struct device_attribute *attr, char *buf)
212289507d3SBjørn Mork {
213289507d3SBjørn Mork 	struct usbnet *dev = netdev_priv(to_net_dev(d));
214289507d3SBjørn Mork 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
215289507d3SBjørn Mork 
216289507d3SBjørn Mork 	return sprintf(buf, "%u\n", ctx->tx_max);
217289507d3SBjørn Mork }
218289507d3SBjørn Mork 
219289507d3SBjørn Mork static ssize_t cdc_ncm_show_tx_timer_usecs(struct device *d, struct device_attribute *attr, char *buf)
220289507d3SBjørn Mork {
221289507d3SBjørn Mork 	struct usbnet *dev = netdev_priv(to_net_dev(d));
222289507d3SBjørn Mork 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
223289507d3SBjørn Mork 
224289507d3SBjørn Mork 	return sprintf(buf, "%u\n", ctx->timer_interval / (u32)NSEC_PER_USEC);
225289507d3SBjørn Mork }
226289507d3SBjørn Mork 
22739eb7e0eSBjørn Mork static ssize_t cdc_ncm_store_min_tx_pkt(struct device *d,  struct device_attribute *attr, const char *buf, size_t len)
22839eb7e0eSBjørn Mork {
22939eb7e0eSBjørn Mork 	struct usbnet *dev = netdev_priv(to_net_dev(d));
23039eb7e0eSBjørn Mork 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
23139eb7e0eSBjørn Mork 	unsigned long val;
23239eb7e0eSBjørn Mork 
23339eb7e0eSBjørn Mork 	/* no need to restrict values - anything from 0 to infinity is OK */
23439eb7e0eSBjørn Mork 	if (kstrtoul(buf, 0, &val))
23539eb7e0eSBjørn Mork 		return -EINVAL;
23639eb7e0eSBjørn Mork 
23739eb7e0eSBjørn Mork 	ctx->min_tx_pkt = val;
23839eb7e0eSBjørn Mork 	return len;
23939eb7e0eSBjørn Mork }
24039eb7e0eSBjørn Mork 
241289507d3SBjørn Mork static ssize_t cdc_ncm_store_rx_max(struct device *d,  struct device_attribute *attr, const char *buf, size_t len)
242289507d3SBjørn Mork {
243289507d3SBjørn Mork 	struct usbnet *dev = netdev_priv(to_net_dev(d));
244289507d3SBjørn Mork 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
245289507d3SBjørn Mork 	unsigned long val;
246289507d3SBjørn Mork 
247289507d3SBjørn Mork 	if (kstrtoul(buf, 0, &val) || cdc_ncm_check_rx_max(dev, val) != val)
248289507d3SBjørn Mork 		return -EINVAL;
249289507d3SBjørn Mork 
250289507d3SBjørn Mork 	cdc_ncm_update_rxtx_max(dev, val, ctx->tx_max);
251289507d3SBjørn Mork 	return len;
252289507d3SBjørn Mork }
253289507d3SBjørn Mork 
254289507d3SBjørn Mork static ssize_t cdc_ncm_store_tx_max(struct device *d,  struct device_attribute *attr, const char *buf, size_t len)
255289507d3SBjørn Mork {
256289507d3SBjørn Mork 	struct usbnet *dev = netdev_priv(to_net_dev(d));
257289507d3SBjørn Mork 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
258289507d3SBjørn Mork 	unsigned long val;
259289507d3SBjørn Mork 
260289507d3SBjørn Mork 	if (kstrtoul(buf, 0, &val) || cdc_ncm_check_tx_max(dev, val) != val)
261289507d3SBjørn Mork 		return -EINVAL;
262289507d3SBjørn Mork 
263289507d3SBjørn Mork 	cdc_ncm_update_rxtx_max(dev, ctx->rx_max, val);
264289507d3SBjørn Mork 	return len;
265289507d3SBjørn Mork }
266289507d3SBjørn Mork 
267289507d3SBjørn Mork static ssize_t cdc_ncm_store_tx_timer_usecs(struct device *d,  struct device_attribute *attr, const char *buf, size_t len)
268289507d3SBjørn Mork {
269289507d3SBjørn Mork 	struct usbnet *dev = netdev_priv(to_net_dev(d));
270289507d3SBjørn Mork 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
271289507d3SBjørn Mork 	ssize_t ret;
272289507d3SBjørn Mork 	unsigned long val;
273289507d3SBjørn Mork 
274289507d3SBjørn Mork 	ret = kstrtoul(buf, 0, &val);
275289507d3SBjørn Mork 	if (ret)
276289507d3SBjørn Mork 		return ret;
277289507d3SBjørn Mork 	if (val && (val < CDC_NCM_TIMER_INTERVAL_MIN || val > CDC_NCM_TIMER_INTERVAL_MAX))
278289507d3SBjørn Mork 		return -EINVAL;
279289507d3SBjørn Mork 
280289507d3SBjørn Mork 	spin_lock_bh(&ctx->mtx);
281289507d3SBjørn Mork 	ctx->timer_interval = val * NSEC_PER_USEC;
282289507d3SBjørn Mork 	if (!ctx->timer_interval)
283289507d3SBjørn Mork 		ctx->tx_timer_pending = 0;
284289507d3SBjørn Mork 	spin_unlock_bh(&ctx->mtx);
285289507d3SBjørn Mork 	return len;
286289507d3SBjørn Mork }
287289507d3SBjørn Mork 
288d61e4038SJoe Perches static DEVICE_ATTR(min_tx_pkt, 0644, cdc_ncm_show_min_tx_pkt, cdc_ncm_store_min_tx_pkt);
289d61e4038SJoe Perches static DEVICE_ATTR(rx_max, 0644, cdc_ncm_show_rx_max, cdc_ncm_store_rx_max);
290d61e4038SJoe Perches static DEVICE_ATTR(tx_max, 0644, cdc_ncm_show_tx_max, cdc_ncm_store_tx_max);
291d61e4038SJoe Perches static DEVICE_ATTR(tx_timer_usecs, 0644, cdc_ncm_show_tx_timer_usecs, cdc_ncm_store_tx_timer_usecs);
292289507d3SBjørn Mork 
293404814afSBjørn Mork static ssize_t ndp_to_end_show(struct device *d, struct device_attribute *attr, char *buf)
294404814afSBjørn Mork {
295404814afSBjørn Mork 	struct usbnet *dev = netdev_priv(to_net_dev(d));
296404814afSBjørn Mork 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
297404814afSBjørn Mork 
298404814afSBjørn Mork 	return sprintf(buf, "%c\n", ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END ? 'Y' : 'N');
299404814afSBjørn Mork }
300404814afSBjørn Mork 
301404814afSBjørn Mork static ssize_t ndp_to_end_store(struct device *d,  struct device_attribute *attr, const char *buf, size_t len)
302404814afSBjørn Mork {
303404814afSBjørn Mork 	struct usbnet *dev = netdev_priv(to_net_dev(d));
304404814afSBjørn Mork 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
305404814afSBjørn Mork 	bool enable;
306404814afSBjørn Mork 
307404814afSBjørn Mork 	if (strtobool(buf, &enable))
308404814afSBjørn Mork 		return -EINVAL;
309404814afSBjørn Mork 
310404814afSBjørn Mork 	/* no change? */
311404814afSBjørn Mork 	if (enable == (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END))
312404814afSBjørn Mork 		return len;
313404814afSBjørn Mork 
3140fa81b30SAlexander Bersenev 	if (enable) {
3150fa81b30SAlexander Bersenev 		if (ctx->is_ndp16 && !ctx->delayed_ndp16) {
316404814afSBjørn Mork 			ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
317404814afSBjørn Mork 			if (!ctx->delayed_ndp16)
318404814afSBjørn Mork 				return -ENOMEM;
319404814afSBjørn Mork 		}
3200fa81b30SAlexander Bersenev 		if (!ctx->is_ndp16 && !ctx->delayed_ndp32) {
3210fa81b30SAlexander Bersenev 			ctx->delayed_ndp32 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
3220fa81b30SAlexander Bersenev 			if (!ctx->delayed_ndp32)
3230fa81b30SAlexander Bersenev 				return -ENOMEM;
3240fa81b30SAlexander Bersenev 		}
3250fa81b30SAlexander Bersenev 	}
326404814afSBjørn Mork 
327404814afSBjørn Mork 	/* flush pending data before changing flag */
328404814afSBjørn Mork 	netif_tx_lock_bh(dev->net);
329404814afSBjørn Mork 	usbnet_start_xmit(NULL, dev->net);
330404814afSBjørn Mork 	spin_lock_bh(&ctx->mtx);
331404814afSBjørn Mork 	if (enable)
332404814afSBjørn Mork 		ctx->drvflags |= CDC_NCM_FLAG_NDP_TO_END;
333404814afSBjørn Mork 	else
334404814afSBjørn Mork 		ctx->drvflags &= ~CDC_NCM_FLAG_NDP_TO_END;
335404814afSBjørn Mork 	spin_unlock_bh(&ctx->mtx);
336404814afSBjørn Mork 	netif_tx_unlock_bh(dev->net);
337404814afSBjørn Mork 
338404814afSBjørn Mork 	return len;
339404814afSBjørn Mork }
340404814afSBjørn Mork static DEVICE_ATTR_RW(ndp_to_end);
341404814afSBjørn Mork 
342871578c9SBjørn Mork #define NCM_PARM_ATTR(name, format, tocpu)				\
343871578c9SBjørn Mork static ssize_t cdc_ncm_show_##name(struct device *d, struct device_attribute *attr, char *buf) \
344871578c9SBjørn Mork { \
345871578c9SBjørn Mork 	struct usbnet *dev = netdev_priv(to_net_dev(d)); \
346871578c9SBjørn Mork 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; \
347871578c9SBjørn Mork 	return sprintf(buf, format "\n", tocpu(ctx->ncm_parm.name));	\
348871578c9SBjørn Mork } \
349d61e4038SJoe Perches static DEVICE_ATTR(name, 0444, cdc_ncm_show_##name, NULL)
350871578c9SBjørn Mork 
351871578c9SBjørn Mork NCM_PARM_ATTR(bmNtbFormatsSupported, "0x%04x", le16_to_cpu);
352871578c9SBjørn Mork NCM_PARM_ATTR(dwNtbInMaxSize, "%u", le32_to_cpu);
353871578c9SBjørn Mork NCM_PARM_ATTR(wNdpInDivisor, "%u", le16_to_cpu);
354871578c9SBjørn Mork NCM_PARM_ATTR(wNdpInPayloadRemainder, "%u", le16_to_cpu);
355871578c9SBjørn Mork NCM_PARM_ATTR(wNdpInAlignment, "%u", le16_to_cpu);
356871578c9SBjørn Mork NCM_PARM_ATTR(dwNtbOutMaxSize, "%u", le32_to_cpu);
357871578c9SBjørn Mork NCM_PARM_ATTR(wNdpOutDivisor, "%u", le16_to_cpu);
358871578c9SBjørn Mork NCM_PARM_ATTR(wNdpOutPayloadRemainder, "%u", le16_to_cpu);
359871578c9SBjørn Mork NCM_PARM_ATTR(wNdpOutAlignment, "%u", le16_to_cpu);
360871578c9SBjørn Mork NCM_PARM_ATTR(wNtbOutMaxDatagrams, "%u", le16_to_cpu);
361871578c9SBjørn Mork 
362289507d3SBjørn Mork static struct attribute *cdc_ncm_sysfs_attrs[] = {
36339eb7e0eSBjørn Mork 	&dev_attr_min_tx_pkt.attr,
364404814afSBjørn Mork 	&dev_attr_ndp_to_end.attr,
365289507d3SBjørn Mork 	&dev_attr_rx_max.attr,
366289507d3SBjørn Mork 	&dev_attr_tx_max.attr,
367289507d3SBjørn Mork 	&dev_attr_tx_timer_usecs.attr,
368871578c9SBjørn Mork 	&dev_attr_bmNtbFormatsSupported.attr,
369871578c9SBjørn Mork 	&dev_attr_dwNtbInMaxSize.attr,
370871578c9SBjørn Mork 	&dev_attr_wNdpInDivisor.attr,
371871578c9SBjørn Mork 	&dev_attr_wNdpInPayloadRemainder.attr,
372871578c9SBjørn Mork 	&dev_attr_wNdpInAlignment.attr,
373871578c9SBjørn Mork 	&dev_attr_dwNtbOutMaxSize.attr,
374871578c9SBjørn Mork 	&dev_attr_wNdpOutDivisor.attr,
375871578c9SBjørn Mork 	&dev_attr_wNdpOutPayloadRemainder.attr,
376871578c9SBjørn Mork 	&dev_attr_wNdpOutAlignment.attr,
377871578c9SBjørn Mork 	&dev_attr_wNtbOutMaxDatagrams.attr,
378289507d3SBjørn Mork 	NULL,
379289507d3SBjørn Mork };
380289507d3SBjørn Mork 
38143f51ef1SArvind Yadav static const struct attribute_group cdc_ncm_sysfs_attr_group = {
382289507d3SBjørn Mork 	.name = "cdc_ncm",
383289507d3SBjørn Mork 	.attrs = cdc_ncm_sysfs_attrs,
384289507d3SBjørn Mork };
385289507d3SBjørn Mork 
386289507d3SBjørn Mork /* handle rx_max and tx_max changes */
387289507d3SBjørn Mork static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx)
388289507d3SBjørn Mork {
389289507d3SBjørn Mork 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
390289507d3SBjørn Mork 	u8 iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber;
391289507d3SBjørn Mork 	u32 val;
392289507d3SBjørn Mork 
393289507d3SBjørn Mork 	val = cdc_ncm_check_rx_max(dev, new_rx);
394289507d3SBjørn Mork 
3955aa73d5dSBjørn Mork 	/* inform device about NTB input size changes */
3965aa73d5dSBjørn Mork 	if (val != ctx->rx_max) {
3975aa73d5dSBjørn Mork 		__le32 dwNtbInMaxSize = cpu_to_le32(val);
3985aa73d5dSBjørn Mork 
3995aa73d5dSBjørn Mork 		dev_info(&dev->intf->dev, "setting rx_max = %u\n", val);
40068864abfSBjørn Mork 
40168864abfSBjørn Mork 		/* tell device to use new size */
4025aa73d5dSBjørn Mork 		if (usbnet_write_cmd(dev, USB_CDC_SET_NTB_INPUT_SIZE,
4035aa73d5dSBjørn Mork 				     USB_TYPE_CLASS | USB_DIR_OUT
4045aa73d5dSBjørn Mork 				     | USB_RECIP_INTERFACE,
4055aa73d5dSBjørn Mork 				     0, iface_no, &dwNtbInMaxSize, 4) < 0)
4065aa73d5dSBjørn Mork 			dev_dbg(&dev->intf->dev, "Setting NTB Input Size failed\n");
4075aa73d5dSBjørn Mork 		else
4085aa73d5dSBjørn Mork 			ctx->rx_max = val;
4095aa73d5dSBjørn Mork 	}
4105aa73d5dSBjørn Mork 
411f42763dbSBjørn Mork 	/* usbnet use these values for sizing rx queues */
412f42763dbSBjørn Mork 	if (dev->rx_urb_size != ctx->rx_max) {
413f42763dbSBjørn Mork 		dev->rx_urb_size = ctx->rx_max;
414f42763dbSBjørn Mork 		if (netif_running(dev->net))
415f42763dbSBjørn Mork 			usbnet_unlink_rx_urbs(dev);
416f42763dbSBjørn Mork 	}
417f42763dbSBjørn Mork 
418289507d3SBjørn Mork 	val = cdc_ncm_check_tx_max(dev, new_tx);
4195aa73d5dSBjørn Mork 	if (val != ctx->tx_max)
4205aa73d5dSBjørn Mork 		dev_info(&dev->intf->dev, "setting tx_max = %u\n", val);
42108c74fc9SBjørn Mork 
42208c74fc9SBjørn Mork 	/* Adding a pad byte here if necessary simplifies the handling
42308c74fc9SBjørn Mork 	 * in cdc_ncm_fill_tx_frame, making tx_max always represent
42408c74fc9SBjørn Mork 	 * the real skb max size.
42508c74fc9SBjørn Mork 	 *
42608c74fc9SBjørn Mork 	 * We cannot use dev->maxpacket here because this is called from
42708c74fc9SBjørn Mork 	 * .bind which is called before usbnet sets up dev->maxpacket
42808c74fc9SBjørn Mork 	 */
42968864abfSBjørn Mork 	if (val != le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize) &&
43068864abfSBjørn Mork 	    val % usb_maxpacket(dev->udev, dev->out, 1) == 0)
43168864abfSBjørn Mork 		val++;
43208c74fc9SBjørn Mork 
43368864abfSBjørn Mork 	/* we might need to flush any pending tx buffers if running */
43468864abfSBjørn Mork 	if (netif_running(dev->net) && val > ctx->tx_max) {
43568864abfSBjørn Mork 		netif_tx_lock_bh(dev->net);
43668864abfSBjørn Mork 		usbnet_start_xmit(NULL, dev->net);
4371ba5d0ffSBjørn Mork 		/* make sure tx_curr_skb is reallocated if it was empty */
4381ba5d0ffSBjørn Mork 		if (ctx->tx_curr_skb) {
4391ba5d0ffSBjørn Mork 			dev_kfree_skb_any(ctx->tx_curr_skb);
4401ba5d0ffSBjørn Mork 			ctx->tx_curr_skb = NULL;
4411ba5d0ffSBjørn Mork 		}
44268864abfSBjørn Mork 		ctx->tx_max = val;
44368864abfSBjørn Mork 		netif_tx_unlock_bh(dev->net);
44468864abfSBjørn Mork 	} else {
44568864abfSBjørn Mork 		ctx->tx_max = val;
44668864abfSBjørn Mork 	}
44768864abfSBjørn Mork 
44808c74fc9SBjørn Mork 	dev->hard_mtu = ctx->tx_max;
44968864abfSBjørn Mork 
45068864abfSBjørn Mork 	/* max qlen depend on hard_mtu and rx_urb_size */
45168864abfSBjørn Mork 	usbnet_update_max_qlen(dev);
45243e4c6dfSBjørn Mork 
45343e4c6dfSBjørn Mork 	/* never pad more than 3 full USB packets per transfer */
45443e4c6dfSBjørn Mork 	ctx->min_tx_pkt = clamp_t(u16, ctx->tx_max - 3 * usb_maxpacket(dev->udev, dev->out, 1),
45543e4c6dfSBjørn Mork 				  CDC_NCM_MIN_TX_PKT, ctx->tx_max);
4565aa73d5dSBjørn Mork }
4575aa73d5dSBjørn Mork 
458f8afb73dSBjørn Mork /* helpers for NCM and MBIM differences */
459f8afb73dSBjørn Mork static u8 cdc_ncm_flags(struct usbnet *dev)
460900d495aSAlexey Orishko {
461bed6f762SBjørn Mork 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
462900d495aSAlexey Orishko 
463f8afb73dSBjørn Mork 	if (cdc_ncm_comm_intf_is_mbim(dev->intf->cur_altsetting) && ctx->mbim_desc)
464f8afb73dSBjørn Mork 		return ctx->mbim_desc->bmNetworkCapabilities;
465f8afb73dSBjørn Mork 	if (ctx->func_desc)
466f8afb73dSBjørn Mork 		return ctx->func_desc->bmNetworkCapabilities;
467f8afb73dSBjørn Mork 	return 0;
468f8afb73dSBjørn Mork }
469f8afb73dSBjørn Mork 
470f8afb73dSBjørn Mork static int cdc_ncm_eth_hlen(struct usbnet *dev)
471f8afb73dSBjørn Mork {
472f8afb73dSBjørn Mork 	if (cdc_ncm_comm_intf_is_mbim(dev->intf->cur_altsetting))
473f8afb73dSBjørn Mork 		return 0;
474f8afb73dSBjørn Mork 	return ETH_HLEN;
475f8afb73dSBjørn Mork }
476f8afb73dSBjørn Mork 
477f8afb73dSBjørn Mork static u32 cdc_ncm_min_dgram_size(struct usbnet *dev)
478f8afb73dSBjørn Mork {
479f8afb73dSBjørn Mork 	if (cdc_ncm_comm_intf_is_mbim(dev->intf->cur_altsetting))
480f8afb73dSBjørn Mork 		return CDC_MBIM_MIN_DATAGRAM_SIZE;
481f8afb73dSBjørn Mork 	return CDC_NCM_MIN_DATAGRAM_SIZE;
482f8afb73dSBjørn Mork }
483f8afb73dSBjørn Mork 
484f8afb73dSBjørn Mork static u32 cdc_ncm_max_dgram_size(struct usbnet *dev)
485f8afb73dSBjørn Mork {
486f8afb73dSBjørn Mork 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
487f8afb73dSBjørn Mork 
488f8afb73dSBjørn Mork 	if (cdc_ncm_comm_intf_is_mbim(dev->intf->cur_altsetting) && ctx->mbim_desc)
489f8afb73dSBjørn Mork 		return le16_to_cpu(ctx->mbim_desc->wMaxSegmentSize);
490f8afb73dSBjørn Mork 	if (ctx->ether_desc)
491f8afb73dSBjørn Mork 		return le16_to_cpu(ctx->ether_desc->wMaxSegmentSize);
492f8afb73dSBjørn Mork 	return CDC_NCM_MAX_DATAGRAM_SIZE;
493f8afb73dSBjørn Mork }
494f8afb73dSBjørn Mork 
495f8afb73dSBjørn Mork /* initial one-time device setup.  MUST be called with the data interface
496f8afb73dSBjørn Mork  * in altsetting 0
497f8afb73dSBjørn Mork  */
498f8afb73dSBjørn Mork static int cdc_ncm_init(struct usbnet *dev)
499f8afb73dSBjørn Mork {
500f8afb73dSBjørn Mork 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
501f8afb73dSBjørn Mork 	u8 iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber;
502f8afb73dSBjørn Mork 	int err;
503900d495aSAlexey Orishko 
50490b8b037SMing Lei 	err = usbnet_read_cmd(dev, USB_CDC_GET_NTB_PARAMETERS,
50536c35416SGiuseppe Scrivano 			      USB_TYPE_CLASS | USB_DIR_IN
50636c35416SGiuseppe Scrivano 			      |USB_RECIP_INTERFACE,
507ff0992e9SBjørn Mork 			      0, iface_no, &ctx->ncm_parm,
508ff0992e9SBjørn Mork 			      sizeof(ctx->ncm_parm));
50936c35416SGiuseppe Scrivano 	if (err < 0) {
51059ede316SBjørn Mork 		dev_err(&dev->intf->dev, "failed GET_NTB_PARAMETERS\n");
51159ede316SBjørn Mork 		return err; /* GET_NTB_PARAMETERS is required */
512900d495aSAlexey Orishko 	}
513900d495aSAlexey Orishko 
514f8afb73dSBjørn Mork 	/* set CRC Mode */
515f8afb73dSBjørn Mork 	if (cdc_ncm_flags(dev) & USB_CDC_NCM_NCAP_CRC_MODE) {
516f8afb73dSBjørn Mork 		dev_dbg(&dev->intf->dev, "Setting CRC mode off\n");
517f8afb73dSBjørn Mork 		err = usbnet_write_cmd(dev, USB_CDC_SET_CRC_MODE,
518f8afb73dSBjørn Mork 				       USB_TYPE_CLASS | USB_DIR_OUT
519f8afb73dSBjørn Mork 				       | USB_RECIP_INTERFACE,
520f8afb73dSBjørn Mork 				       USB_CDC_NCM_CRC_NOT_APPENDED,
521f8afb73dSBjørn Mork 				       iface_no, NULL, 0);
522f8afb73dSBjørn Mork 		if (err < 0)
523f8afb73dSBjørn Mork 			dev_err(&dev->intf->dev, "SET_CRC_MODE failed\n");
524f8afb73dSBjørn Mork 	}
525f8afb73dSBjørn Mork 
5260fa81b30SAlexander Bersenev 	/* use ndp16 by default */
5270fa81b30SAlexander Bersenev 	ctx->is_ndp16 = 1;
5280fa81b30SAlexander Bersenev 
529f8afb73dSBjørn Mork 	/* set NTB format, if both formats are supported.
530f8afb73dSBjørn Mork 	 *
531f8afb73dSBjørn Mork 	 * "The host shall only send this command while the NCM Data
532f8afb73dSBjørn Mork 	 *  Interface is in alternate setting 0."
533f8afb73dSBjørn Mork 	 */
534d22adbfbSDan Carpenter 	if (le16_to_cpu(ctx->ncm_parm.bmNtbFormatsSupported) &
535d22adbfbSDan Carpenter 						USB_CDC_NCM_NTB32_SUPPORTED) {
5360fa81b30SAlexander Bersenev 		if (ctx->drvflags & CDC_NCM_FLAG_PREFER_NTB32) {
5370fa81b30SAlexander Bersenev 			ctx->is_ndp16 = 0;
5380fa81b30SAlexander Bersenev 			dev_dbg(&dev->intf->dev, "Setting NTB format to 32-bit\n");
5390fa81b30SAlexander Bersenev 			err = usbnet_write_cmd(dev, USB_CDC_SET_NTB_FORMAT,
5400fa81b30SAlexander Bersenev 					       USB_TYPE_CLASS | USB_DIR_OUT
5410fa81b30SAlexander Bersenev 					       | USB_RECIP_INTERFACE,
5420fa81b30SAlexander Bersenev 					       USB_CDC_NCM_NTB32_FORMAT,
5430fa81b30SAlexander Bersenev 					       iface_no, NULL, 0);
5440fa81b30SAlexander Bersenev 		} else {
5450fa81b30SAlexander Bersenev 			ctx->is_ndp16 = 1;
546f8afb73dSBjørn Mork 			dev_dbg(&dev->intf->dev, "Setting NTB format to 16-bit\n");
547f8afb73dSBjørn Mork 			err = usbnet_write_cmd(dev, USB_CDC_SET_NTB_FORMAT,
548f8afb73dSBjørn Mork 					       USB_TYPE_CLASS | USB_DIR_OUT
549f8afb73dSBjørn Mork 					       | USB_RECIP_INTERFACE,
550f8afb73dSBjørn Mork 					       USB_CDC_NCM_NTB16_FORMAT,
551f8afb73dSBjørn Mork 					       iface_no, NULL, 0);
5520fa81b30SAlexander Bersenev 		}
5530fa81b30SAlexander Bersenev 		if (err < 0) {
5540fa81b30SAlexander Bersenev 			ctx->is_ndp16 = 1;
555f8afb73dSBjørn Mork 			dev_err(&dev->intf->dev, "SET_NTB_FORMAT failed\n");
556f8afb73dSBjørn Mork 		}
5570fa81b30SAlexander Bersenev 	}
558f8afb73dSBjørn Mork 
559f8afb73dSBjørn Mork 	/* set initial device values */
560ff0992e9SBjørn Mork 	ctx->rx_max = le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize);
561ff0992e9SBjørn Mork 	ctx->tx_max = le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize);
562ff0992e9SBjørn Mork 	ctx->tx_remainder = le16_to_cpu(ctx->ncm_parm.wNdpOutPayloadRemainder);
563ff0992e9SBjørn Mork 	ctx->tx_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutDivisor);
564ff0992e9SBjørn Mork 	ctx->tx_ndp_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutAlignment);
56584e77a8bSAlexey Orishko 	/* devices prior to NCM Errata shall set this field to zero */
566ff0992e9SBjørn Mork 	ctx->tx_max_datagrams = le16_to_cpu(ctx->ncm_parm.wNtbOutMaxDatagrams);
56747175e5fSBjørn Mork 
568ae223cd4SBjørn Mork 	dev_dbg(&dev->intf->dev,
569ae223cd4SBjørn Mork 		"dwNtbInMaxSize=%u dwNtbOutMaxSize=%u wNdpOutPayloadRemainder=%u wNdpOutDivisor=%u wNdpOutAlignment=%u wNtbOutMaxDatagrams=%u flags=0x%x\n",
570900d495aSAlexey Orishko 		ctx->rx_max, ctx->tx_max, ctx->tx_remainder, ctx->tx_modulus,
571f8afb73dSBjørn Mork 		ctx->tx_ndp_modulus, ctx->tx_max_datagrams, cdc_ncm_flags(dev));
572900d495aSAlexey Orishko 
57384e77a8bSAlexey Orishko 	/* max count of tx datagrams */
57484e77a8bSAlexey Orishko 	if ((ctx->tx_max_datagrams == 0) ||
57584e77a8bSAlexey Orishko 			(ctx->tx_max_datagrams > CDC_NCM_DPT_DATAGRAMS_MAX))
576900d495aSAlexey Orishko 		ctx->tx_max_datagrams = CDC_NCM_DPT_DATAGRAMS_MAX;
577900d495aSAlexey Orishko 
57870559b89SBjørn Mork 	/* set up maximum NDP size */
5790fa81b30SAlexander Bersenev 	if (ctx->is_ndp16)
58070559b89SBjørn Mork 		ctx->max_ndp_size = sizeof(struct usb_cdc_ncm_ndp16) + (ctx->tx_max_datagrams + 1) * sizeof(struct usb_cdc_ncm_dpe16);
5810fa81b30SAlexander Bersenev 	else
5820fa81b30SAlexander Bersenev 		ctx->max_ndp_size = sizeof(struct usb_cdc_ncm_ndp32) + (ctx->tx_max_datagrams + 1) * sizeof(struct usb_cdc_ncm_dpe32);
58370559b89SBjørn Mork 
5846c4e548fSBjørn Mork 	/* initial coalescing timer interval */
5856c4e548fSBjørn Mork 	ctx->timer_interval = CDC_NCM_TIMER_INTERVAL_USEC * NSEC_PER_USEC;
5866c4e548fSBjørn Mork 
587f8afb73dSBjørn Mork 	return 0;
588f8afb73dSBjørn Mork }
589f8afb73dSBjørn Mork 
590f8afb73dSBjørn Mork /* set a new max datagram size */
591f8afb73dSBjørn Mork static void cdc_ncm_set_dgram_size(struct usbnet *dev, int new_size)
592f8afb73dSBjørn Mork {
593f8afb73dSBjørn Mork 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
594f8afb73dSBjørn Mork 	u8 iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber;
595f8afb73dSBjørn Mork 	__le16 max_datagram_size;
596f8afb73dSBjørn Mork 	u16 mbim_mtu;
597f8afb73dSBjørn Mork 	int err;
598f8afb73dSBjørn Mork 
599f8afb73dSBjørn Mork 	/* set default based on descriptors */
600f8afb73dSBjørn Mork 	ctx->max_datagram_size = clamp_t(u32, new_size,
601f8afb73dSBjørn Mork 					 cdc_ncm_min_dgram_size(dev),
602f8afb73dSBjørn Mork 					 CDC_NCM_MAX_DATAGRAM_SIZE);
603f8afb73dSBjørn Mork 
604f8afb73dSBjørn Mork 	/* inform the device about the selected Max Datagram Size? */
605f8afb73dSBjørn Mork 	if (!(cdc_ncm_flags(dev) & USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE))
606f8afb73dSBjørn Mork 		goto out;
607f8afb73dSBjørn Mork 
608f8afb73dSBjørn Mork 	/* read current mtu value from device */
609f8afb73dSBjørn Mork 	err = usbnet_read_cmd(dev, USB_CDC_GET_MAX_DATAGRAM_SIZE,
610f8afb73dSBjørn Mork 			      USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
611332f989aSOliver Neukum 			      0, iface_no, &max_datagram_size, sizeof(max_datagram_size));
612a56dcc6bSDan Carpenter 	if (err != sizeof(max_datagram_size)) {
613f8afb73dSBjørn Mork 		dev_dbg(&dev->intf->dev, "GET_MAX_DATAGRAM_SIZE failed\n");
614f8afb73dSBjørn Mork 		goto out;
615f8afb73dSBjørn Mork 	}
616f8afb73dSBjørn Mork 
617f8afb73dSBjørn Mork 	if (le16_to_cpu(max_datagram_size) == ctx->max_datagram_size)
618f8afb73dSBjørn Mork 		goto out;
619f8afb73dSBjørn Mork 
620f8afb73dSBjørn Mork 	max_datagram_size = cpu_to_le16(ctx->max_datagram_size);
621f8afb73dSBjørn Mork 	err = usbnet_write_cmd(dev, USB_CDC_SET_MAX_DATAGRAM_SIZE,
622f8afb73dSBjørn Mork 			       USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE,
623332f989aSOliver Neukum 			       0, iface_no, &max_datagram_size, sizeof(max_datagram_size));
624f8afb73dSBjørn Mork 	if (err < 0)
625f8afb73dSBjørn Mork 		dev_dbg(&dev->intf->dev, "SET_MAX_DATAGRAM_SIZE failed\n");
626f8afb73dSBjørn Mork 
627f8afb73dSBjørn Mork out:
628f8afb73dSBjørn Mork 	/* set MTU to max supported by the device if necessary */
629f8afb73dSBjørn Mork 	dev->net->mtu = min_t(int, dev->net->mtu, ctx->max_datagram_size - cdc_ncm_eth_hlen(dev));
630f8afb73dSBjørn Mork 
631f8afb73dSBjørn Mork 	/* do not exceed operater preferred MTU */
632f8afb73dSBjørn Mork 	if (ctx->mbim_extended_desc) {
633f8afb73dSBjørn Mork 		mbim_mtu = le16_to_cpu(ctx->mbim_extended_desc->wMTU);
634f8afb73dSBjørn Mork 		if (mbim_mtu != 0 && mbim_mtu < dev->net->mtu)
635f8afb73dSBjørn Mork 			dev->net->mtu = mbim_mtu;
636f8afb73dSBjørn Mork 	}
637f8afb73dSBjørn Mork }
638f8afb73dSBjørn Mork 
639f8afb73dSBjørn Mork static void cdc_ncm_fix_modulus(struct usbnet *dev)
640f8afb73dSBjørn Mork {
641f8afb73dSBjørn Mork 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
642f8afb73dSBjørn Mork 	u32 val;
643900d495aSAlexey Orishko 
644900d495aSAlexey Orishko 	/*
645900d495aSAlexey Orishko 	 * verify that the structure alignment is:
646900d495aSAlexey Orishko 	 * - power of two
647900d495aSAlexey Orishko 	 * - not greater than the maximum transmit length
648900d495aSAlexey Orishko 	 * - not less than four bytes
649900d495aSAlexey Orishko 	 */
650900d495aSAlexey Orishko 	val = ctx->tx_ndp_modulus;
651900d495aSAlexey Orishko 
652900d495aSAlexey Orishko 	if ((val < USB_CDC_NCM_NDP_ALIGN_MIN_SIZE) ||
653900d495aSAlexey Orishko 	    (val != ((-val) & val)) || (val >= ctx->tx_max)) {
654ae223cd4SBjørn Mork 		dev_dbg(&dev->intf->dev, "Using default alignment: 4 bytes\n");
655900d495aSAlexey Orishko 		ctx->tx_ndp_modulus = USB_CDC_NCM_NDP_ALIGN_MIN_SIZE;
656900d495aSAlexey Orishko 	}
657900d495aSAlexey Orishko 
658900d495aSAlexey Orishko 	/*
659900d495aSAlexey Orishko 	 * verify that the payload alignment is:
660900d495aSAlexey Orishko 	 * - power of two
661900d495aSAlexey Orishko 	 * - not greater than the maximum transmit length
662900d495aSAlexey Orishko 	 * - not less than four bytes
663900d495aSAlexey Orishko 	 */
664900d495aSAlexey Orishko 	val = ctx->tx_modulus;
665900d495aSAlexey Orishko 
666900d495aSAlexey Orishko 	if ((val < USB_CDC_NCM_NDP_ALIGN_MIN_SIZE) ||
667900d495aSAlexey Orishko 	    (val != ((-val) & val)) || (val >= ctx->tx_max)) {
668ae223cd4SBjørn Mork 		dev_dbg(&dev->intf->dev, "Using default transmit modulus: 4 bytes\n");
669900d495aSAlexey Orishko 		ctx->tx_modulus = USB_CDC_NCM_NDP_ALIGN_MIN_SIZE;
670900d495aSAlexey Orishko 	}
671900d495aSAlexey Orishko 
672900d495aSAlexey Orishko 	/* verify the payload remainder */
673900d495aSAlexey Orishko 	if (ctx->tx_remainder >= ctx->tx_modulus) {
674ae223cd4SBjørn Mork 		dev_dbg(&dev->intf->dev, "Using default transmit remainder: 0 bytes\n");
675900d495aSAlexey Orishko 		ctx->tx_remainder = 0;
676900d495aSAlexey Orishko 	}
677900d495aSAlexey Orishko 
678900d495aSAlexey Orishko 	/* adjust TX-remainder according to NCM specification. */
679f8afb73dSBjørn Mork 	ctx->tx_remainder = ((ctx->tx_remainder - cdc_ncm_eth_hlen(dev)) &
680900d495aSAlexey Orishko 			     (ctx->tx_modulus - 1));
68184e77a8bSAlexey Orishko }
682900d495aSAlexey Orishko 
683f8afb73dSBjørn Mork static int cdc_ncm_setup(struct usbnet *dev)
684f8afb73dSBjørn Mork {
685f8afb73dSBjørn Mork 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
68650f1cb1cSBjørn Mork 	u32 def_rx, def_tx;
68750f1cb1cSBjørn Mork 
68850f1cb1cSBjørn Mork 	/* be conservative when selecting intial buffer size to
68950f1cb1cSBjørn Mork 	 * increase the number of hosts this will work for
69050f1cb1cSBjørn Mork 	 */
69150f1cb1cSBjørn Mork 	def_rx = min_t(u32, CDC_NCM_NTB_DEF_SIZE_RX,
69250f1cb1cSBjørn Mork 		       le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize));
69350f1cb1cSBjørn Mork 	def_tx = min_t(u32, CDC_NCM_NTB_DEF_SIZE_TX,
69450f1cb1cSBjørn Mork 		       le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize));
69584e77a8bSAlexey Orishko 
696f8afb73dSBjørn Mork 	/* clamp rx_max and tx_max and inform device */
69750f1cb1cSBjørn Mork 	cdc_ncm_update_rxtx_max(dev, def_rx, def_tx);
6983f658cdeSAlexey Orishko 
699f8afb73dSBjørn Mork 	/* sanitize the modulus and remainder values */
700f8afb73dSBjørn Mork 	cdc_ncm_fix_modulus(dev);
701900d495aSAlexey Orishko 
702f8afb73dSBjørn Mork 	/* set max datagram size */
703f8afb73dSBjørn Mork 	cdc_ncm_set_dgram_size(dev, cdc_ncm_max_dgram_size(dev));
704900d495aSAlexey Orishko 	return 0;
705900d495aSAlexey Orishko }
706900d495aSAlexey Orishko 
707900d495aSAlexey Orishko static void
708ff1632aaSBjørn Mork cdc_ncm_find_endpoints(struct usbnet *dev, struct usb_interface *intf)
709900d495aSAlexey Orishko {
710ff1632aaSBjørn Mork 	struct usb_host_endpoint *e, *in = NULL, *out = NULL;
711900d495aSAlexey Orishko 	u8 ep;
712900d495aSAlexey Orishko 
713900d495aSAlexey Orishko 	for (ep = 0; ep < intf->cur_altsetting->desc.bNumEndpoints; ep++) {
714900d495aSAlexey Orishko 		e = intf->cur_altsetting->endpoint + ep;
7153fe4b335SBjørn Mork 
7163fe4b335SBjørn Mork 		/* ignore endpoints which cannot transfer data */
7173fe4b335SBjørn Mork 		if (!usb_endpoint_maxp(&e->desc))
7183fe4b335SBjørn Mork 			continue;
7193fe4b335SBjørn Mork 
720900d495aSAlexey Orishko 		switch (e->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
721900d495aSAlexey Orishko 		case USB_ENDPOINT_XFER_INT:
722900d495aSAlexey Orishko 			if (usb_endpoint_dir_in(&e->desc)) {
723ff1632aaSBjørn Mork 				if (!dev->status)
724ff1632aaSBjørn Mork 					dev->status = e;
725900d495aSAlexey Orishko 			}
726900d495aSAlexey Orishko 			break;
727900d495aSAlexey Orishko 
728900d495aSAlexey Orishko 		case USB_ENDPOINT_XFER_BULK:
729900d495aSAlexey Orishko 			if (usb_endpoint_dir_in(&e->desc)) {
730ff1632aaSBjørn Mork 				if (!in)
731ff1632aaSBjørn Mork 					in = e;
732900d495aSAlexey Orishko 			} else {
733ff1632aaSBjørn Mork 				if (!out)
734ff1632aaSBjørn Mork 					out = e;
735900d495aSAlexey Orishko 			}
736900d495aSAlexey Orishko 			break;
737900d495aSAlexey Orishko 
738900d495aSAlexey Orishko 		default:
739900d495aSAlexey Orishko 			break;
740900d495aSAlexey Orishko 		}
741900d495aSAlexey Orishko 	}
742ff1632aaSBjørn Mork 	if (in && !dev->in)
743ff1632aaSBjørn Mork 		dev->in = usb_rcvbulkpipe(dev->udev,
744ff1632aaSBjørn Mork 					  in->desc.bEndpointAddress &
745ff1632aaSBjørn Mork 					  USB_ENDPOINT_NUMBER_MASK);
746ff1632aaSBjørn Mork 	if (out && !dev->out)
747ff1632aaSBjørn Mork 		dev->out = usb_sndbulkpipe(dev->udev,
748ff1632aaSBjørn Mork 					   out->desc.bEndpointAddress &
749ff1632aaSBjørn Mork 					   USB_ENDPOINT_NUMBER_MASK);
750900d495aSAlexey Orishko }
751900d495aSAlexey Orishko 
752900d495aSAlexey Orishko static void cdc_ncm_free(struct cdc_ncm_ctx *ctx)
753900d495aSAlexey Orishko {
754900d495aSAlexey Orishko 	if (ctx == NULL)
755900d495aSAlexey Orishko 		return;
756900d495aSAlexey Orishko 
757900d495aSAlexey Orishko 	if (ctx->tx_rem_skb != NULL) {
758900d495aSAlexey Orishko 		dev_kfree_skb_any(ctx->tx_rem_skb);
759900d495aSAlexey Orishko 		ctx->tx_rem_skb = NULL;
760900d495aSAlexey Orishko 	}
761900d495aSAlexey Orishko 
762900d495aSAlexey Orishko 	if (ctx->tx_curr_skb != NULL) {
763900d495aSAlexey Orishko 		dev_kfree_skb_any(ctx->tx_curr_skb);
764900d495aSAlexey Orishko 		ctx->tx_curr_skb = NULL;
765900d495aSAlexey Orishko 	}
766900d495aSAlexey Orishko 
7670fa81b30SAlexander Bersenev 	if (ctx->is_ndp16)
7684a0e3e98SEnrico Mioso 		kfree(ctx->delayed_ndp16);
7690fa81b30SAlexander Bersenev 	else
7700fa81b30SAlexander Bersenev 		kfree(ctx->delayed_ndp32);
7714a0e3e98SEnrico Mioso 
772900d495aSAlexey Orishko 	kfree(ctx);
773900d495aSAlexey Orishko }
774900d495aSAlexey Orishko 
7751dfddff5SBjørn Mork /* we need to override the usbnet change_mtu ndo for two reasons:
7761dfddff5SBjørn Mork  *  - respect the negotiated maximum datagram size
7771dfddff5SBjørn Mork  *  - avoid unwanted changes to rx and tx buffers
7781dfddff5SBjørn Mork  */
7791dfddff5SBjørn Mork int cdc_ncm_change_mtu(struct net_device *net, int new_mtu)
7801dfddff5SBjørn Mork {
7811dfddff5SBjørn Mork 	struct usbnet *dev = netdev_priv(net);
78205a56487SRafal Redzimski 
7831dfddff5SBjørn Mork 	net->mtu = new_mtu;
78405a56487SRafal Redzimski 	cdc_ncm_set_dgram_size(dev, new_mtu + cdc_ncm_eth_hlen(dev));
78505a56487SRafal Redzimski 
7861dfddff5SBjørn Mork 	return 0;
7871dfddff5SBjørn Mork }
7881dfddff5SBjørn Mork EXPORT_SYMBOL_GPL(cdc_ncm_change_mtu);
7891dfddff5SBjørn Mork 
7901dfddff5SBjørn Mork static const struct net_device_ops cdc_ncm_netdev_ops = {
7911dfddff5SBjørn Mork 	.ndo_open	     = usbnet_open,
7921dfddff5SBjørn Mork 	.ndo_stop	     = usbnet_stop,
7931dfddff5SBjørn Mork 	.ndo_start_xmit	     = usbnet_start_xmit,
7941dfddff5SBjørn Mork 	.ndo_tx_timeout	     = usbnet_tx_timeout,
79537a2ebddSMiguel Rodríguez Pérez 	.ndo_set_rx_mode     = usbnet_set_rx_mode,
796323955a0SHeiner Kallweit 	.ndo_get_stats64     = dev_get_tstats64,
7971dfddff5SBjørn Mork 	.ndo_change_mtu	     = cdc_ncm_change_mtu,
7981dfddff5SBjørn Mork 	.ndo_set_mac_address = eth_mac_addr,
7991dfddff5SBjørn Mork 	.ndo_validate_addr   = eth_validate_addr,
8001dfddff5SBjørn Mork };
8011dfddff5SBjørn Mork 
8024a0e3e98SEnrico Mioso int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags)
803900d495aSAlexey Orishko {
804900d495aSAlexey Orishko 	struct cdc_ncm_ctx *ctx;
805900d495aSAlexey Orishko 	struct usb_driver *driver;
806900d495aSAlexey Orishko 	u8 *buf;
807900d495aSAlexey Orishko 	int len;
808900d495aSAlexey Orishko 	int temp;
809900d495aSAlexey Orishko 	u8 iface_no;
81077b0a099SOliver Neukum 	struct usb_cdc_parsed_header hdr;
811900d495aSAlexey Orishko 
812c796984fSThomas Meyer 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
8138f0923c1SDevendra Naga 	if (!ctx)
8148f0923c1SDevendra Naga 		return -ENOMEM;
815900d495aSAlexey Orishko 
8164f4e5436SEmil Renner Berthing 	ctx->dev = dev;
8174f4e5436SEmil Renner Berthing 
818c84ff1d6SAlexey Orishko 	hrtimer_init(&ctx->tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
819c84ff1d6SAlexey Orishko 	ctx->tx_timer.function = &cdc_ncm_tx_timer_cb;
8204f4e5436SEmil Renner Berthing 	tasklet_setup(&ctx->bh, cdc_ncm_txpath_bh);
821c84ff1d6SAlexey Orishko 	atomic_set(&ctx->stop, 0);
822900d495aSAlexey Orishko 	spin_lock_init(&ctx->mtx);
823900d495aSAlexey Orishko 
824900d495aSAlexey Orishko 	/* store ctx pointer in device data field */
825900d495aSAlexey Orishko 	dev->data[0] = (unsigned long)ctx;
826900d495aSAlexey Orishko 
8279fe0234cSBjørn Mork 	/* only the control interface can be successfully probed */
8289fe0234cSBjørn Mork 	ctx->control = intf;
8299fe0234cSBjørn Mork 
830900d495aSAlexey Orishko 	/* get some pointers */
831900d495aSAlexey Orishko 	driver = driver_of(intf);
832900d495aSAlexey Orishko 	buf = intf->cur_altsetting->extra;
833900d495aSAlexey Orishko 	len = intf->cur_altsetting->extralen;
834900d495aSAlexey Orishko 
835900d495aSAlexey Orishko 	/* parse through descriptors associated with control interface */
83677b0a099SOliver Neukum 	cdc_parse_cdc_header(&hdr, intf, buf, len);
837900d495aSAlexey Orishko 
8386527f833SBjørn Mork 	if (hdr.usb_cdc_union_desc)
839900d495aSAlexey Orishko 		ctx->data = usb_ifnum_to_if(dev->udev,
84077b0a099SOliver Neukum 					    hdr.usb_cdc_union_desc->bSlaveInterface0);
84177b0a099SOliver Neukum 	ctx->ether_desc = hdr.usb_cdc_ether_desc;
84277b0a099SOliver Neukum 	ctx->func_desc = hdr.usb_cdc_ncm_desc;
84377b0a099SOliver Neukum 	ctx->mbim_desc = hdr.usb_cdc_mbim_desc;
84477b0a099SOliver Neukum 	ctx->mbim_extended_desc = hdr.usb_cdc_mbim_extended_desc;
845900d495aSAlexey Orishko 
8469992c2e2SBjørn Mork 	/* some buggy devices have an IAD but no CDC Union */
8476527f833SBjørn Mork 	if (!hdr.usb_cdc_union_desc && intf->intf_assoc && intf->intf_assoc->bInterfaceCount == 2) {
84856a666dcSBjørn Mork 		ctx->data = usb_ifnum_to_if(dev->udev, intf->cur_altsetting->desc.bInterfaceNumber + 1);
84956a666dcSBjørn Mork 		dev_dbg(&intf->dev, "CDC Union missing - got slave from IAD\n");
8509992c2e2SBjørn Mork 	}
8519992c2e2SBjørn Mork 
852900d495aSAlexey Orishko 	/* check if we got everything */
853f8afb73dSBjørn Mork 	if (!ctx->data) {
854492bbe7fSGrant Grundler 		dev_err(&intf->dev, "CDC Union missing and no IAD found\n");
855900d495aSAlexey Orishko 		goto error;
856296e81f8SBjørn Mork 	}
857f8afb73dSBjørn Mork 	if (cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) {
858f8afb73dSBjørn Mork 		if (!ctx->mbim_desc) {
859492bbe7fSGrant Grundler 			dev_err(&intf->dev, "MBIM functional descriptor missing\n");
860f8afb73dSBjørn Mork 			goto error;
861f8afb73dSBjørn Mork 		}
862f8afb73dSBjørn Mork 	} else {
863f8afb73dSBjørn Mork 		if (!ctx->ether_desc || !ctx->func_desc) {
864492bbe7fSGrant Grundler 			dev_err(&intf->dev, "NCM or ECM functional descriptors missing\n");
865f8afb73dSBjørn Mork 			goto error;
866f8afb73dSBjørn Mork 		}
867f8afb73dSBjørn Mork 	}
868900d495aSAlexey Orishko 
869bbc8d922SBjørn Mork 	/* claim data interface, if different from control */
870bbc8d922SBjørn Mork 	if (ctx->data != ctx->control) {
871900d495aSAlexey Orishko 		temp = usb_driver_claim_interface(driver, ctx->data, dev);
872296e81f8SBjørn Mork 		if (temp) {
873492bbe7fSGrant Grundler 			dev_err(&intf->dev, "failed to claim data intf\n");
874900d495aSAlexey Orishko 			goto error;
875bbc8d922SBjørn Mork 		}
876296e81f8SBjørn Mork 	}
877900d495aSAlexey Orishko 
878900d495aSAlexey Orishko 	iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber;
879900d495aSAlexey Orishko 
8807b8076ceSDaniele Palmas 	/* Device-specific flags */
8817b8076ceSDaniele Palmas 	ctx->drvflags = drvflags;
8827b8076ceSDaniele Palmas 
88348906f62SBjørn Mork 	/* Reset data interface. Some devices will not reset properly
88448906f62SBjørn Mork 	 * unless they are configured first.  Toggle the altsetting to
8857b8076ceSDaniele Palmas 	 * force a reset.
8867b8076ceSDaniele Palmas 	 * Some other devices do not work properly with this procedure
8877b8076ceSDaniele Palmas 	 * that can be avoided using quirk CDC_MBIM_FLAG_AVOID_ALTSETTING_TOGGLE
88848906f62SBjørn Mork 	 */
8897b8076ceSDaniele Palmas 	if (!(ctx->drvflags & CDC_MBIM_FLAG_AVOID_ALTSETTING_TOGGLE))
89048906f62SBjørn Mork 		usb_set_interface(dev->udev, iface_no, data_altsetting);
8917b8076ceSDaniele Palmas 
892900d495aSAlexey Orishko 	temp = usb_set_interface(dev->udev, iface_no, 0);
893296e81f8SBjørn Mork 	if (temp) {
894296e81f8SBjørn Mork 		dev_dbg(&intf->dev, "set interface failed\n");
89519694ac8SAlexey Orishko 		goto error2;
896296e81f8SBjørn Mork 	}
897900d495aSAlexey Orishko 
89808c74fc9SBjørn Mork 	/* initialize basic device settings */
89908c74fc9SBjørn Mork 	if (cdc_ncm_init(dev))
900ff0992e9SBjørn Mork 		goto error2;
901ff0992e9SBjørn Mork 
902c086e709SBjørn Mork 	/* Some firmwares need a pause here or they will silently fail
903c086e709SBjørn Mork 	 * to set up the interface properly.  This value was decided
904c086e709SBjørn Mork 	 * empirically on a Sierra Wireless MC7455 running 02.08.02.00
905c086e709SBjørn Mork 	 * firmware.
906c086e709SBjørn Mork 	 */
907c086e709SBjørn Mork 	usleep_range(10000, 20000);
908c086e709SBjørn Mork 
909900d495aSAlexey Orishko 	/* configure data interface */
91038396e4cSGreg Suarez 	temp = usb_set_interface(dev->udev, iface_no, data_altsetting);
911296e81f8SBjørn Mork 	if (temp) {
912296e81f8SBjørn Mork 		dev_dbg(&intf->dev, "set interface failed\n");
91319694ac8SAlexey Orishko 		goto error2;
914296e81f8SBjørn Mork 	}
915900d495aSAlexey Orishko 
916ff1632aaSBjørn Mork 	cdc_ncm_find_endpoints(dev, ctx->data);
917ff1632aaSBjørn Mork 	cdc_ncm_find_endpoints(dev, ctx->control);
918296e81f8SBjørn Mork 	if (!dev->in || !dev->out || !dev->status) {
919296e81f8SBjørn Mork 		dev_dbg(&intf->dev, "failed to collect endpoints\n");
92019694ac8SAlexey Orishko 		goto error2;
921296e81f8SBjørn Mork 	}
922900d495aSAlexey Orishko 
923900d495aSAlexey Orishko 	usb_set_intfdata(ctx->control, dev);
924900d495aSAlexey Orishko 
92538396e4cSGreg Suarez 	if (ctx->ether_desc) {
926900d495aSAlexey Orishko 		temp = usbnet_get_ethernet_addr(dev, ctx->ether_desc->iMACAddress);
927296e81f8SBjørn Mork 		if (temp) {
928492bbe7fSGrant Grundler 			dev_err(&intf->dev, "failed to get mac address\n");
92919694ac8SAlexey Orishko 			goto error2;
930296e81f8SBjørn Mork 		}
931296e81f8SBjørn Mork 		dev_info(&intf->dev, "MAC-Address: %pM\n", dev->net->dev_addr);
93238396e4cSGreg Suarez 	}
93338396e4cSGreg Suarez 
93408c74fc9SBjørn Mork 	/* finish setting up the device specific data */
93508c74fc9SBjørn Mork 	cdc_ncm_setup(dev);
936ff0992e9SBjørn Mork 
9374a0e3e98SEnrico Mioso 	/* Allocate the delayed NDP if needed. */
9384a0e3e98SEnrico Mioso 	if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
9390fa81b30SAlexander Bersenev 		if (ctx->is_ndp16) {
9404a0e3e98SEnrico Mioso 			ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
9414a0e3e98SEnrico Mioso 			if (!ctx->delayed_ndp16)
9424a0e3e98SEnrico Mioso 				goto error2;
9430fa81b30SAlexander Bersenev 		} else {
9440fa81b30SAlexander Bersenev 			ctx->delayed_ndp32 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
9450fa81b30SAlexander Bersenev 			if (!ctx->delayed_ndp32)
9460fa81b30SAlexander Bersenev 				goto error2;
9470fa81b30SAlexander Bersenev 		}
9484a0e3e98SEnrico Mioso 		dev_info(&intf->dev, "NDP will be placed at end of frame for this device.");
9494a0e3e98SEnrico Mioso 	}
9504a0e3e98SEnrico Mioso 
9516c4e548fSBjørn Mork 	/* override ethtool_ops */
9526c4e548fSBjørn Mork 	dev->net->ethtool_ops = &cdc_ncm_ethtool_ops;
9536c4e548fSBjørn Mork 
954289507d3SBjørn Mork 	/* add our sysfs attrs */
955289507d3SBjørn Mork 	dev->net->sysfs_groups[0] = &cdc_ncm_sysfs_attr_group;
956289507d3SBjørn Mork 
9571dfddff5SBjørn Mork 	/* must handle MTU changes */
9581dfddff5SBjørn Mork 	dev->net->netdev_ops = &cdc_ncm_netdev_ops;
959f77f0aeeSJarod Wilson 	dev->net->max_mtu = cdc_ncm_max_dgram_size(dev) - cdc_ncm_eth_hlen(dev);
9601dfddff5SBjørn Mork 
961900d495aSAlexey Orishko 	return 0;
962900d495aSAlexey Orishko 
96319694ac8SAlexey Orishko error2:
96419694ac8SAlexey Orishko 	usb_set_intfdata(ctx->control, NULL);
96519694ac8SAlexey Orishko 	usb_set_intfdata(ctx->data, NULL);
9666b4ef602SBjørn Mork 	if (ctx->data != ctx->control)
96719694ac8SAlexey Orishko 		usb_driver_release_interface(driver, ctx->data);
968900d495aSAlexey Orishko error:
969900d495aSAlexey Orishko 	cdc_ncm_free((struct cdc_ncm_ctx *)dev->data[0]);
970900d495aSAlexey Orishko 	dev->data[0] = 0;
971296e81f8SBjørn Mork 	dev_info(&intf->dev, "bind() failure\n");
972900d495aSAlexey Orishko 	return -ENODEV;
973900d495aSAlexey Orishko }
974c91ce3b6SBjørn Mork EXPORT_SYMBOL_GPL(cdc_ncm_bind_common);
975900d495aSAlexey Orishko 
976c91ce3b6SBjørn Mork void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf)
977900d495aSAlexey Orishko {
978900d495aSAlexey Orishko 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
97919694ac8SAlexey Orishko 	struct usb_driver *driver = driver_of(intf);
980900d495aSAlexey Orishko 
981900d495aSAlexey Orishko 	if (ctx == NULL)
982900d495aSAlexey Orishko 		return;		/* no setup */
983900d495aSAlexey Orishko 
984c84ff1d6SAlexey Orishko 	atomic_set(&ctx->stop, 1);
985c84ff1d6SAlexey Orishko 
986c84ff1d6SAlexey Orishko 	hrtimer_cancel(&ctx->tx_timer);
987c84ff1d6SAlexey Orishko 
988c84ff1d6SAlexey Orishko 	tasklet_kill(&ctx->bh);
989c84ff1d6SAlexey Orishko 
990bbc8d922SBjørn Mork 	/* handle devices with combined control and data interface */
991bbc8d922SBjørn Mork 	if (ctx->control == ctx->data)
992bbc8d922SBjørn Mork 		ctx->data = NULL;
993bbc8d922SBjørn Mork 
99419694ac8SAlexey Orishko 	/* disconnect master --> disconnect slave */
99519694ac8SAlexey Orishko 	if (intf == ctx->control && ctx->data) {
996900d495aSAlexey Orishko 		usb_set_intfdata(ctx->data, NULL);
997900d495aSAlexey Orishko 		usb_driver_release_interface(driver, ctx->data);
99819694ac8SAlexey Orishko 		ctx->data = NULL;
999900d495aSAlexey Orishko 
100019694ac8SAlexey Orishko 	} else if (intf == ctx->data && ctx->control) {
100119694ac8SAlexey Orishko 		usb_set_intfdata(ctx->control, NULL);
1002900d495aSAlexey Orishko 		usb_driver_release_interface(driver, ctx->control);
100319694ac8SAlexey Orishko 		ctx->control = NULL;
1004900d495aSAlexey Orishko 	}
1005900d495aSAlexey Orishko 
10063e515665SBjørn Mork 	usb_set_intfdata(intf, NULL);
1007900d495aSAlexey Orishko 	cdc_ncm_free(ctx);
1008900d495aSAlexey Orishko }
1009c91ce3b6SBjørn Mork EXPORT_SYMBOL_GPL(cdc_ncm_unbind);
1010900d495aSAlexey Orishko 
101150a0ffafSBjørn Mork /* Return the number of the MBIM control interface altsetting iff it
101250a0ffafSBjørn Mork  * is preferred and available,
10131e8bbe6cSBjørn Mork  */
101450a0ffafSBjørn Mork u8 cdc_ncm_select_altsetting(struct usb_interface *intf)
101538396e4cSGreg Suarez {
10161e8bbe6cSBjørn Mork 	struct usb_host_interface *alt;
101738396e4cSGreg Suarez 
1018bd329e12SBjørn Mork 	/* The MBIM spec defines a NCM compatible default altsetting,
1019bd329e12SBjørn Mork 	 * which we may have matched:
1020bd329e12SBjørn Mork 	 *
1021bd329e12SBjørn Mork 	 *  "Functions that implement both NCM 1.0 and MBIM (an
1022bd329e12SBjørn Mork 	 *   “NCM/MBIM function”) according to this recommendation
1023bd329e12SBjørn Mork 	 *   shall provide two alternate settings for the
1024bd329e12SBjørn Mork 	 *   Communication Interface.  Alternate setting 0, and the
1025bd329e12SBjørn Mork 	 *   associated class and endpoint descriptors, shall be
1026bd329e12SBjørn Mork 	 *   constructed according to the rules given for the
1027bd329e12SBjørn Mork 	 *   Communication Interface in section 5 of [USBNCM10].
1028bd329e12SBjørn Mork 	 *   Alternate setting 1, and the associated class and
1029bd329e12SBjørn Mork 	 *   endpoint descriptors, shall be constructed according to
1030bd329e12SBjørn Mork 	 *   the rules given in section 6 (USB Device Model) of this
1031bd329e12SBjørn Mork 	 *   specification."
1032bd329e12SBjørn Mork 	 */
103350a0ffafSBjørn Mork 	if (intf->num_altsetting < 2)
103450a0ffafSBjørn Mork 		return intf->cur_altsetting->desc.bAlternateSetting;
103550a0ffafSBjørn Mork 
103650a0ffafSBjørn Mork 	if (prefer_mbim) {
10371e8bbe6cSBjørn Mork 		alt = usb_altnum_to_altsetting(intf, CDC_NCM_COMM_ALTSETTING_MBIM);
103850a0ffafSBjørn Mork 		if (alt && cdc_ncm_comm_intf_is_mbim(alt))
103950a0ffafSBjørn Mork 			return CDC_NCM_COMM_ALTSETTING_MBIM;
10401e8bbe6cSBjørn Mork 	}
104150a0ffafSBjørn Mork 	return CDC_NCM_COMM_ALTSETTING_NCM;
10421e8bbe6cSBjørn Mork }
10431e8bbe6cSBjørn Mork EXPORT_SYMBOL_GPL(cdc_ncm_select_altsetting);
10441e8bbe6cSBjørn Mork 
10451e8bbe6cSBjørn Mork static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
10461e8bbe6cSBjørn Mork {
10471e8bbe6cSBjørn Mork 	/* MBIM backwards compatible function? */
104850a0ffafSBjørn Mork 	if (cdc_ncm_select_altsetting(intf) != CDC_NCM_COMM_ALTSETTING_NCM)
1049bd329e12SBjørn Mork 		return -ENODEV;
1050bd329e12SBjørn Mork 
10514a0e3e98SEnrico Mioso 	/* The NCM data altsetting is fixed, so we hard-coded it.
10524a0e3e98SEnrico Mioso 	 * Additionally, generic NCM devices are assumed to accept arbitrarily
10534a0e3e98SEnrico Mioso 	 * placed NDP.
10544a0e3e98SEnrico Mioso 	 */
10554d06dd53SBjørn Mork 	return cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM, 0);
105638396e4cSGreg Suarez }
105738396e4cSGreg Suarez 
1058c78b7c58SBjørn Mork static void cdc_ncm_align_tail(struct sk_buff *skb, size_t modulus, size_t remainder, size_t max)
1059900d495aSAlexey Orishko {
1060c78b7c58SBjørn Mork 	size_t align = ALIGN(skb->len, modulus) - skb->len + remainder;
1061c78b7c58SBjørn Mork 
1062c78b7c58SBjørn Mork 	if (skb->len + align > max)
1063c78b7c58SBjørn Mork 		align = max - skb->len;
1064c78b7c58SBjørn Mork 	if (align && skb_tailroom(skb) >= align)
1065b080db58SJohannes Berg 		skb_put_zero(skb, align);
1066c78b7c58SBjørn Mork }
1067c78b7c58SBjørn Mork 
1068c78b7c58SBjørn Mork /* return a pointer to a valid struct usb_cdc_ncm_ndp16 of type sign, possibly
1069c78b7c58SBjørn Mork  * allocating a new one within skb
1070c78b7c58SBjørn Mork  */
10710fa81b30SAlexander Bersenev static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp16(struct cdc_ncm_ctx *ctx, struct sk_buff *skb, __le32 sign, size_t reserve)
1072c78b7c58SBjørn Mork {
1073c78b7c58SBjørn Mork 	struct usb_cdc_ncm_ndp16 *ndp16 = NULL;
1074c78b7c58SBjørn Mork 	struct usb_cdc_ncm_nth16 *nth16 = (void *)skb->data;
1075c78b7c58SBjørn Mork 	size_t ndpoffset = le16_to_cpu(nth16->wNdpIndex);
1076c78b7c58SBjørn Mork 
10774a0e3e98SEnrico Mioso 	/* If NDP should be moved to the end of the NCM package, we can't follow the
10784a0e3e98SEnrico Mioso 	* NTH16 header as we would normally do. NDP isn't written to the SKB yet, and
10794a0e3e98SEnrico Mioso 	* the wNdpIndex field in the header is actually not consistent with reality. It will be later.
10804a0e3e98SEnrico Mioso 	*/
1081f8c0cfa5SBjørn Mork 	if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
10824a0e3e98SEnrico Mioso 		if (ctx->delayed_ndp16->dwSignature == sign)
10834a0e3e98SEnrico Mioso 			return ctx->delayed_ndp16;
10844a0e3e98SEnrico Mioso 
1085f8c0cfa5SBjørn Mork 		/* We can only push a single NDP to the end. Return
1086f8c0cfa5SBjørn Mork 		 * NULL to send what we've already got and queue this
1087f8c0cfa5SBjørn Mork 		 * skb for later.
1088f8c0cfa5SBjørn Mork 		 */
1089f8c0cfa5SBjørn Mork 		else if (ctx->delayed_ndp16->dwSignature)
1090f8c0cfa5SBjørn Mork 			return NULL;
1091f8c0cfa5SBjørn Mork 	}
1092f8c0cfa5SBjørn Mork 
1093c78b7c58SBjørn Mork 	/* follow the chain of NDPs, looking for a match */
1094c78b7c58SBjørn Mork 	while (ndpoffset) {
1095c78b7c58SBjørn Mork 		ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb->data + ndpoffset);
1096c78b7c58SBjørn Mork 		if  (ndp16->dwSignature == sign)
1097c78b7c58SBjørn Mork 			return ndp16;
1098c78b7c58SBjørn Mork 		ndpoffset = le16_to_cpu(ndp16->wNextNdpIndex);
1099c78b7c58SBjørn Mork 	}
1100c78b7c58SBjørn Mork 
1101c78b7c58SBjørn Mork 	/* align new NDP */
11024a0e3e98SEnrico Mioso 	if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END))
1103e1069bbfSJim Baxter 		cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_curr_size);
1104c78b7c58SBjørn Mork 
1105c78b7c58SBjørn Mork 	/* verify that there is room for the NDP and the datagram (reserve) */
1106e1069bbfSJim Baxter 	if ((ctx->tx_curr_size - skb->len - reserve) < ctx->max_ndp_size)
1107c78b7c58SBjørn Mork 		return NULL;
1108c78b7c58SBjørn Mork 
1109c78b7c58SBjørn Mork 	/* link to it */
1110c78b7c58SBjørn Mork 	if (ndp16)
1111c78b7c58SBjørn Mork 		ndp16->wNextNdpIndex = cpu_to_le16(skb->len);
1112c78b7c58SBjørn Mork 	else
1113c78b7c58SBjørn Mork 		nth16->wNdpIndex = cpu_to_le16(skb->len);
1114c78b7c58SBjørn Mork 
1115c78b7c58SBjørn Mork 	/* push a new empty NDP */
11164a0e3e98SEnrico Mioso 	if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END))
1117ad941e69Syuan linyu 		ndp16 = skb_put_zero(skb, ctx->max_ndp_size);
11184a0e3e98SEnrico Mioso 	else
11194a0e3e98SEnrico Mioso 		ndp16 = ctx->delayed_ndp16;
11204a0e3e98SEnrico Mioso 
1121c78b7c58SBjørn Mork 	ndp16->dwSignature = sign;
1122c78b7c58SBjørn Mork 	ndp16->wLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_ndp16) + sizeof(struct usb_cdc_ncm_dpe16));
1123c78b7c58SBjørn Mork 	return ndp16;
1124900d495aSAlexey Orishko }
1125900d495aSAlexey Orishko 
11260fa81b30SAlexander Bersenev static struct usb_cdc_ncm_ndp32 *cdc_ncm_ndp32(struct cdc_ncm_ctx *ctx, struct sk_buff *skb, __le32 sign, size_t reserve)
11270fa81b30SAlexander Bersenev {
11280fa81b30SAlexander Bersenev 	struct usb_cdc_ncm_ndp32 *ndp32 = NULL;
11290fa81b30SAlexander Bersenev 	struct usb_cdc_ncm_nth32 *nth32 = (void *)skb->data;
11300fa81b30SAlexander Bersenev 	size_t ndpoffset = le32_to_cpu(nth32->dwNdpIndex);
11310fa81b30SAlexander Bersenev 
11320fa81b30SAlexander Bersenev 	/* If NDP should be moved to the end of the NCM package, we can't follow the
11330fa81b30SAlexander Bersenev 	 * NTH32 header as we would normally do. NDP isn't written to the SKB yet, and
11340fa81b30SAlexander Bersenev 	 * the wNdpIndex field in the header is actually not consistent with reality. It will be later.
11350fa81b30SAlexander Bersenev 	 */
11360fa81b30SAlexander Bersenev 	if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
11370fa81b30SAlexander Bersenev 		if (ctx->delayed_ndp32->dwSignature == sign)
11380fa81b30SAlexander Bersenev 			return ctx->delayed_ndp32;
11390fa81b30SAlexander Bersenev 
11400fa81b30SAlexander Bersenev 		/* We can only push a single NDP to the end. Return
11410fa81b30SAlexander Bersenev 		 * NULL to send what we've already got and queue this
11420fa81b30SAlexander Bersenev 		 * skb for later.
11430fa81b30SAlexander Bersenev 		 */
11440fa81b30SAlexander Bersenev 		else if (ctx->delayed_ndp32->dwSignature)
11450fa81b30SAlexander Bersenev 			return NULL;
11460fa81b30SAlexander Bersenev 	}
11470fa81b30SAlexander Bersenev 
11480fa81b30SAlexander Bersenev 	/* follow the chain of NDPs, looking for a match */
11490fa81b30SAlexander Bersenev 	while (ndpoffset) {
11500fa81b30SAlexander Bersenev 		ndp32 = (struct usb_cdc_ncm_ndp32 *)(skb->data + ndpoffset);
11510fa81b30SAlexander Bersenev 		if  (ndp32->dwSignature == sign)
11520fa81b30SAlexander Bersenev 			return ndp32;
11530fa81b30SAlexander Bersenev 		ndpoffset = le32_to_cpu(ndp32->dwNextNdpIndex);
11540fa81b30SAlexander Bersenev 	}
11550fa81b30SAlexander Bersenev 
11560fa81b30SAlexander Bersenev 	/* align new NDP */
11570fa81b30SAlexander Bersenev 	if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END))
11580fa81b30SAlexander Bersenev 		cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_curr_size);
11590fa81b30SAlexander Bersenev 
11600fa81b30SAlexander Bersenev 	/* verify that there is room for the NDP and the datagram (reserve) */
11610fa81b30SAlexander Bersenev 	if ((ctx->tx_curr_size - skb->len - reserve) < ctx->max_ndp_size)
11620fa81b30SAlexander Bersenev 		return NULL;
11630fa81b30SAlexander Bersenev 
11640fa81b30SAlexander Bersenev 	/* link to it */
11650fa81b30SAlexander Bersenev 	if (ndp32)
11660fa81b30SAlexander Bersenev 		ndp32->dwNextNdpIndex = cpu_to_le32(skb->len);
11670fa81b30SAlexander Bersenev 	else
11680fa81b30SAlexander Bersenev 		nth32->dwNdpIndex = cpu_to_le32(skb->len);
11690fa81b30SAlexander Bersenev 
11700fa81b30SAlexander Bersenev 	/* push a new empty NDP */
11710fa81b30SAlexander Bersenev 	if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END))
11720fa81b30SAlexander Bersenev 		ndp32 = skb_put_zero(skb, ctx->max_ndp_size);
11730fa81b30SAlexander Bersenev 	else
11740fa81b30SAlexander Bersenev 		ndp32 = ctx->delayed_ndp32;
11750fa81b30SAlexander Bersenev 
11760fa81b30SAlexander Bersenev 	ndp32->dwSignature = sign;
11775d0ab06bSAlexander Bersenev 	ndp32->wLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_ndp32) + sizeof(struct usb_cdc_ncm_dpe32));
11780fa81b30SAlexander Bersenev 	return ndp32;
11790fa81b30SAlexander Bersenev }
11800fa81b30SAlexander Bersenev 
1181c91ce3b6SBjørn Mork struct sk_buff *
1182bed6f762SBjørn Mork cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
1183900d495aSAlexey Orishko {
1184bed6f762SBjørn Mork 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
11850fa81b30SAlexander Bersenev 	union {
1186c78b7c58SBjørn Mork 		struct usb_cdc_ncm_nth16 *nth16;
11870fa81b30SAlexander Bersenev 		struct usb_cdc_ncm_nth32 *nth32;
11880fa81b30SAlexander Bersenev 	} nth;
11890fa81b30SAlexander Bersenev 	union {
1190c78b7c58SBjørn Mork 		struct usb_cdc_ncm_ndp16 *ndp16;
11910fa81b30SAlexander Bersenev 		struct usb_cdc_ncm_ndp32 *ndp32;
11920fa81b30SAlexander Bersenev 	} ndp;
1193900d495aSAlexey Orishko 	struct sk_buff *skb_out;
1194c78b7c58SBjørn Mork 	u16 n = 0, index, ndplen;
119584e77a8bSAlexey Orishko 	u8 ready2send = 0;
11964a0e3e98SEnrico Mioso 	u32 delayed_ndp_size;
1197aeca3a77SJim Baxter 	size_t padding_count;
11984a0e3e98SEnrico Mioso 
11994a0e3e98SEnrico Mioso 	/* When our NDP gets written in cdc_ncm_ndp(), then skb_out->len gets updated
12004a0e3e98SEnrico Mioso 	 * accordingly. Otherwise, we should check here.
12014a0e3e98SEnrico Mioso 	 */
12024a0e3e98SEnrico Mioso 	if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)
12037a68d725SJouni K. Seppänen 		delayed_ndp_size = ctx->max_ndp_size +
12047a68d725SJouni K. Seppänen 			max_t(u32,
12057a68d725SJouni K. Seppänen 			      ctx->tx_ndp_modulus,
12067a68d725SJouni K. Seppänen 			      ctx->tx_modulus + ctx->tx_remainder) - 1;
12074a0e3e98SEnrico Mioso 	else
12084a0e3e98SEnrico Mioso 		delayed_ndp_size = 0;
1209900d495aSAlexey Orishko 
1210900d495aSAlexey Orishko 	/* if there is a remaining skb, it gets priority */
1211c78b7c58SBjørn Mork 	if (skb != NULL) {
1212900d495aSAlexey Orishko 		swap(skb, ctx->tx_rem_skb);
1213c78b7c58SBjørn Mork 		swap(sign, ctx->tx_rem_sign);
1214c78b7c58SBjørn Mork 	} else {
121584e77a8bSAlexey Orishko 		ready2send = 1;
1216c78b7c58SBjørn Mork 	}
1217900d495aSAlexey Orishko 
1218900d495aSAlexey Orishko 	/* check if we are resuming an OUT skb */
1219900d495aSAlexey Orishko 	skb_out = ctx->tx_curr_skb;
1220900d495aSAlexey Orishko 
1221c78b7c58SBjørn Mork 	/* allocate a new OUT skb */
1222c78b7c58SBjørn Mork 	if (!skb_out) {
1223e1069bbfSJim Baxter 		if (ctx->tx_low_mem_val == 0) {
1224e1069bbfSJim Baxter 			ctx->tx_curr_size = ctx->tx_max;
1225e1069bbfSJim Baxter 			skb_out = alloc_skb(ctx->tx_curr_size, GFP_ATOMIC);
1226e1069bbfSJim Baxter 			/* If the memory allocation fails we will wait longer
1227e1069bbfSJim Baxter 			 * each time before attempting another full size
1228e1069bbfSJim Baxter 			 * allocation again to not overload the system
1229e1069bbfSJim Baxter 			 * further.
1230e1069bbfSJim Baxter 			 */
1231e1069bbfSJim Baxter 			if (skb_out == NULL) {
1232e1069bbfSJim Baxter 				ctx->tx_low_mem_max_cnt = min(ctx->tx_low_mem_max_cnt + 1,
1233e1069bbfSJim Baxter 							      (unsigned)CDC_NCM_LOW_MEM_MAX_CNT);
1234e1069bbfSJim Baxter 				ctx->tx_low_mem_val = ctx->tx_low_mem_max_cnt;
1235e1069bbfSJim Baxter 			}
1236e1069bbfSJim Baxter 		}
1237e1069bbfSJim Baxter 		if (skb_out == NULL) {
1238e1069bbfSJim Baxter 			/* See if a very small allocation is possible.
1239e1069bbfSJim Baxter 			 * We will send this packet immediately and hope
1240e1069bbfSJim Baxter 			 * that there is more memory available later.
1241e1069bbfSJim Baxter 			 */
1242e1069bbfSJim Baxter 			if (skb)
1243e1069bbfSJim Baxter 				ctx->tx_curr_size = max(skb->len,
1244e1069bbfSJim Baxter 					(u32)USB_CDC_NCM_NTB_MIN_OUT_SIZE);
1245e1069bbfSJim Baxter 			else
1246e1069bbfSJim Baxter 				ctx->tx_curr_size = USB_CDC_NCM_NTB_MIN_OUT_SIZE;
1247e1069bbfSJim Baxter 			skb_out = alloc_skb(ctx->tx_curr_size, GFP_ATOMIC);
1248e1069bbfSJim Baxter 
1249e1069bbfSJim Baxter 			/* No allocation possible so we will abort */
1250900d495aSAlexey Orishko 			if (skb_out == NULL) {
1251900d495aSAlexey Orishko 				if (skb != NULL) {
1252900d495aSAlexey Orishko 					dev_kfree_skb_any(skb);
1253bed6f762SBjørn Mork 					dev->net->stats.tx_dropped++;
1254900d495aSAlexey Orishko 				}
1255900d495aSAlexey Orishko 				goto exit_no_skb;
1256900d495aSAlexey Orishko 			}
1257e1069bbfSJim Baxter 			ctx->tx_low_mem_val--;
1258e1069bbfSJim Baxter 		}
12590fa81b30SAlexander Bersenev 		if (ctx->is_ndp16) {
1260c78b7c58SBjørn Mork 			/* fill out the initial 16-bit NTB header */
12610fa81b30SAlexander Bersenev 			nth.nth16 = skb_put_zero(skb_out, sizeof(struct usb_cdc_ncm_nth16));
12620fa81b30SAlexander Bersenev 			nth.nth16->dwSignature = cpu_to_le32(USB_CDC_NCM_NTH16_SIGN);
12630fa81b30SAlexander Bersenev 			nth.nth16->wHeaderLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_nth16));
12640fa81b30SAlexander Bersenev 			nth.nth16->wSequence = cpu_to_le16(ctx->tx_seq++);
12650fa81b30SAlexander Bersenev 		} else {
12660fa81b30SAlexander Bersenev 			/* fill out the initial 32-bit NTB header */
12670fa81b30SAlexander Bersenev 			nth.nth32 = skb_put_zero(skb_out, sizeof(struct usb_cdc_ncm_nth32));
12680fa81b30SAlexander Bersenev 			nth.nth32->dwSignature = cpu_to_le32(USB_CDC_NCM_NTH32_SIGN);
12690fa81b30SAlexander Bersenev 			nth.nth32->wHeaderLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_nth32));
12700fa81b30SAlexander Bersenev 			nth.nth32->wSequence = cpu_to_le16(ctx->tx_seq++);
12710fa81b30SAlexander Bersenev 		}
1272900d495aSAlexey Orishko 
1273c78b7c58SBjørn Mork 		/* count total number of frames in this NTB */
1274900d495aSAlexey Orishko 		ctx->tx_curr_frame_num = 0;
1275beeecd42SBjørn Mork 
1276beeecd42SBjørn Mork 		/* recent payload counter for this skb_out */
1277beeecd42SBjørn Mork 		ctx->tx_curr_frame_payload = 0;
1278900d495aSAlexey Orishko 	}
1279900d495aSAlexey Orishko 
1280c78b7c58SBjørn Mork 	for (n = ctx->tx_curr_frame_num; n < ctx->tx_max_datagrams; n++) {
1281c78b7c58SBjørn Mork 		/* send any remaining skb first */
1282900d495aSAlexey Orishko 		if (skb == NULL) {
1283900d495aSAlexey Orishko 			skb = ctx->tx_rem_skb;
1284c78b7c58SBjørn Mork 			sign = ctx->tx_rem_sign;
1285900d495aSAlexey Orishko 			ctx->tx_rem_skb = NULL;
1286900d495aSAlexey Orishko 
1287900d495aSAlexey Orishko 			/* check for end of skb */
1288900d495aSAlexey Orishko 			if (skb == NULL)
1289900d495aSAlexey Orishko 				break;
1290900d495aSAlexey Orishko 		}
1291900d495aSAlexey Orishko 
1292c78b7c58SBjørn Mork 		/* get the appropriate NDP for this skb */
12930fa81b30SAlexander Bersenev 		if (ctx->is_ndp16)
12940fa81b30SAlexander Bersenev 			ndp.ndp16 = cdc_ncm_ndp16(ctx, skb_out, sign, skb->len + ctx->tx_modulus + ctx->tx_remainder);
12950fa81b30SAlexander Bersenev 		else
12960fa81b30SAlexander Bersenev 			ndp.ndp32 = cdc_ncm_ndp32(ctx, skb_out, sign, skb->len + ctx->tx_modulus + ctx->tx_remainder);
1297c78b7c58SBjørn Mork 
1298c78b7c58SBjørn Mork 		/* align beginning of next frame */
1299e1069bbfSJim Baxter 		cdc_ncm_align_tail(skb_out,  ctx->tx_modulus, ctx->tx_remainder, ctx->tx_curr_size);
1300c78b7c58SBjørn Mork 
1301c78b7c58SBjørn Mork 		/* check if we had enough room left for both NDP and frame */
13020fa81b30SAlexander Bersenev 		if ((ctx->is_ndp16 && !ndp.ndp16) || (!ctx->is_ndp16 && !ndp.ndp32) ||
13030fa81b30SAlexander Bersenev 		    skb_out->len + skb->len + delayed_ndp_size > ctx->tx_curr_size) {
1304900d495aSAlexey Orishko 			if (n == 0) {
1305900d495aSAlexey Orishko 				/* won't fit, MTU problem? */
1306900d495aSAlexey Orishko 				dev_kfree_skb_any(skb);
1307900d495aSAlexey Orishko 				skb = NULL;
1308bed6f762SBjørn Mork 				dev->net->stats.tx_dropped++;
1309900d495aSAlexey Orishko 			} else {
1310900d495aSAlexey Orishko 				/* no room for skb - store for later */
1311900d495aSAlexey Orishko 				if (ctx->tx_rem_skb != NULL) {
1312900d495aSAlexey Orishko 					dev_kfree_skb_any(ctx->tx_rem_skb);
1313bed6f762SBjørn Mork 					dev->net->stats.tx_dropped++;
1314900d495aSAlexey Orishko 				}
1315900d495aSAlexey Orishko 				ctx->tx_rem_skb = skb;
1316c78b7c58SBjørn Mork 				ctx->tx_rem_sign = sign;
1317900d495aSAlexey Orishko 				skb = NULL;
131884e77a8bSAlexey Orishko 				ready2send = 1;
1319beeecd42SBjørn Mork 				ctx->tx_reason_ntb_full++;	/* count reason for transmitting */
1320900d495aSAlexey Orishko 			}
1321900d495aSAlexey Orishko 			break;
1322900d495aSAlexey Orishko 		}
1323900d495aSAlexey Orishko 
1324ef9ac209SWang Qing 		/* calculate frame number within this NDP */
13250fa81b30SAlexander Bersenev 		if (ctx->is_ndp16) {
13260fa81b30SAlexander Bersenev 			ndplen = le16_to_cpu(ndp.ndp16->wLength);
1327c78b7c58SBjørn Mork 			index = (ndplen - sizeof(struct usb_cdc_ncm_ndp16)) / sizeof(struct usb_cdc_ncm_dpe16) - 1;
1328900d495aSAlexey Orishko 
1329c78b7c58SBjørn Mork 			/* OK, add this skb */
13300fa81b30SAlexander Bersenev 			ndp.ndp16->dpe16[index].wDatagramLength = cpu_to_le16(skb->len);
13310fa81b30SAlexander Bersenev 			ndp.ndp16->dpe16[index].wDatagramIndex = cpu_to_le16(skb_out->len);
13320fa81b30SAlexander Bersenev 			ndp.ndp16->wLength = cpu_to_le16(ndplen + sizeof(struct usb_cdc_ncm_dpe16));
13330fa81b30SAlexander Bersenev 		} else {
13340fa81b30SAlexander Bersenev 			ndplen = le16_to_cpu(ndp.ndp32->wLength);
13350fa81b30SAlexander Bersenev 			index = (ndplen - sizeof(struct usb_cdc_ncm_ndp32)) / sizeof(struct usb_cdc_ncm_dpe32) - 1;
13360fa81b30SAlexander Bersenev 
13370fa81b30SAlexander Bersenev 			ndp.ndp32->dpe32[index].dwDatagramLength = cpu_to_le32(skb->len);
13380fa81b30SAlexander Bersenev 			ndp.ndp32->dpe32[index].dwDatagramIndex = cpu_to_le32(skb_out->len);
13390fa81b30SAlexander Bersenev 			ndp.ndp32->wLength = cpu_to_le16(ndplen + sizeof(struct usb_cdc_ncm_dpe32));
13400fa81b30SAlexander Bersenev 		}
134159ae1d12SJohannes Berg 		skb_put_data(skb_out, skb->data, skb->len);
1342beeecd42SBjørn Mork 		ctx->tx_curr_frame_payload += skb->len;	/* count real tx payload data */
1343900d495aSAlexey Orishko 		dev_kfree_skb_any(skb);
1344900d495aSAlexey Orishko 		skb = NULL;
1345c78b7c58SBjørn Mork 
1346c78b7c58SBjørn Mork 		/* send now if this NDP is full */
1347c78b7c58SBjørn Mork 		if (index >= CDC_NCM_DPT_DATAGRAMS_MAX) {
1348c78b7c58SBjørn Mork 			ready2send = 1;
1349beeecd42SBjørn Mork 			ctx->tx_reason_ndp_full++;	/* count reason for transmitting */
1350c78b7c58SBjørn Mork 			break;
1351c78b7c58SBjørn Mork 		}
1352900d495aSAlexey Orishko 	}
1353900d495aSAlexey Orishko 
1354900d495aSAlexey Orishko 	/* free up any dangling skb */
1355900d495aSAlexey Orishko 	if (skb != NULL) {
1356900d495aSAlexey Orishko 		dev_kfree_skb_any(skb);
1357900d495aSAlexey Orishko 		skb = NULL;
1358bed6f762SBjørn Mork 		dev->net->stats.tx_dropped++;
1359900d495aSAlexey Orishko 	}
1360900d495aSAlexey Orishko 
1361900d495aSAlexey Orishko 	ctx->tx_curr_frame_num = n;
1362900d495aSAlexey Orishko 
1363900d495aSAlexey Orishko 	if (n == 0) {
1364900d495aSAlexey Orishko 		/* wait for more frames */
1365900d495aSAlexey Orishko 		/* push variables */
1366900d495aSAlexey Orishko 		ctx->tx_curr_skb = skb_out;
1367900d495aSAlexey Orishko 		goto exit_no_skb;
1368900d495aSAlexey Orishko 
13696c4e548fSBjørn Mork 	} else if ((n < ctx->tx_max_datagrams) && (ready2send == 0) && (ctx->timer_interval > 0)) {
1370900d495aSAlexey Orishko 		/* wait for more frames */
1371900d495aSAlexey Orishko 		/* push variables */
1372900d495aSAlexey Orishko 		ctx->tx_curr_skb = skb_out;
1373900d495aSAlexey Orishko 		/* set the pending count */
1374900d495aSAlexey Orishko 		if (n < CDC_NCM_RESTART_TIMER_DATAGRAM_CNT)
1375c84ff1d6SAlexey Orishko 			ctx->tx_timer_pending = CDC_NCM_TIMER_PENDING_CNT;
1376900d495aSAlexey Orishko 		goto exit_no_skb;
1377900d495aSAlexey Orishko 
1378900d495aSAlexey Orishko 	} else {
1379beeecd42SBjørn Mork 		if (n == ctx->tx_max_datagrams)
1380beeecd42SBjørn Mork 			ctx->tx_reason_max_datagram++;	/* count reason for transmitting */
1381900d495aSAlexey Orishko 		/* frame goes out */
1382900d495aSAlexey Orishko 		/* variables will be reset at next call */
1383900d495aSAlexey Orishko 	}
1384900d495aSAlexey Orishko 
13854a0e3e98SEnrico Mioso 	/* If requested, put NDP at end of frame. */
13864a0e3e98SEnrico Mioso 	if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
13870fa81b30SAlexander Bersenev 		if (ctx->is_ndp16) {
13880fa81b30SAlexander Bersenev 			nth.nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data;
138949c2c3f2SBjørn Mork 			cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_curr_size - ctx->max_ndp_size);
13900fa81b30SAlexander Bersenev 			nth.nth16->wNdpIndex = cpu_to_le16(skb_out->len);
139159ae1d12SJohannes Berg 			skb_put_data(skb_out, ctx->delayed_ndp16, ctx->max_ndp_size);
13924a0e3e98SEnrico Mioso 
13934a0e3e98SEnrico Mioso 			/* Zero out delayed NDP - signature checking will naturally fail. */
13940fa81b30SAlexander Bersenev 			ndp.ndp16 = memset(ctx->delayed_ndp16, 0, ctx->max_ndp_size);
13950fa81b30SAlexander Bersenev 		} else {
13960fa81b30SAlexander Bersenev 			nth.nth32 = (struct usb_cdc_ncm_nth32 *)skb_out->data;
13970fa81b30SAlexander Bersenev 			cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_curr_size - ctx->max_ndp_size);
13980fa81b30SAlexander Bersenev 			nth.nth32->dwNdpIndex = cpu_to_le32(skb_out->len);
13990fa81b30SAlexander Bersenev 			skb_put_data(skb_out, ctx->delayed_ndp32, ctx->max_ndp_size);
14000fa81b30SAlexander Bersenev 
14010fa81b30SAlexander Bersenev 			ndp.ndp32 = memset(ctx->delayed_ndp32, 0, ctx->max_ndp_size);
14020fa81b30SAlexander Bersenev 		}
14034a0e3e98SEnrico Mioso 	}
14044a0e3e98SEnrico Mioso 
140543e4c6dfSBjørn Mork 	/* If collected data size is less or equal ctx->min_tx_pkt
140620572226SBjørn Mork 	 * bytes, we send buffers as it is. If we get more data, it
140720572226SBjørn Mork 	 * would be more efficient for USB HS mobile device with DMA
140820572226SBjørn Mork 	 * engine to receive a full size NTB, than canceling DMA
140920572226SBjørn Mork 	 * transfer and receiving a short packet.
14104d619f62SBjørn Mork 	 *
14114d619f62SBjørn Mork 	 * This optimization support is pointless if we end up sending
14124d619f62SBjørn Mork 	 * a ZLP after full sized NTBs.
1413900d495aSAlexey Orishko 	 */
14144d619f62SBjørn Mork 	if (!(dev->driver_info->flags & FLAG_SEND_ZLP) &&
1415aeca3a77SJim Baxter 	    skb_out->len > ctx->min_tx_pkt) {
1416e1069bbfSJim Baxter 		padding_count = ctx->tx_curr_size - skb_out->len;
14177a68d725SJouni K. Seppänen 		if (!WARN_ON(padding_count > ctx->tx_curr_size))
1418b080db58SJohannes Berg 			skb_put_zero(skb_out, padding_count);
1419e1069bbfSJim Baxter 	} else if (skb_out->len < ctx->tx_curr_size &&
1420aeca3a77SJim Baxter 		   (skb_out->len % dev->maxpacket) == 0) {
1421634fef61SJohannes Berg 		skb_put_u8(skb_out, 0);	/* force short packet */
1422aeca3a77SJim Baxter 	}
1423900d495aSAlexey Orishko 
1424c78b7c58SBjørn Mork 	/* set final frame length */
14250fa81b30SAlexander Bersenev 	if (ctx->is_ndp16) {
14260fa81b30SAlexander Bersenev 		nth.nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data;
14270fa81b30SAlexander Bersenev 		nth.nth16->wBlockLength = cpu_to_le16(skb_out->len);
14280fa81b30SAlexander Bersenev 	} else {
14290fa81b30SAlexander Bersenev 		nth.nth32 = (struct usb_cdc_ncm_nth32 *)skb_out->data;
14300fa81b30SAlexander Bersenev 		nth.nth32->dwBlockLength = cpu_to_le32(skb_out->len);
14310fa81b30SAlexander Bersenev 	}
1432900d495aSAlexey Orishko 
1433900d495aSAlexey Orishko 	/* return skb */
1434900d495aSAlexey Orishko 	ctx->tx_curr_skb = NULL;
1435beeecd42SBjørn Mork 
1436beeecd42SBjørn Mork 	/* keep private stats: framing overhead and number of NTBs */
1437beeecd42SBjørn Mork 	ctx->tx_overhead += skb_out->len - ctx->tx_curr_frame_payload;
1438beeecd42SBjørn Mork 	ctx->tx_ntbs++;
1439beeecd42SBjørn Mork 
14407a1e890eSBen Hutchings 	/* usbnet will count all the framing overhead by default.
1441beeecd42SBjørn Mork 	 * Adjust the stats so that the tx_bytes counter show real
1442beeecd42SBjørn Mork 	 * payload data instead.
1443beeecd42SBjørn Mork 	 */
14447a1e890eSBen Hutchings 	usbnet_set_skb_tx_stats(skb_out, n,
144544f6731dSBjørn Mork 				(long)ctx->tx_curr_frame_payload - skb_out->len);
14461e9e39f4SBen Hutchings 
1447900d495aSAlexey Orishko 	return skb_out;
1448900d495aSAlexey Orishko 
1449900d495aSAlexey Orishko exit_no_skb:
1450046c6594SBjørn Mork 	/* Start timer, if there is a remaining non-empty skb */
1451046c6594SBjørn Mork 	if (ctx->tx_curr_skb != NULL && n > 0)
1452c84ff1d6SAlexey Orishko 		cdc_ncm_tx_timeout_start(ctx);
1453900d495aSAlexey Orishko 	return NULL;
1454900d495aSAlexey Orishko }
1455c91ce3b6SBjørn Mork EXPORT_SYMBOL_GPL(cdc_ncm_fill_tx_frame);
1456900d495aSAlexey Orishko 
1457900d495aSAlexey Orishko static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx)
1458900d495aSAlexey Orishko {
1459900d495aSAlexey Orishko 	/* start timer, if not already started */
1460c84ff1d6SAlexey Orishko 	if (!(hrtimer_active(&ctx->tx_timer) || atomic_read(&ctx->stop)))
1461c84ff1d6SAlexey Orishko 		hrtimer_start(&ctx->tx_timer,
14628b0e1953SThomas Gleixner 				ctx->timer_interval,
1463c84ff1d6SAlexey Orishko 				HRTIMER_MODE_REL);
1464900d495aSAlexey Orishko }
1465900d495aSAlexey Orishko 
1466c84ff1d6SAlexey Orishko static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *timer)
1467900d495aSAlexey Orishko {
1468c84ff1d6SAlexey Orishko 	struct cdc_ncm_ctx *ctx =
1469c84ff1d6SAlexey Orishko 			container_of(timer, struct cdc_ncm_ctx, tx_timer);
1470900d495aSAlexey Orishko 
1471c84ff1d6SAlexey Orishko 	if (!atomic_read(&ctx->stop))
1472c84ff1d6SAlexey Orishko 		tasklet_schedule(&ctx->bh);
1473c84ff1d6SAlexey Orishko 	return HRTIMER_NORESTART;
1474c84ff1d6SAlexey Orishko }
1475c84ff1d6SAlexey Orishko 
14764f4e5436SEmil Renner Berthing static void cdc_ncm_txpath_bh(struct tasklet_struct *t)
1477c84ff1d6SAlexey Orishko {
14784f4e5436SEmil Renner Berthing 	struct cdc_ncm_ctx *ctx = from_tasklet(ctx, t, bh);
14794f4e5436SEmil Renner Berthing 	struct usbnet *dev = ctx->dev;
1480c84ff1d6SAlexey Orishko 
1481c84ff1d6SAlexey Orishko 	spin_lock_bh(&ctx->mtx);
1482900d495aSAlexey Orishko 	if (ctx->tx_timer_pending != 0) {
1483900d495aSAlexey Orishko 		ctx->tx_timer_pending--;
1484900d495aSAlexey Orishko 		cdc_ncm_tx_timeout_start(ctx);
1485c84ff1d6SAlexey Orishko 		spin_unlock_bh(&ctx->mtx);
1486bed6f762SBjørn Mork 	} else if (dev->net != NULL) {
1487beeecd42SBjørn Mork 		ctx->tx_reason_timeout++;	/* count reason for transmitting */
1488c84ff1d6SAlexey Orishko 		spin_unlock_bh(&ctx->mtx);
1489bed6f762SBjørn Mork 		netif_tx_lock_bh(dev->net);
1490bed6f762SBjørn Mork 		usbnet_start_xmit(NULL, dev->net);
1491bed6f762SBjørn Mork 		netif_tx_unlock_bh(dev->net);
14927b1e0cbaSBjørn Mork 	} else {
14937b1e0cbaSBjørn Mork 		spin_unlock_bh(&ctx->mtx);
1494900d495aSAlexey Orishko 	}
1495f742aa8aSAlexey Orishko }
1496900d495aSAlexey Orishko 
14972f69702cSEnrico Mioso struct sk_buff *
1498900d495aSAlexey Orishko cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
1499900d495aSAlexey Orishko {
1500900d495aSAlexey Orishko 	struct sk_buff *skb_out;
1501900d495aSAlexey Orishko 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
1502900d495aSAlexey Orishko 
1503900d495aSAlexey Orishko 	/*
1504900d495aSAlexey Orishko 	 * The Ethernet API we are using does not support transmitting
1505900d495aSAlexey Orishko 	 * multiple Ethernet frames in a single call. This driver will
1506900d495aSAlexey Orishko 	 * accumulate multiple Ethernet frames and send out a larger
1507900d495aSAlexey Orishko 	 * USB frame when the USB buffer is full or when a single jiffies
1508900d495aSAlexey Orishko 	 * timeout happens.
1509900d495aSAlexey Orishko 	 */
1510900d495aSAlexey Orishko 	if (ctx == NULL)
1511900d495aSAlexey Orishko 		goto error;
1512900d495aSAlexey Orishko 
1513c84ff1d6SAlexey Orishko 	spin_lock_bh(&ctx->mtx);
15140fa81b30SAlexander Bersenev 
15150fa81b30SAlexander Bersenev 	if (ctx->is_ndp16)
1516bed6f762SBjørn Mork 		skb_out = cdc_ncm_fill_tx_frame(dev, skb, cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN));
15170fa81b30SAlexander Bersenev 	else
15180fa81b30SAlexander Bersenev 		skb_out = cdc_ncm_fill_tx_frame(dev, skb, cpu_to_le32(USB_CDC_NCM_NDP32_NOCRC_SIGN));
15190fa81b30SAlexander Bersenev 
1520c84ff1d6SAlexey Orishko 	spin_unlock_bh(&ctx->mtx);
1521900d495aSAlexey Orishko 	return skb_out;
1522900d495aSAlexey Orishko 
1523900d495aSAlexey Orishko error:
1524900d495aSAlexey Orishko 	if (skb != NULL)
1525900d495aSAlexey Orishko 		dev_kfree_skb_any(skb);
1526900d495aSAlexey Orishko 
1527900d495aSAlexey Orishko 	return NULL;
1528900d495aSAlexey Orishko }
15292f69702cSEnrico Mioso EXPORT_SYMBOL_GPL(cdc_ncm_tx_fixup);
1530900d495aSAlexey Orishko 
1531ff06ab13SBjørn Mork /* verify NTB header and return offset of first NDP, or negative error */
1532c91ce3b6SBjørn Mork int cdc_ncm_rx_verify_nth16(struct cdc_ncm_ctx *ctx, struct sk_buff *skb_in)
1533900d495aSAlexey Orishko {
1534ae223cd4SBjørn Mork 	struct usbnet *dev = netdev_priv(skb_in->dev);
1535d5ddb4a5SAlexey Orishko 	struct usb_cdc_ncm_nth16 *nth16;
1536ff06ab13SBjørn Mork 	int len;
1537ff06ab13SBjørn Mork 	int ret = -EINVAL;
1538900d495aSAlexey Orishko 
1539900d495aSAlexey Orishko 	if (ctx == NULL)
1540900d495aSAlexey Orishko 		goto error;
1541900d495aSAlexey Orishko 
1542d5ddb4a5SAlexey Orishko 	if (skb_in->len < (sizeof(struct usb_cdc_ncm_nth16) +
1543d5ddb4a5SAlexey Orishko 					sizeof(struct usb_cdc_ncm_ndp16))) {
1544ae223cd4SBjørn Mork 		netif_dbg(dev, rx_err, dev->net, "frame too short\n");
1545900d495aSAlexey Orishko 		goto error;
1546900d495aSAlexey Orishko 	}
1547900d495aSAlexey Orishko 
1548d5ddb4a5SAlexey Orishko 	nth16 = (struct usb_cdc_ncm_nth16 *)skb_in->data;
1549900d495aSAlexey Orishko 
1550986e10d6SBjørn Mork 	if (nth16->dwSignature != cpu_to_le32(USB_CDC_NCM_NTH16_SIGN)) {
15515448d75fSBjørn Mork 		netif_dbg(dev, rx_err, dev->net,
15525448d75fSBjørn Mork 			  "invalid NTH16 signature <%#010x>\n",
1553d5ddb4a5SAlexey Orishko 			  le32_to_cpu(nth16->dwSignature));
1554900d495aSAlexey Orishko 		goto error;
1555900d495aSAlexey Orishko 	}
1556900d495aSAlexey Orishko 
1557d5ddb4a5SAlexey Orishko 	len = le16_to_cpu(nth16->wBlockLength);
1558d5ddb4a5SAlexey Orishko 	if (len > ctx->rx_max) {
1559ae223cd4SBjørn Mork 		netif_dbg(dev, rx_err, dev->net,
1560ae223cd4SBjørn Mork 			  "unsupported NTB block length %u/%u\n", len,
1561d5ddb4a5SAlexey Orishko 			  ctx->rx_max);
1562900d495aSAlexey Orishko 		goto error;
1563900d495aSAlexey Orishko 	}
1564900d495aSAlexey Orishko 
1565d5ddb4a5SAlexey Orishko 	if ((ctx->rx_seq + 1) != le16_to_cpu(nth16->wSequence) &&
1566d5ddb4a5SAlexey Orishko 	    (ctx->rx_seq || le16_to_cpu(nth16->wSequence)) &&
1567d5ddb4a5SAlexey Orishko 	    !((ctx->rx_seq == 0xffff) && !le16_to_cpu(nth16->wSequence))) {
1568ae223cd4SBjørn Mork 		netif_dbg(dev, rx_err, dev->net,
1569ae223cd4SBjørn Mork 			  "sequence number glitch prev=%d curr=%d\n",
1570d5ddb4a5SAlexey Orishko 			  ctx->rx_seq, le16_to_cpu(nth16->wSequence));
1571d5ddb4a5SAlexey Orishko 	}
1572d5ddb4a5SAlexey Orishko 	ctx->rx_seq = le16_to_cpu(nth16->wSequence);
1573d5ddb4a5SAlexey Orishko 
1574ff06ab13SBjørn Mork 	ret = le16_to_cpu(nth16->wNdpIndex);
1575ff06ab13SBjørn Mork error:
1576ff06ab13SBjørn Mork 	return ret;
1577ff06ab13SBjørn Mork }
1578c91ce3b6SBjørn Mork EXPORT_SYMBOL_GPL(cdc_ncm_rx_verify_nth16);
1579ff06ab13SBjørn Mork 
15800fa81b30SAlexander Bersenev int cdc_ncm_rx_verify_nth32(struct cdc_ncm_ctx *ctx, struct sk_buff *skb_in)
15810fa81b30SAlexander Bersenev {
15820fa81b30SAlexander Bersenev 	struct usbnet *dev = netdev_priv(skb_in->dev);
15830fa81b30SAlexander Bersenev 	struct usb_cdc_ncm_nth32 *nth32;
15840fa81b30SAlexander Bersenev 	int len;
15850fa81b30SAlexander Bersenev 	int ret = -EINVAL;
15860fa81b30SAlexander Bersenev 
15870fa81b30SAlexander Bersenev 	if (ctx == NULL)
15880fa81b30SAlexander Bersenev 		goto error;
15890fa81b30SAlexander Bersenev 
15900fa81b30SAlexander Bersenev 	if (skb_in->len < (sizeof(struct usb_cdc_ncm_nth32) +
15910fa81b30SAlexander Bersenev 					sizeof(struct usb_cdc_ncm_ndp32))) {
15920fa81b30SAlexander Bersenev 		netif_dbg(dev, rx_err, dev->net, "frame too short\n");
15930fa81b30SAlexander Bersenev 		goto error;
15940fa81b30SAlexander Bersenev 	}
15950fa81b30SAlexander Bersenev 
15960fa81b30SAlexander Bersenev 	nth32 = (struct usb_cdc_ncm_nth32 *)skb_in->data;
15970fa81b30SAlexander Bersenev 
15980fa81b30SAlexander Bersenev 	if (nth32->dwSignature != cpu_to_le32(USB_CDC_NCM_NTH32_SIGN)) {
15990fa81b30SAlexander Bersenev 		netif_dbg(dev, rx_err, dev->net,
16000fa81b30SAlexander Bersenev 			  "invalid NTH32 signature <%#010x>\n",
16010fa81b30SAlexander Bersenev 			  le32_to_cpu(nth32->dwSignature));
16020fa81b30SAlexander Bersenev 		goto error;
16030fa81b30SAlexander Bersenev 	}
16040fa81b30SAlexander Bersenev 
16050fa81b30SAlexander Bersenev 	len = le32_to_cpu(nth32->dwBlockLength);
16060fa81b30SAlexander Bersenev 	if (len > ctx->rx_max) {
16070fa81b30SAlexander Bersenev 		netif_dbg(dev, rx_err, dev->net,
16080fa81b30SAlexander Bersenev 			  "unsupported NTB block length %u/%u\n", len,
16090fa81b30SAlexander Bersenev 			  ctx->rx_max);
16100fa81b30SAlexander Bersenev 		goto error;
16110fa81b30SAlexander Bersenev 	}
16120fa81b30SAlexander Bersenev 
16130fa81b30SAlexander Bersenev 	if ((ctx->rx_seq + 1) != le16_to_cpu(nth32->wSequence) &&
16140fa81b30SAlexander Bersenev 	    (ctx->rx_seq || le16_to_cpu(nth32->wSequence)) &&
16150fa81b30SAlexander Bersenev 	    !((ctx->rx_seq == 0xffff) && !le16_to_cpu(nth32->wSequence))) {
16160fa81b30SAlexander Bersenev 		netif_dbg(dev, rx_err, dev->net,
16170fa81b30SAlexander Bersenev 			  "sequence number glitch prev=%d curr=%d\n",
16180fa81b30SAlexander Bersenev 			  ctx->rx_seq, le16_to_cpu(nth32->wSequence));
16190fa81b30SAlexander Bersenev 	}
16200fa81b30SAlexander Bersenev 	ctx->rx_seq = le16_to_cpu(nth32->wSequence);
16210fa81b30SAlexander Bersenev 
16220fa81b30SAlexander Bersenev 	ret = le32_to_cpu(nth32->dwNdpIndex);
16230fa81b30SAlexander Bersenev error:
16240fa81b30SAlexander Bersenev 	return ret;
16250fa81b30SAlexander Bersenev }
16260fa81b30SAlexander Bersenev EXPORT_SYMBOL_GPL(cdc_ncm_rx_verify_nth32);
16270fa81b30SAlexander Bersenev 
1628ff06ab13SBjørn Mork /* verify NDP header and return number of datagrams, or negative error */
1629c91ce3b6SBjørn Mork int cdc_ncm_rx_verify_ndp16(struct sk_buff *skb_in, int ndpoffset)
1630ff06ab13SBjørn Mork {
1631ae223cd4SBjørn Mork 	struct usbnet *dev = netdev_priv(skb_in->dev);
1632ff06ab13SBjørn Mork 	struct usb_cdc_ncm_ndp16 *ndp16;
1633ff06ab13SBjørn Mork 	int ret = -EINVAL;
1634ff06ab13SBjørn Mork 
163575d67d35SBjørn Mork 	if ((ndpoffset + sizeof(struct usb_cdc_ncm_ndp16)) > skb_in->len) {
1636ae223cd4SBjørn Mork 		netif_dbg(dev, rx_err, dev->net, "invalid NDP offset  <%u>\n",
1637ae223cd4SBjørn Mork 			  ndpoffset);
1638900d495aSAlexey Orishko 		goto error;
1639900d495aSAlexey Orishko 	}
164075d67d35SBjørn Mork 	ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb_in->data + ndpoffset);
1641900d495aSAlexey Orishko 
1642ff06ab13SBjørn Mork 	if (le16_to_cpu(ndp16->wLength) < USB_CDC_NCM_NDP16_LENGTH_MIN) {
1643ae223cd4SBjørn Mork 		netif_dbg(dev, rx_err, dev->net, "invalid DPT16 length <%u>\n",
1644a26fd05dSBjørn Mork 			  le16_to_cpu(ndp16->wLength));
1645ff06ab13SBjørn Mork 		goto error;
1646ff06ab13SBjørn Mork 	}
1647ff06ab13SBjørn Mork 
1648ff06ab13SBjørn Mork 	ret = ((le16_to_cpu(ndp16->wLength) -
1649ff06ab13SBjørn Mork 					sizeof(struct usb_cdc_ncm_ndp16)) /
1650ff06ab13SBjørn Mork 					sizeof(struct usb_cdc_ncm_dpe16));
1651ff06ab13SBjørn Mork 	ret--; /* we process NDP entries except for the last one */
1652ff06ab13SBjørn Mork 
1653ae223cd4SBjørn Mork 	if ((sizeof(struct usb_cdc_ncm_ndp16) +
1654ae223cd4SBjørn Mork 	     ret * (sizeof(struct usb_cdc_ncm_dpe16))) > skb_in->len) {
1655ae223cd4SBjørn Mork 		netif_dbg(dev, rx_err, dev->net, "Invalid nframes = %d\n", ret);
1656ff06ab13SBjørn Mork 		ret = -EINVAL;
1657ff06ab13SBjørn Mork 	}
1658ff06ab13SBjørn Mork 
1659ff06ab13SBjørn Mork error:
1660ff06ab13SBjørn Mork 	return ret;
1661ff06ab13SBjørn Mork }
1662c91ce3b6SBjørn Mork EXPORT_SYMBOL_GPL(cdc_ncm_rx_verify_ndp16);
1663ff06ab13SBjørn Mork 
16640fa81b30SAlexander Bersenev /* verify NDP header and return number of datagrams, or negative error */
16650fa81b30SAlexander Bersenev int cdc_ncm_rx_verify_ndp32(struct sk_buff *skb_in, int ndpoffset)
16660fa81b30SAlexander Bersenev {
16670fa81b30SAlexander Bersenev 	struct usbnet *dev = netdev_priv(skb_in->dev);
16680fa81b30SAlexander Bersenev 	struct usb_cdc_ncm_ndp32 *ndp32;
16690fa81b30SAlexander Bersenev 	int ret = -EINVAL;
16700fa81b30SAlexander Bersenev 
16710fa81b30SAlexander Bersenev 	if ((ndpoffset + sizeof(struct usb_cdc_ncm_ndp32)) > skb_in->len) {
16720fa81b30SAlexander Bersenev 		netif_dbg(dev, rx_err, dev->net, "invalid NDP offset  <%u>\n",
16730fa81b30SAlexander Bersenev 			  ndpoffset);
16740fa81b30SAlexander Bersenev 		goto error;
16750fa81b30SAlexander Bersenev 	}
16760fa81b30SAlexander Bersenev 	ndp32 = (struct usb_cdc_ncm_ndp32 *)(skb_in->data + ndpoffset);
16770fa81b30SAlexander Bersenev 
16780fa81b30SAlexander Bersenev 	if (le16_to_cpu(ndp32->wLength) < USB_CDC_NCM_NDP32_LENGTH_MIN) {
16790fa81b30SAlexander Bersenev 		netif_dbg(dev, rx_err, dev->net, "invalid DPT32 length <%u>\n",
16800fa81b30SAlexander Bersenev 			  le16_to_cpu(ndp32->wLength));
16810fa81b30SAlexander Bersenev 		goto error;
16820fa81b30SAlexander Bersenev 	}
16830fa81b30SAlexander Bersenev 
16840fa81b30SAlexander Bersenev 	ret = ((le16_to_cpu(ndp32->wLength) -
16850fa81b30SAlexander Bersenev 					sizeof(struct usb_cdc_ncm_ndp32)) /
16860fa81b30SAlexander Bersenev 					sizeof(struct usb_cdc_ncm_dpe32));
16870fa81b30SAlexander Bersenev 	ret--; /* we process NDP entries except for the last one */
16880fa81b30SAlexander Bersenev 
16890fa81b30SAlexander Bersenev 	if ((sizeof(struct usb_cdc_ncm_ndp32) +
16900fa81b30SAlexander Bersenev 	     ret * (sizeof(struct usb_cdc_ncm_dpe32))) > skb_in->len) {
16910fa81b30SAlexander Bersenev 		netif_dbg(dev, rx_err, dev->net, "Invalid nframes = %d\n", ret);
16920fa81b30SAlexander Bersenev 		ret = -EINVAL;
16930fa81b30SAlexander Bersenev 	}
16940fa81b30SAlexander Bersenev 
16950fa81b30SAlexander Bersenev error:
16960fa81b30SAlexander Bersenev 	return ret;
16970fa81b30SAlexander Bersenev }
16980fa81b30SAlexander Bersenev EXPORT_SYMBOL_GPL(cdc_ncm_rx_verify_ndp32);
16990fa81b30SAlexander Bersenev 
17002f69702cSEnrico Mioso int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
1701ff06ab13SBjørn Mork {
1702ff06ab13SBjørn Mork 	struct sk_buff *skb;
1703ff06ab13SBjørn Mork 	struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
1704ff06ab13SBjørn Mork 	int len;
1705ff06ab13SBjørn Mork 	int nframes;
1706ff06ab13SBjørn Mork 	int x;
1707ff06ab13SBjørn Mork 	int offset;
17080fa81b30SAlexander Bersenev 	union {
1709ff06ab13SBjørn Mork 		struct usb_cdc_ncm_ndp16 *ndp16;
17100fa81b30SAlexander Bersenev 		struct usb_cdc_ncm_ndp32 *ndp32;
17110fa81b30SAlexander Bersenev 	} ndp;
17120fa81b30SAlexander Bersenev 	union {
1713ff06ab13SBjørn Mork 		struct usb_cdc_ncm_dpe16 *dpe16;
17140fa81b30SAlexander Bersenev 		struct usb_cdc_ncm_dpe32 *dpe32;
17150fa81b30SAlexander Bersenev 	} dpe;
17160fa81b30SAlexander Bersenev 
1717ff06ab13SBjørn Mork 	int ndpoffset;
1718ff06ab13SBjørn Mork 	int loopcount = 50; /* arbitrary max preventing infinite loop */
1719beeecd42SBjørn Mork 	u32 payload = 0;
1720ff06ab13SBjørn Mork 
17210fa81b30SAlexander Bersenev 	if (ctx->is_ndp16)
1722ff06ab13SBjørn Mork 		ndpoffset = cdc_ncm_rx_verify_nth16(ctx, skb_in);
17230fa81b30SAlexander Bersenev 	else
17240fa81b30SAlexander Bersenev 		ndpoffset = cdc_ncm_rx_verify_nth32(ctx, skb_in);
17250fa81b30SAlexander Bersenev 
1726ff06ab13SBjørn Mork 	if (ndpoffset < 0)
1727ff06ab13SBjørn Mork 		goto error;
1728ff06ab13SBjørn Mork 
1729ff06ab13SBjørn Mork next_ndp:
17300fa81b30SAlexander Bersenev 	if (ctx->is_ndp16) {
1731ff06ab13SBjørn Mork 		nframes = cdc_ncm_rx_verify_ndp16(skb_in, ndpoffset);
1732ff06ab13SBjørn Mork 		if (nframes < 0)
1733ff06ab13SBjørn Mork 			goto error;
1734ff06ab13SBjørn Mork 
17350fa81b30SAlexander Bersenev 		ndp.ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb_in->data + ndpoffset);
1736ff06ab13SBjørn Mork 
17370fa81b30SAlexander Bersenev 		if (ndp.ndp16->dwSignature != cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN)) {
17385448d75fSBjørn Mork 			netif_dbg(dev, rx_err, dev->net,
17395448d75fSBjørn Mork 				  "invalid DPT16 signature <%#010x>\n",
17400fa81b30SAlexander Bersenev 				  le32_to_cpu(ndp.ndp16->dwSignature));
174175d67d35SBjørn Mork 			goto err_ndp;
1742900d495aSAlexey Orishko 		}
17430fa81b30SAlexander Bersenev 		dpe.dpe16 = ndp.ndp16->dpe16;
17440fa81b30SAlexander Bersenev 	} else {
17450fa81b30SAlexander Bersenev 		nframes = cdc_ncm_rx_verify_ndp32(skb_in, ndpoffset);
17460fa81b30SAlexander Bersenev 		if (nframes < 0)
17470fa81b30SAlexander Bersenev 			goto error;
1748900d495aSAlexey Orishko 
17490fa81b30SAlexander Bersenev 		ndp.ndp32 = (struct usb_cdc_ncm_ndp32 *)(skb_in->data + ndpoffset);
17500fa81b30SAlexander Bersenev 
17510fa81b30SAlexander Bersenev 		if (ndp.ndp32->dwSignature != cpu_to_le32(USB_CDC_NCM_NDP32_NOCRC_SIGN)) {
17520fa81b30SAlexander Bersenev 			netif_dbg(dev, rx_err, dev->net,
17530fa81b30SAlexander Bersenev 				  "invalid DPT32 signature <%#010x>\n",
17540fa81b30SAlexander Bersenev 				  le32_to_cpu(ndp.ndp32->dwSignature));
17550fa81b30SAlexander Bersenev 			goto err_ndp;
17560fa81b30SAlexander Bersenev 		}
17570fa81b30SAlexander Bersenev 		dpe.dpe32 = ndp.ndp32->dpe32;
17580fa81b30SAlexander Bersenev 	}
17590fa81b30SAlexander Bersenev 
17600fa81b30SAlexander Bersenev 	for (x = 0; x < nframes; x++) {
17610fa81b30SAlexander Bersenev 		if (ctx->is_ndp16) {
17620fa81b30SAlexander Bersenev 			offset = le16_to_cpu(dpe.dpe16->wDatagramIndex);
17630fa81b30SAlexander Bersenev 			len = le16_to_cpu(dpe.dpe16->wDatagramLength);
17640fa81b30SAlexander Bersenev 		} else {
17650fa81b30SAlexander Bersenev 			offset = le32_to_cpu(dpe.dpe32->dwDatagramIndex);
17660fa81b30SAlexander Bersenev 			len = le32_to_cpu(dpe.dpe32->dwDatagramLength);
17670fa81b30SAlexander Bersenev 		}
1768900d495aSAlexey Orishko 
1769900d495aSAlexey Orishko 		/*
1770900d495aSAlexey Orishko 		 * CDC NCM ch. 3.7
1771900d495aSAlexey Orishko 		 * All entries after first NULL entry are to be ignored
1772900d495aSAlexey Orishko 		 */
1773d5ddb4a5SAlexey Orishko 		if ((offset == 0) || (len == 0)) {
1774900d495aSAlexey Orishko 			if (!x)
177575d67d35SBjørn Mork 				goto err_ndp; /* empty NTB */
1776900d495aSAlexey Orishko 			break;
1777900d495aSAlexey Orishko 		}
1778900d495aSAlexey Orishko 
1779900d495aSAlexey Orishko 		/* sanity checking */
1780d5ddb4a5SAlexey Orishko 		if (((offset + len) > skb_in->len) ||
1781d5ddb4a5SAlexey Orishko 				(len > ctx->rx_max) || (len < ETH_HLEN)) {
1782ae223cd4SBjørn Mork 			netif_dbg(dev, rx_err, dev->net,
1783ae223cd4SBjørn Mork 				  "invalid frame detected (ignored) offset[%u]=%u, length=%u, skb=%p\n",
1784d5ddb4a5SAlexey Orishko 				  x, offset, len, skb_in);
1785900d495aSAlexey Orishko 			if (!x)
178675d67d35SBjørn Mork 				goto err_ndp;
1787900d495aSAlexey Orishko 			break;
1788900d495aSAlexey Orishko 
1789900d495aSAlexey Orishko 		} else {
17901e2c6117SBjørn Mork 			/* create a fresh copy to reduce truesize */
17911e2c6117SBjørn Mork 			skb = netdev_alloc_skb_ip_align(dev->net,  len);
17929e56790aSJesper Juhl 			if (!skb)
17939e56790aSJesper Juhl 				goto error;
179459ae1d12SJohannes Berg 			skb_put_data(skb, skb_in->data + offset, len);
1795900d495aSAlexey Orishko 			usbnet_skb_return(dev, skb);
1796beeecd42SBjørn Mork 			payload += len;	/* count payload bytes in this NTB */
1797900d495aSAlexey Orishko 		}
17980fa81b30SAlexander Bersenev 
17990fa81b30SAlexander Bersenev 		if (ctx->is_ndp16)
18000fa81b30SAlexander Bersenev 			dpe.dpe16++;
18010fa81b30SAlexander Bersenev 		else
18020fa81b30SAlexander Bersenev 			dpe.dpe32++;
1803900d495aSAlexey Orishko 	}
180475d67d35SBjørn Mork err_ndp:
180575d67d35SBjørn Mork 	/* are there more NDPs to process? */
18060fa81b30SAlexander Bersenev 	if (ctx->is_ndp16)
18070fa81b30SAlexander Bersenev 		ndpoffset = le16_to_cpu(ndp.ndp16->wNextNdpIndex);
18080fa81b30SAlexander Bersenev 	else
18090fa81b30SAlexander Bersenev 		ndpoffset = le32_to_cpu(ndp.ndp32->dwNextNdpIndex);
18100fa81b30SAlexander Bersenev 
181175d67d35SBjørn Mork 	if (ndpoffset && loopcount--)
181275d67d35SBjørn Mork 		goto next_ndp;
181375d67d35SBjørn Mork 
1814beeecd42SBjørn Mork 	/* update stats */
1815beeecd42SBjørn Mork 	ctx->rx_overhead += skb_in->len - payload;
1816beeecd42SBjørn Mork 	ctx->rx_ntbs++;
1817beeecd42SBjørn Mork 
1818900d495aSAlexey Orishko 	return 1;
1819900d495aSAlexey Orishko error:
1820900d495aSAlexey Orishko 	return 0;
1821900d495aSAlexey Orishko }
18222f69702cSEnrico Mioso EXPORT_SYMBOL_GPL(cdc_ncm_rx_fixup);
1823900d495aSAlexey Orishko 
1824900d495aSAlexey Orishko static void
1825bed6f762SBjørn Mork cdc_ncm_speed_change(struct usbnet *dev,
182684e77a8bSAlexey Orishko 		     struct usb_cdc_speed_change *data)
1827900d495aSAlexey Orishko {
1828*eb47c274SOliver Neukum 	/* RTL8156 shipped before 2021 sends notification about every 32ms. */
1829*eb47c274SOliver Neukum 	dev->rx_speed = le32_to_cpu(data->DLBitRRate);
1830*eb47c274SOliver Neukum 	dev->tx_speed = le32_to_cpu(data->ULBitRate);
1831900d495aSAlexey Orishko }
1832900d495aSAlexey Orishko 
1833900d495aSAlexey Orishko static void cdc_ncm_status(struct usbnet *dev, struct urb *urb)
1834900d495aSAlexey Orishko {
1835900d495aSAlexey Orishko 	struct usb_cdc_notification *event;
1836900d495aSAlexey Orishko 
1837900d495aSAlexey Orishko 	if (urb->actual_length < sizeof(*event))
1838900d495aSAlexey Orishko 		return;
1839900d495aSAlexey Orishko 
1840900d495aSAlexey Orishko 	/* test for split data in 8-byte chunks */
1841900d495aSAlexey Orishko 	if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) {
1842bed6f762SBjørn Mork 		cdc_ncm_speed_change(dev,
184384e77a8bSAlexey Orishko 		      (struct usb_cdc_speed_change *)urb->transfer_buffer);
1844900d495aSAlexey Orishko 		return;
1845900d495aSAlexey Orishko 	}
1846900d495aSAlexey Orishko 
1847900d495aSAlexey Orishko 	event = urb->transfer_buffer;
1848900d495aSAlexey Orishko 
1849900d495aSAlexey Orishko 	switch (event->bNotificationType) {
1850900d495aSAlexey Orishko 	case USB_CDC_NOTIFY_NETWORK_CONNECTION:
1851900d495aSAlexey Orishko 		/*
1852900d495aSAlexey Orishko 		 * According to the CDC NCM specification ch.7.1
1853900d495aSAlexey Orishko 		 * USB_CDC_NOTIFY_NETWORK_CONNECTION notification shall be
1854900d495aSAlexey Orishko 		 * sent by device after USB_CDC_NOTIFY_SPEED_CHANGE.
1855900d495aSAlexey Orishko 		 */
1856*eb47c274SOliver Neukum 		/* RTL8156 shipped before 2021 sends notification about
1857*eb47c274SOliver Neukum 		 * every 32ms. Don't forward notification if state is same.
1858*eb47c274SOliver Neukum 		 */
1859de658a19SGrant Grundler 		if (netif_carrier_ok(dev->net) != !!event->wValue)
1860fa83dbeeSBjørn Mork 			usbnet_link_change(dev, !!event->wValue, 0);
1861900d495aSAlexey Orishko 		break;
1862900d495aSAlexey Orishko 
1863900d495aSAlexey Orishko 	case USB_CDC_NOTIFY_SPEED_CHANGE:
186484e77a8bSAlexey Orishko 		if (urb->actual_length < (sizeof(*event) +
186584e77a8bSAlexey Orishko 					sizeof(struct usb_cdc_speed_change)))
1866900d495aSAlexey Orishko 			set_bit(EVENT_STS_SPLIT, &dev->flags);
1867900d495aSAlexey Orishko 		else
1868bed6f762SBjørn Mork 			cdc_ncm_speed_change(dev,
186984e77a8bSAlexey Orishko 					     (struct usb_cdc_speed_change *)&event[1]);
1870900d495aSAlexey Orishko 		break;
1871900d495aSAlexey Orishko 
1872900d495aSAlexey Orishko 	default:
187367a36606SBjørn Mork 		dev_dbg(&dev->udev->dev,
187467a36606SBjørn Mork 			"NCM: unexpected notification 0x%02x!\n",
187567a36606SBjørn Mork 			event->bNotificationType);
1876900d495aSAlexey Orishko 		break;
1877900d495aSAlexey Orishko 	}
1878900d495aSAlexey Orishko }
1879900d495aSAlexey Orishko 
1880900d495aSAlexey Orishko static const struct driver_info cdc_ncm_info = {
1881900d495aSAlexey Orishko 	.description = "CDC NCM",
18824d06dd53SBjørn Mork 	.flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET
18834d06dd53SBjørn Mork 			| FLAG_LINK_INTR,
1884900d495aSAlexey Orishko 	.bind = cdc_ncm_bind,
1885900d495aSAlexey Orishko 	.unbind = cdc_ncm_unbind,
1886a5e40708SOliver Neukum 	.manage_power = usbnet_manage_power,
1887900d495aSAlexey Orishko 	.status = cdc_ncm_status,
1888900d495aSAlexey Orishko 	.rx_fixup = cdc_ncm_rx_fixup,
1889900d495aSAlexey Orishko 	.tx_fixup = cdc_ncm_tx_fixup,
1890e10dcb1bSMiguel Rodríguez Pérez 	.set_rx_mode = usbnet_cdc_update_filter,
1891900d495aSAlexey Orishko };
1892900d495aSAlexey Orishko 
1893f94898eaSDan Williams /* Same as cdc_ncm_info, but with FLAG_WWAN */
1894f94898eaSDan Williams static const struct driver_info wwan_info = {
1895f94898eaSDan Williams 	.description = "Mobile Broadband Network Device",
1896f94898eaSDan Williams 	.flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET
18974d06dd53SBjørn Mork 			| FLAG_LINK_INTR | FLAG_WWAN,
1898f94898eaSDan Williams 	.bind = cdc_ncm_bind,
1899f94898eaSDan Williams 	.unbind = cdc_ncm_unbind,
1900a5e40708SOliver Neukum 	.manage_power = usbnet_manage_power,
1901f94898eaSDan Williams 	.status = cdc_ncm_status,
1902f94898eaSDan Williams 	.rx_fixup = cdc_ncm_rx_fixup,
1903f94898eaSDan Williams 	.tx_fixup = cdc_ncm_tx_fixup,
1904e10dcb1bSMiguel Rodríguez Pérez 	.set_rx_mode = usbnet_cdc_update_filter,
1905f94898eaSDan Williams };
1906f94898eaSDan Williams 
19072f62d5aaSWei Shuai /* Same as wwan_info, but with FLAG_NOARP  */
19082f62d5aaSWei Shuai static const struct driver_info wwan_noarp_info = {
19092f62d5aaSWei Shuai 	.description = "Mobile Broadband Network Device (NO ARP)",
19102f62d5aaSWei Shuai 	.flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET
19114d06dd53SBjørn Mork 			| FLAG_LINK_INTR | FLAG_WWAN | FLAG_NOARP,
19122f62d5aaSWei Shuai 	.bind = cdc_ncm_bind,
19132f62d5aaSWei Shuai 	.unbind = cdc_ncm_unbind,
19142f62d5aaSWei Shuai 	.manage_power = usbnet_manage_power,
19152f62d5aaSWei Shuai 	.status = cdc_ncm_status,
19162f62d5aaSWei Shuai 	.rx_fixup = cdc_ncm_rx_fixup,
19172f62d5aaSWei Shuai 	.tx_fixup = cdc_ncm_tx_fixup,
1918e10dcb1bSMiguel Rodríguez Pérez 	.set_rx_mode = usbnet_cdc_update_filter,
19192f62d5aaSWei Shuai };
19202f62d5aaSWei Shuai 
1921f94898eaSDan Williams static const struct usb_device_id cdc_devs[] = {
1922f94898eaSDan Williams 	/* Ericsson MBM devices like F5521gw */
1923f94898eaSDan Williams 	{ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
1924f94898eaSDan Williams 		| USB_DEVICE_ID_MATCH_VENDOR,
1925f94898eaSDan Williams 	  .idVendor = 0x0bdb,
1926f94898eaSDan Williams 	  .bInterfaceClass = USB_CLASS_COMM,
1927f94898eaSDan Williams 	  .bInterfaceSubClass = USB_CDC_SUBCLASS_NCM,
1928f94898eaSDan Williams 	  .bInterfaceProtocol = USB_CDC_PROTO_NONE,
1929f94898eaSDan Williams 	  .driver_info = (unsigned long) &wwan_info,
1930f94898eaSDan Williams 	},
1931f94898eaSDan Williams 
193279f42232SDaniele Palmas 	/* Telit LE910 V2 */
193379f42232SDaniele Palmas 	{ USB_DEVICE_AND_INTERFACE_INFO(0x1bc7, 0x0036,
193479f42232SDaniele Palmas 		USB_CLASS_COMM,
193579f42232SDaniele Palmas 		USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
193679f42232SDaniele Palmas 	  .driver_info = (unsigned long)&wwan_noarp_info,
193779f42232SDaniele Palmas 	},
193879f42232SDaniele Palmas 
1939670c0d62SDaniele Palmas 	/* DW5812 LTE Verizon Mobile Broadband Card
1940670c0d62SDaniele Palmas 	 * Unlike DW5550 this device requires FLAG_NOARP
1941670c0d62SDaniele Palmas 	 */
1942670c0d62SDaniele Palmas 	{ USB_DEVICE_AND_INTERFACE_INFO(0x413c, 0x81bb,
1943670c0d62SDaniele Palmas 		USB_CLASS_COMM,
1944670c0d62SDaniele Palmas 		USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
1945670c0d62SDaniele Palmas 	  .driver_info = (unsigned long)&wwan_noarp_info,
1946670c0d62SDaniele Palmas 	},
1947670c0d62SDaniele Palmas 
1948fb83d5f2SDaniele Palmas 	/* DW5813 LTE AT&T Mobile Broadband Card
1949fb83d5f2SDaniele Palmas 	 * Unlike DW5550 this device requires FLAG_NOARP
1950fb83d5f2SDaniele Palmas 	 */
1951fb83d5f2SDaniele Palmas 	{ USB_DEVICE_AND_INTERFACE_INFO(0x413c, 0x81bc,
1952fb83d5f2SDaniele Palmas 		USB_CLASS_COMM,
1953fb83d5f2SDaniele Palmas 		USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
1954fb83d5f2SDaniele Palmas 	  .driver_info = (unsigned long)&wwan_noarp_info,
1955fb83d5f2SDaniele Palmas 	},
1956fb83d5f2SDaniele Palmas 
1957f3a1ef9cSPeter Meiser 	/* Dell branded MBM devices like DW5550 */
1958f3a1ef9cSPeter Meiser 	{ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
1959f3a1ef9cSPeter Meiser 		| USB_DEVICE_ID_MATCH_VENDOR,
1960f3a1ef9cSPeter Meiser 	  .idVendor = 0x413c,
1961f3a1ef9cSPeter Meiser 	  .bInterfaceClass = USB_CLASS_COMM,
1962f3a1ef9cSPeter Meiser 	  .bInterfaceSubClass = USB_CDC_SUBCLASS_NCM,
1963f3a1ef9cSPeter Meiser 	  .bInterfaceProtocol = USB_CDC_PROTO_NONE,
1964f3a1ef9cSPeter Meiser 	  .driver_info = (unsigned long) &wwan_info,
1965f3a1ef9cSPeter Meiser 	},
1966f3a1ef9cSPeter Meiser 
1967f3a1ef9cSPeter Meiser 	/* Toshiba branded MBM devices */
1968f3a1ef9cSPeter Meiser 	{ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
1969f3a1ef9cSPeter Meiser 		| USB_DEVICE_ID_MATCH_VENDOR,
1970f3a1ef9cSPeter Meiser 	  .idVendor = 0x0930,
1971f3a1ef9cSPeter Meiser 	  .bInterfaceClass = USB_CLASS_COMM,
1972f3a1ef9cSPeter Meiser 	  .bInterfaceSubClass = USB_CDC_SUBCLASS_NCM,
1973f3a1ef9cSPeter Meiser 	  .bInterfaceProtocol = USB_CDC_PROTO_NONE,
1974f3a1ef9cSPeter Meiser 	  .driver_info = (unsigned long) &wwan_info,
1975f3a1ef9cSPeter Meiser 	},
1976f3a1ef9cSPeter Meiser 
19771f84eab4SBjørn Mork 	/* tag Huawei devices as wwan */
19781f84eab4SBjørn Mork 	{ USB_VENDOR_AND_INTERFACE_INFO(0x12d1,
19791f84eab4SBjørn Mork 					USB_CLASS_COMM,
19801f84eab4SBjørn Mork 					USB_CDC_SUBCLASS_NCM,
19811f84eab4SBjørn Mork 					USB_CDC_PROTO_NONE),
19821f84eab4SBjørn Mork 	  .driver_info = (unsigned long)&wwan_info,
19831f84eab4SBjørn Mork 	},
19841f84eab4SBjørn Mork 
19852f62d5aaSWei Shuai 	/* Infineon(now Intel) HSPA Modem platform */
19862f62d5aaSWei Shuai 	{ USB_DEVICE_AND_INTERFACE_INFO(0x1519, 0x0443,
19872f62d5aaSWei Shuai 		USB_CLASS_COMM,
19882f62d5aaSWei Shuai 		USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
19892f62d5aaSWei Shuai 	  .driver_info = (unsigned long)&wwan_noarp_info,
19902f62d5aaSWei Shuai 	},
19912f62d5aaSWei Shuai 
19923b638f0fSAleksander Morgado 	/* u-blox TOBY-L4 */
19933b638f0fSAleksander Morgado 	{ USB_DEVICE_AND_INTERFACE_INFO(0x1546, 0x1010,
19943b638f0fSAleksander Morgado 		USB_CLASS_COMM,
19953b638f0fSAleksander Morgado 		USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
19963b638f0fSAleksander Morgado 	  .driver_info = (unsigned long)&wwan_info,
19973b638f0fSAleksander Morgado 	},
19983b638f0fSAleksander Morgado 
1999f94898eaSDan Williams 	/* Generic CDC-NCM devices */
2000f94898eaSDan Williams 	{ USB_INTERFACE_INFO(USB_CLASS_COMM,
2001f94898eaSDan Williams 		USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
2002f94898eaSDan Williams 		.driver_info = (unsigned long)&cdc_ncm_info,
2003f94898eaSDan Williams 	},
2004f94898eaSDan Williams 	{
2005f94898eaSDan Williams 	},
2006f94898eaSDan Williams };
2007f94898eaSDan Williams MODULE_DEVICE_TABLE(usb, cdc_devs);
2008f94898eaSDan Williams 
2009900d495aSAlexey Orishko static struct usb_driver cdc_ncm_driver = {
2010900d495aSAlexey Orishko 	.name = "cdc_ncm",
2011900d495aSAlexey Orishko 	.id_table = cdc_devs,
2012085e50e1SBjørn Mork 	.probe = usbnet_probe,
2013085e50e1SBjørn Mork 	.disconnect = usbnet_disconnect,
2014900d495aSAlexey Orishko 	.suspend = usbnet_suspend,
2015900d495aSAlexey Orishko 	.resume = usbnet_resume,
201685e3c65fSStefan Metzmacher 	.reset_resume =	usbnet_resume,
2017900d495aSAlexey Orishko 	.supports_autosuspend = 1,
2018e1f12eb6SSarah Sharp 	.disable_hub_initiated_lpm = 1,
2019900d495aSAlexey Orishko };
2020900d495aSAlexey Orishko 
2021d632eb1bSGreg Kroah-Hartman module_usb_driver(cdc_ncm_driver);
2022900d495aSAlexey Orishko 
2023900d495aSAlexey Orishko MODULE_AUTHOR("Hans Petter Selasky");
2024900d495aSAlexey Orishko MODULE_DESCRIPTION("USB CDC NCM host driver");
2025900d495aSAlexey Orishko MODULE_LICENSE("Dual BSD/GPL");
2026