diff --git a/target/linux/generic/patches-4.4/099-0001-usbnet-allow-mini-drivers-to-consume-L2-headers.patch b/target/linux/generic/patches-4.4/099-0001-usbnet-allow-mini-drivers-to-consume-L2-headers.patch new file mode 100644 index 00000000000..a1f19ea18e9 --- /dev/null +++ b/target/linux/generic/patches-4.4/099-0001-usbnet-allow-mini-drivers-to-consume-L2-headers.patch @@ -0,0 +1,39 @@ +From 81e0ce79f2919dbd5f025894d29aa806af8695c7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= +Date: Thu, 3 Dec 2015 19:24:20 +0100 +Subject: [PATCH] usbnet: allow mini-drivers to consume L2 headers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Assume the minidriver has taken care of all L2 header parsing +if it sets skb->protocol. This allows the minidriver to +support non-ethernet L2 headers, and even operate without +any L2 header at all. + +Signed-off-by: Bjørn Mork +Acked-by: Oliver Neukum +Signed-off-by: David S. Miller +--- + drivers/net/usb/usbnet.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c +index 0744bf2ef2d6..0b0ba7ef14e4 100644 +--- a/drivers/net/usb/usbnet.c ++++ b/drivers/net/usb/usbnet.c +@@ -324,7 +324,10 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) + return; + } + +- skb->protocol = eth_type_trans (skb, dev->net); ++ /* only update if unset to allow minidriver rx_fixup override */ ++ if (skb->protocol == 0) ++ skb->protocol = eth_type_trans (skb, dev->net); ++ + dev->net->stats.rx_packets++; + dev->net->stats.rx_bytes += skb->len; + +-- +2.7.4 + diff --git a/target/linux/generic/patches-4.4/099-0002-net-qmi_wwan-support-raw-IP-mode.patch b/target/linux/generic/patches-4.4/099-0002-net-qmi_wwan-support-raw-IP-mode.patch new file mode 100644 index 00000000000..8b5fc374b37 --- /dev/null +++ b/target/linux/generic/patches-4.4/099-0002-net-qmi_wwan-support-raw-IP-mode.patch @@ -0,0 +1,206 @@ +From 32f7adf633b9f99ad5089901bc7ebff57704aaa9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= +Date: Thu, 3 Dec 2015 19:24:21 +0100 +Subject: [PATCH] net: qmi_wwan: support "raw IP" mode +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +QMI wwan devices have traditionally emulated ethernet devices +by default. But they have always had the capability of operating +without any L2 header at all, transmitting and receiving "raw" +IP packets over the USB link. This firmware feature used to be +configurable through the QMI management protocol. + +Traditionally there was no way to verify the firmware mode +without attempting to change it. And the firmware would often +disallow changes anyway, i.e. due to a session already being +established. In some cases, this could be a hidden firmware +internal session, completely outside host control. For these +reasons, sticking with the "well known" default mode was safest. + +But newer generations of QMI hardware and firmware have moved +towards defaulting to "raw IP" mode instead, followed by an +increasing number of bugs in the already buggy "802.3" firmware +implementation. At the same time, the QMI management protocol +gained the ability to detect the current mode. This has enabled +the userspace QMI management application to verify the current +firmware mode without trying to modify it. + +Following this development, the latest QMI hardware and firmware +(the MDM9x30 generation) has dropped support for "802.3" mode +entirely. Support for "raw IP" framing in the driver is therefore +necessary for these devices, and to a certain degree to work +around problems with the previous generation, + +This patch adds support for "raw IP" framing for QMI devices, +changing the netdev from an ethernet device to an ARPHRD_NONE +p-t-p device when "raw IP" framing is enabled. + +The firmware setup is fully delegated to the QMI userspace +management application, through simple tunneling of the QMI +protocol. The driver will therefore not know which mode has been +"negotiated" between firmware and userspace. Allowing userspace +to inform the driver of the result through a sysfs switch is +considered a better alternative than to change the well established +clean delegation of firmware management to userspace. + +Signed-off-by: Bjørn Mork +Signed-off-by: David S. Miller +--- + drivers/net/usb/qmi_wwan.c | 98 +++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 97 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c +index e3727b66d850..98add3bf8821 100644 +--- a/drivers/net/usb/qmi_wwan.c ++++ b/drivers/net/usb/qmi_wwan.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -48,11 +49,93 @@ + struct qmi_wwan_state { + struct usb_driver *subdriver; + atomic_t pmcount; +- unsigned long unused; ++ unsigned long flags; + struct usb_interface *control; + struct usb_interface *data; + }; + ++enum qmi_wwan_flags { ++ QMI_WWAN_FLAG_RAWIP = 1 << 0, ++}; ++ ++static void qmi_wwan_netdev_setup(struct net_device *net) ++{ ++ struct usbnet *dev = netdev_priv(net); ++ struct qmi_wwan_state *info = (void *)&dev->data; ++ ++ if (info->flags & QMI_WWAN_FLAG_RAWIP) { ++ net->header_ops = NULL; /* No header */ ++ net->type = ARPHRD_NONE; ++ net->hard_header_len = 0; ++ net->addr_len = 0; ++ net->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; ++ netdev_dbg(net, "mode: raw IP\n"); ++ } else if (!net->header_ops) { /* don't bother if already set */ ++ ether_setup(net); ++ netdev_dbg(net, "mode: Ethernet\n"); ++ } ++ ++ /* recalculate buffers after changing hard_header_len */ ++ usbnet_change_mtu(net, net->mtu); ++} ++ ++static ssize_t raw_ip_show(struct device *d, struct device_attribute *attr, char *buf) ++{ ++ struct usbnet *dev = netdev_priv(to_net_dev(d)); ++ struct qmi_wwan_state *info = (void *)&dev->data; ++ ++ return sprintf(buf, "%c\n", info->flags & QMI_WWAN_FLAG_RAWIP ? 'Y' : 'N'); ++} ++ ++static ssize_t raw_ip_store(struct device *d, struct device_attribute *attr, const char *buf, size_t len) ++{ ++ struct usbnet *dev = netdev_priv(to_net_dev(d)); ++ struct qmi_wwan_state *info = (void *)&dev->data; ++ bool enable; ++ int err; ++ ++ if (strtobool(buf, &enable)) ++ return -EINVAL; ++ ++ /* no change? */ ++ if (enable == (info->flags & QMI_WWAN_FLAG_RAWIP)) ++ return len; ++ ++ /* we don't want to modify a running netdev */ ++ if (netif_running(dev->net)) { ++ netdev_err(dev->net, "Cannot change a running device\n"); ++ return -EBUSY; ++ } ++ ++ /* let other drivers deny the change */ ++ err = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE, dev->net); ++ err = notifier_to_errno(err); ++ if (err) { ++ netdev_err(dev->net, "Type change was refused\n"); ++ return err; ++ } ++ ++ if (enable) ++ info->flags |= QMI_WWAN_FLAG_RAWIP; ++ else ++ info->flags &= ~QMI_WWAN_FLAG_RAWIP; ++ qmi_wwan_netdev_setup(dev->net); ++ call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE, dev->net); ++ return len; ++} ++ ++static DEVICE_ATTR_RW(raw_ip); ++ ++static struct attribute *qmi_wwan_sysfs_attrs[] = { ++ &dev_attr_raw_ip.attr, ++ NULL, ++}; ++ ++static struct attribute_group qmi_wwan_sysfs_attr_group = { ++ .name = "qmi", ++ .attrs = qmi_wwan_sysfs_attrs, ++}; ++ + /* default ethernet address used by the modem */ + static const u8 default_modem_addr[ETH_ALEN] = {0x02, 0x50, 0xf3}; + +@@ -80,6 +163,8 @@ static const u8 buggy_fw_addr[ETH_ALEN] = {0x00, 0xa0, 0xc6, 0x00, 0x00, 0x00}; + */ + static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb) + { ++ struct qmi_wwan_state *info = (void *)&dev->data; ++ bool rawip = info->flags & QMI_WWAN_FLAG_RAWIP; + __be16 proto; + + /* This check is no longer done by usbnet */ +@@ -94,15 +179,25 @@ static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb) + proto = htons(ETH_P_IPV6); + break; + case 0x00: ++ if (rawip) ++ return 0; + if (is_multicast_ether_addr(skb->data)) + return 1; + /* possibly bogus destination - rewrite just in case */ + skb_reset_mac_header(skb); + goto fix_dest; + default: ++ if (rawip) ++ return 0; + /* pass along other packets without modifications */ + return 1; + } ++ if (rawip) { ++ skb->dev = dev->net; /* normally set by eth_type_trans */ ++ skb->protocol = proto; ++ return 1; ++ } ++ + if (skb_headroom(skb) < ETH_HLEN) + return 0; + skb_push(skb, ETH_HLEN); +@@ -326,6 +421,7 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) + dev->net->dev_addr[0] &= 0xbf; /* clear "IP" bit */ + } + dev->net->netdev_ops = &qmi_wwan_netdev_ops; ++ dev->net->sysfs_groups[0] = &qmi_wwan_sysfs_attr_group; + err: + return status; + } +-- +2.7.4 + diff --git a/target/linux/generic/patches-4.4/099-0003-net-qmi_wwan-should-hold-RTNL-while-changing-netdev-.patch b/target/linux/generic/patches-4.4/099-0003-net-qmi_wwan-should-hold-RTNL-while-changing-netdev-.patch new file mode 100644 index 00000000000..48f7141efb6 --- /dev/null +++ b/target/linux/generic/patches-4.4/099-0003-net-qmi_wwan-should-hold-RTNL-while-changing-netdev-.patch @@ -0,0 +1,107 @@ +From 6c730080e663b1d629f8aa89348291fbcdc46cd9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= +Date: Sun, 6 Dec 2015 21:25:50 +0100 +Subject: [PATCH] net: qmi_wwan: should hold RTNL while changing netdev type +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The notifier calls were thrown in as a last-minute fix for an +imagined "this device could be part of a bridge" problem. That +revealed a certain lack of locking. Not to mention testing... + +Avoid this splat: + +RTNL: assertion failed at net/core/dev.c (1639) +CPU: 0 PID: 4293 Comm: bash Not tainted 4.4.0-rc3+ #358 +Hardware name: LENOVO 2776LEG/2776LEG, BIOS 6EET55WW (3.15 ) 12/19/2011 + 0000000000000000 ffff8800ad253d60 ffffffff8122f7cf ffff8800ad253d98 + ffff8800ad253d88 ffffffff813833ab 0000000000000002 ffff880230f48560 + ffff880230a12900 ffff8800ad253da0 ffffffff813833da 0000000000000002 +Call Trace: + [] dump_stack+0x4b/0x63 + [] call_netdevice_notifiers_info+0x3d/0x59 + [] call_netdevice_notifiers+0x13/0x15 + [] raw_ip_store+0x81/0x193 [qmi_wwan] + [] dev_attr_store+0x20/0x22 + [] sysfs_kf_write+0x49/0x50 + [] kernfs_fop_write+0x10a/0x151 + [] __vfs_write+0x26/0xa5 + [] ? percpu_down_read+0x53/0x7f + [] ? __sb_start_write+0x5f/0xb0 + [] ? __sb_start_write+0x5f/0xb0 + [] vfs_write+0xa3/0xe7 + [] SyS_write+0x50/0x7e + [] entry_SYSCALL_64_fastpath+0x12/0x6f + +Fixes: 32f7adf633b9 ("net: qmi_wwan: support "raw IP" mode") +Signed-off-by: Bjørn Mork +Signed-off-by: David S. Miller +--- + drivers/net/usb/qmi_wwan.c | 22 +++++++++++++++------- + 1 file changed, 15 insertions(+), 7 deletions(-) + +diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c +index 98add3bf8821..babc84a3946c 100644 +--- a/drivers/net/usb/qmi_wwan.c ++++ b/drivers/net/usb/qmi_wwan.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -92,7 +93,7 @@ static ssize_t raw_ip_store(struct device *d, struct device_attribute *attr, co + struct usbnet *dev = netdev_priv(to_net_dev(d)); + struct qmi_wwan_state *info = (void *)&dev->data; + bool enable; +- int err; ++ int ret; + + if (strtobool(buf, &enable)) + return -EINVAL; +@@ -101,18 +102,22 @@ static ssize_t raw_ip_store(struct device *d, struct device_attribute *attr, co + if (enable == (info->flags & QMI_WWAN_FLAG_RAWIP)) + return len; + ++ if (!rtnl_trylock()) ++ return restart_syscall(); ++ + /* we don't want to modify a running netdev */ + if (netif_running(dev->net)) { + netdev_err(dev->net, "Cannot change a running device\n"); +- return -EBUSY; ++ ret = -EBUSY; ++ goto err; + } + + /* let other drivers deny the change */ +- err = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE, dev->net); +- err = notifier_to_errno(err); +- if (err) { ++ ret = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE, dev->net); ++ ret = notifier_to_errno(ret); ++ if (ret) { + netdev_err(dev->net, "Type change was refused\n"); +- return err; ++ goto err; + } + + if (enable) +@@ -121,7 +126,10 @@ static ssize_t raw_ip_store(struct device *d, struct device_attribute *attr, co + info->flags &= ~QMI_WWAN_FLAG_RAWIP; + qmi_wwan_netdev_setup(dev->net); + call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE, dev->net); +- return len; ++ ret = len; ++err: ++ rtnl_unlock(); ++ return ret; + } + + static DEVICE_ATTR_RW(raw_ip); +-- +2.7.4 + diff --git a/target/linux/generic/patches-4.4/099-0004-usbnet-fix-alignment-for-frames-with-no-ethernet-hea.patch b/target/linux/generic/patches-4.4/099-0004-usbnet-fix-alignment-for-frames-with-no-ethernet-hea.patch new file mode 100644 index 00000000000..2511e0a9614 --- /dev/null +++ b/target/linux/generic/patches-4.4/099-0004-usbnet-fix-alignment-for-frames-with-no-ethernet-hea.patch @@ -0,0 +1,73 @@ +From a4abd7a80addb4a9547f7dfc7812566b60ec505c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= +Date: Wed, 6 Dec 2017 20:21:24 +0100 +Subject: [PATCH] usbnet: fix alignment for frames with no ethernet header +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The qmi_wwan minidriver support a 'raw-ip' mode where frames are +received without any ethernet header. This causes alignment issues +because the skbs allocated by usbnet are "IP aligned". + +Fix by allowing minidrivers to disable the additional alignment +offset. This is implemented using a per-device flag, since the same +minidriver also supports 'ethernet' mode. + +Fixes: 32f7adf633b9 ("net: qmi_wwan: support "raw IP" mode") +Reported-and-tested-by: Jay Foster +Signed-off-by: Bjørn Mork +Signed-off-by: David S. Miller +--- + drivers/net/usb/qmi_wwan.c | 2 ++ + drivers/net/usb/usbnet.c | 5 ++++- + include/linux/usb/usbnet.h | 1 + + 3 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c +index c750cf7c042b..304ec6555cd8 100644 +--- a/drivers/net/usb/qmi_wwan.c ++++ b/drivers/net/usb/qmi_wwan.c +@@ -261,9 +261,11 @@ static void qmi_wwan_netdev_setup(struct net_device *net) + net->hard_header_len = 0; + net->addr_len = 0; + net->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; ++ set_bit(EVENT_NO_IP_ALIGN, &dev->flags); + netdev_dbg(net, "mode: raw IP\n"); + } else if (!net->header_ops) { /* don't bother if already set */ + ether_setup(net); ++ clear_bit(EVENT_NO_IP_ALIGN, &dev->flags); + netdev_dbg(net, "mode: Ethernet\n"); + } + +diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c +index 80348b6a8646..d56fe32bf48d 100644 +--- a/drivers/net/usb/usbnet.c ++++ b/drivers/net/usb/usbnet.c +@@ -484,7 +484,10 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) + return -ENOLINK; + } + +- skb = __netdev_alloc_skb_ip_align(dev->net, size, flags); ++ if (test_bit(EVENT_NO_IP_ALIGN, &dev->flags)) ++ skb = __netdev_alloc_skb(dev->net, size, flags); ++ else ++ skb = __netdev_alloc_skb_ip_align(dev->net, size, flags); + if (!skb) { + netif_dbg(dev, rx_err, dev->net, "no rx skb\n"); + usbnet_defer_kevent (dev, EVENT_RX_MEMORY); +diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h +index a69877734c4e..e2ec3582e549 100644 +--- a/include/linux/usb/usbnet.h ++++ b/include/linux/usb/usbnet.h +@@ -82,6 +82,7 @@ struct usbnet { + # define EVENT_RX_KILL 10 + # define EVENT_LINK_CHANGE 11 + # define EVENT_SET_RX_MODE 12 ++# define EVENT_NO_IP_ALIGN 13 + }; + + static inline struct usb_driver *driver_of(struct usb_interface *intf) +-- +2.7.4 + diff --git a/target/linux/generic/patches-4.4/099-0005-qmi_wwan-Add-missing-skb_reset_mac_header-call.patch b/target/linux/generic/patches-4.4/099-0005-qmi_wwan-Add-missing-skb_reset_mac_header-call.patch new file mode 100644 index 00000000000..08408e2414d --- /dev/null +++ b/target/linux/generic/patches-4.4/099-0005-qmi_wwan-Add-missing-skb_reset_mac_header-call.patch @@ -0,0 +1,81 @@ +From 0de0add10e587effa880c741c9413c874f16be91 Mon Sep 17 00:00:00 2001 +From: Kristian Evensen +Date: Tue, 7 Nov 2017 13:47:56 +0100 +Subject: [PATCH] qmi_wwan: Add missing skb_reset_mac_header-call +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When we receive a packet on a QMI device in raw IP mode, we should call +skb_reset_mac_header() to ensure that skb->mac_header contains a valid +offset in the packet. While it shouldn't really matter, the packets have +no MAC header and the interface is configured as-such, it seems certain +parts of the network stack expects a "good" value in skb->mac_header. + +Without the skb_reset_mac_header() call added in this patch, for example +shaping traffic (using tc) triggers the following oops on the first +received packet: + +[ 303.642957] skbuff: skb_under_panic: text:8f137918 len:177 put:67 head:8e4b0f00 data:8e4b0eff tail:0x8e4b0fb0 end:0x8e4b1520 dev:wwan0 +[ 303.655045] Kernel bug detected[#1]: +[ 303.658622] CPU: 1 PID: 1002 Comm: logd Not tainted 4.9.58 #0 +[ 303.664339] task: 8fdf05e0 task.stack: 8f15c000 +[ 303.668844] $ 0 : 00000000 00000001 0000007a 00000000 +[ 303.674062] $ 4 : 8149a2fc 8149a2fc 8149ce20 00000000 +[ 303.679284] $ 8 : 00000030 3878303a 31623465 20303235 +[ 303.684510] $12 : ded731e3 2626a277 00000000 03bd0000 +[ 303.689747] $16 : 8ef62b40 00000043 8f137918 804db5fc +[ 303.694978] $20 : 00000001 00000004 8fc13800 00000003 +[ 303.700215] $24 : 00000001 8024ab10 +[ 303.705442] $28 : 8f15c000 8fc19cf0 00000043 802cc920 +[ 303.710664] Hi : 00000000 +[ 303.713533] Lo : 74e58000 +[ 303.716436] epc : 802cc920 skb_panic+0x58/0x5c +[ 303.721046] ra : 802cc920 skb_panic+0x58/0x5c +[ 303.725639] Status: 11007c03 KERNEL EXL IE +[ 303.729823] Cause : 50800024 (ExcCode 09) +[ 303.733817] PrId : 0001992f (MIPS 1004Kc) +[ 303.737892] Modules linked in: rt2800pci rt2800mmio rt2800lib qcserial ppp_async option usb_wwan rt2x00pci rt2x00mmio rt2x00lib rndis_host qmi_wwan ppp_generic nf_nat_pptp nf_conntrack_pptp nf_conntrack_ipv6 mt76x2i +Process logd (pid: 1002, threadinfo=8f15c000, task=8fdf05e0, tls=77b3eee4) +[ 303.962509] Stack : 00000000 80408990 8f137918 000000b1 00000043 8e4b0f00 8e4b0eff 8e4b0fb0 +[ 303.970871] 8e4b1520 8fec1800 00000043 802cd2a4 6e000045 00000043 00000000 8ef62000 +[ 303.979219] 8eef5d00 8ef62b40 8fea7300 8f137918 00000000 00000000 0002bb01 793e5664 +[ 303.987568] 8ef08884 00000001 8fea7300 00000002 8fc19e80 8eef5d00 00000006 00000003 +[ 303.995934] 00000000 8030ba90 00000003 77ab3fd0 8149dc80 8004d1bc 8f15c000 8f383700 +[ 304.004324] ... +[ 304.006767] Call Trace: +[ 304.009241] [<802cc920>] skb_panic+0x58/0x5c +[ 304.013504] [<802cd2a4>] skb_push+0x78/0x90 +[ 304.017783] [<8f137918>] 0x8f137918 +[ 304.021269] Code: 00602825 0c02a3b4 24842888 <000c000d> 8c870060 8c8200a0 0007382b 00070336 8c88005c +[ 304.031034] +[ 304.032805] ---[ end trace b778c482b3f0bda9 ]--- +[ 304.041384] Kernel panic - not syncing: Fatal exception in interrupt +[ 304.051975] Rebooting in 3 seconds.. + +While the oops is for a 4.9-kernel, I was able to trigger the same oops with +net-next as of yesterday. + +Fixes: 32f7adf633b9 ("net: qmi_wwan: support "raw IP" mode") +Signed-off-by: Kristian Evensen +Acked-by: Bjørn Mork +Signed-off-by: David S. Miller +--- + drivers/net/usb/qmi_wwan.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c +index a4f229edcceb..8d4a6f7cba61 100644 +--- a/drivers/net/usb/qmi_wwan.c ++++ b/drivers/net/usb/qmi_wwan.c +@@ -499,6 +499,7 @@ static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb) + return 1; + } + if (rawip) { ++ skb_reset_mac_header(skb); + skb->dev = dev->net; /* normally set by eth_type_trans */ + skb->protocol = proto; + return 1; +-- +2.7.4 + diff --git a/target/linux/generic/patches-4.4/099-0006-net-qmi_wwan-MDM9x30-specific-power-management.patch b/target/linux/generic/patches-4.4/099-0006-net-qmi_wwan-MDM9x30-specific-power-management.patch new file mode 100644 index 00000000000..c26a86b270e --- /dev/null +++ b/target/linux/generic/patches-4.4/099-0006-net-qmi_wwan-MDM9x30-specific-power-management.patch @@ -0,0 +1,97 @@ +From 93725149794d3d418cf1eddcae60c7b536c5faa1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= +Date: Thu, 3 Dec 2015 19:24:18 +0100 +Subject: [PATCH] net: qmi_wwan: MDM9x30 specific power management +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +MDM9x30 based modems appear to go into a deeper sleep when +suspended without "Remote Wakeup" enabled. The QMI interface +will not respond unless a "set DTR" control request is sent +on resume. The effect is similar to a QMI_CTL SYNC request, +resetting (some of) the firmware state. + +We allow userspace sessions to span multiple character device +open/close sequences. This means that userspace can depend +on firmware state while both the netdev and the character +device are closed. We have disabled "needs_remote_wakeup" at +this point to allow devices without remote wakeup support to +be auto-suspended. + +To make sure the MDM9x30 keeps firmware state, we need to +keep "needs_remote_wakeup" always set. We also need to +issue a "set DTR" request to enable the QMI interface. + +Signed-off-by: Bjørn Mork +Signed-off-by: David S. Miller +--- + drivers/net/usb/qmi_wwan.c | 38 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 38 insertions(+) + +diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c +index 9a5be8b85186..fc9dd452a3b5 100644 +--- a/drivers/net/usb/qmi_wwan.c ++++ b/drivers/net/usb/qmi_wwan.c +@@ -223,6 +223,20 @@ static int qmi_wwan_register_subdriver(struct usbnet *dev) + return rv; + } + ++/* Send CDC SetControlLineState request, setting or clearing the DTR. ++ * "Required for Autoconnect and 9x30 to wake up" according to the ++ * GobiNet driver. The requirement has been verified on an MDM9230 ++ * based Sierra Wireless MC7455 ++ */ ++static int qmi_wwan_change_dtr(struct usbnet *dev, bool on) ++{ ++ u8 intf = dev->intf->cur_altsetting->desc.bInterfaceNumber; ++ ++ return usbnet_write_cmd(dev, USB_CDC_REQ_SET_CONTROL_LINE_STATE, ++ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, ++ on ? 0x01 : 0x00, intf, NULL, 0); ++} ++ + static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) + { + int status = -1; +@@ -280,6 +294,24 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) + usb_driver_release_interface(driver, info->data); + } + ++ /* disabling remote wakeup on MDM9x30 devices has the same ++ * effect as clearing DTR. The device will not respond to QMI ++ * requests until we set DTR again. This is similar to a ++ * QMI_CTL SYNC request, clearing a lot of firmware state ++ * including the client ID allocations. ++ * ++ * Our usage model allows a session to span multiple ++ * open/close events, so we must prevent the firmware from ++ * clearing out state the clients might need. ++ * ++ * MDM9x30 is the first QMI chipset with USB3 support. Abuse ++ * this fact to enable the quirk. ++ */ ++ if (le16_to_cpu(dev->udev->descriptor.bcdUSB) >= 0x0201) { ++ qmi_wwan_manage_power(dev, 1); ++ qmi_wwan_change_dtr(dev, true); ++ } ++ + /* Never use the same address on both ends of the link, even if the + * buggy firmware told us to. Or, if device is assigned the well-known + * buggy firmware MAC address, replace it with a random address, +@@ -307,6 +339,12 @@ static void qmi_wwan_unbind(struct usbnet *dev, struct usb_interface *intf) + if (info->subdriver && info->subdriver->disconnect) + info->subdriver->disconnect(info->control); + ++ /* disable MDM9x30 quirk */ ++ if (le16_to_cpu(dev->udev->descriptor.bcdUSB) >= 0x0201) { ++ qmi_wwan_change_dtr(dev, false); ++ qmi_wwan_manage_power(dev, 0); ++ } ++ + /* allow user to unbind using either control or data */ + if (intf == info->control) + other = info->data; +-- +2.7.4 + diff --git a/target/linux/generic/patches-4.4/099-0007-qmi_wwan-add-support-for-Quectel-EC21-and-EC25.patch b/target/linux/generic/patches-4.4/099-0007-qmi_wwan-add-support-for-Quectel-EC21-and-EC25.patch new file mode 100644 index 00000000000..3b8032776ac --- /dev/null +++ b/target/linux/generic/patches-4.4/099-0007-qmi_wwan-add-support-for-Quectel-EC21-and-EC25.patch @@ -0,0 +1,98 @@ +From 9a765881bf3dcd32847d7108cf48cb04a4ed993f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= +Date: Mon, 10 Oct 2016 21:12:49 +0200 +Subject: [PATCH] qmi_wwan: add support for Quectel EC21 and EC25 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The Quectel EC21 and EC25 need the same "set DTR" request as devices +based on the MDM9230 chipset, but has no USB3 support. Our best guess +is that the "set DTR" functionality depends on chipset and/or +baseband firmware generation. But USB3 is still an optional feature. + +Since we cannot enable this unconditionally for all older devices, and +there doesn't appear to be anything we can use in the USB descriptors +to identify these chips, we are forced to use a device specific quirk +flag. + +Reported-and-tested-by: Sebastian Sjoholm +Signed-off-by: Bjørn Mork +Signed-off-by: David S. Miller +--- + drivers/net/usb/qmi_wwan.c | 30 ++++++++++++++++++++++++++++-- + 1 file changed, 28 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c +index 9d1fce8a6e84..3ff76c6db4f6 100644 +--- a/drivers/net/usb/qmi_wwan.c ++++ b/drivers/net/usb/qmi_wwan.c +@@ -59,6 +59,10 @@ enum qmi_wwan_flags { + QMI_WWAN_FLAG_RAWIP = 1 << 0, + }; + ++enum qmi_wwan_quirks { ++ QMI_WWAN_QUIRK_DTR = 1 << 0, /* needs "set DTR" request */ ++}; ++ + static void qmi_wwan_netdev_setup(struct net_device *net) + { + struct usbnet *dev = netdev_priv(net); +@@ -411,9 +415,14 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) + * clearing out state the clients might need. + * + * MDM9x30 is the first QMI chipset with USB3 support. Abuse +- * this fact to enable the quirk. ++ * this fact to enable the quirk for all USB3 devices. ++ * ++ * There are also chipsets with the same "set DTR" requirement ++ * but without USB3 support. Devices based on these chips ++ * need a quirk flag in the device ID table. + */ +- if (le16_to_cpu(dev->udev->descriptor.bcdUSB) >= 0x0201) { ++ if (dev->driver_info->data & QMI_WWAN_QUIRK_DTR || ++ le16_to_cpu(dev->udev->descriptor.bcdUSB) >= 0x0201) { + qmi_wwan_manage_power(dev, 1); + qmi_wwan_change_dtr(dev, true); + } +@@ -526,6 +535,16 @@ static const struct driver_info qmi_wwan_info = { + .rx_fixup = qmi_wwan_rx_fixup, + }; + ++static const struct driver_info qmi_wwan_info_quirk_dtr = { ++ .description = "WWAN/QMI device", ++ .flags = FLAG_WWAN, ++ .bind = qmi_wwan_bind, ++ .unbind = qmi_wwan_unbind, ++ .manage_power = qmi_wwan_manage_power, ++ .rx_fixup = qmi_wwan_rx_fixup, ++ .data = QMI_WWAN_QUIRK_DTR, ++}; ++ + #define HUAWEI_VENDOR_ID 0x12D1 + + /* map QMI/wwan function by a fixed interface number */ +@@ -533,6 +552,11 @@ static const struct driver_info qmi_wwan_info = { + USB_DEVICE_INTERFACE_NUMBER(vend, prod, num), \ + .driver_info = (unsigned long)&qmi_wwan_info + ++/* devices requiring "set DTR" quirk */ ++#define QMI_QUIRK_SET_DTR(vend, prod, num) \ ++ USB_DEVICE_INTERFACE_NUMBER(vend, prod, num), \ ++ .driver_info = (unsigned long)&qmi_wwan_info_quirk_dtr ++ + /* Gobi 1000 QMI/wwan interface number is 3 according to qcserial */ + #define QMI_GOBI1K_DEVICE(vend, prod) \ + QMI_FIXED_INTF(vend, prod, 3) +@@ -895,6 +919,8 @@ static const struct usb_device_id products[] = { + {QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)}, /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */ + {QMI_FIXED_INTF(0x22de, 0x9061, 3)}, /* WeTelecom WPD-600N */ + {QMI_FIXED_INTF(0x1e0e, 0x9001, 5)}, /* SIMCom 7230E */ ++ {QMI_QUIRK_SET_DTR(0x2c7c, 0x0125, 4)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */ ++ {QMI_QUIRK_SET_DTR(0x2c7c, 0x0121, 4)}, /* Quectel EC21 Mini PCIe */ + + /* 4. Gobi 1000 devices */ + {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ +-- +2.7.4 +