Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'qmi_wwan_MDM9x30'

Bjørn Mork says:

====================
net: qmi_wwan: MDM9x30 support

We add new device IDs all the time, often without any testing on
actual hardware. This is usually OK as long as the device is similar
to already supported devices, using the same chipset and firmware
basis. But the Sierra Wireless MC7455 is an example of a new chipset
generation. Adding it based on assumed similarity with its ancestors
proved too optimistic.

This series adds the missing bits and pieces necessary to support LTE
Advanced modems based on the Qualcomm MDM9x30 chipset. A big thanks to
Sierra Wireless for providing MC7455 samples for testing

The most important change is the "raw-ip" support. The series also
adds a necessary control request, removes an unsupported device ID,
and adds a driver specific entry in MAINTAINERS.

A few random notes about "raw-ip":

"I rather have these all running in raw IP mode. The 802.3 framing is
utterly stupid." - Marcel Holtmann in Jan 2012 [1]

Marcel was right. I should have listened to him. What more can I say?

The 802.3 framing has provided a steady supply of firmware bugs for
many years. We've added driver workarounds for many of these, but
there are still known bugs where the workaround is so yucky that we
have refused to apply it. But all that is over now. The latest
generation Qualcomm chips no longer supports 802.3 framing at all.

I had two open questions regarding the "raw-ip" userspace API:

1) Should we continue faking an ethernet device, even if we don't use
the L2 headers on the USB link anymore?

There was a vote in favour of the "headerless" device. This is the
honest representation of the hardware/firmware interface.

2) What input should the driver base its framing on?

Snooping or directly manipulating QMI is considered out of the
question. We delegated all QMI handling to userspace from the
beginning.

We have so far required userspace to configure the firmware for
"802.3" framing, or fail if that proved impossible. This
requirement is now changed. Userspace must now inform the driver
if it negotiates "raw-ip" framing. Two alternative interfaces were
proposed:
- ethtool private driver flag, or
- sysfs file

The NetworkManager/ModemManager developers were in favour of the
sysfs alternative.

These questions (or any other you migh have :) are of course still
open. This patch set presents the solutions I currently prefer,
considering the above.

All comments are appreciated, even simple '+1' ones.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+169 -4
+23
Documentation/ABI/testing/sysfs-class-net-qmi
··· 1 + What: /sys/class/net/<iface>/qmi/raw_ip 2 + Date: Dec 2015 3 + KernelVersion: 4.4 4 + Contact: Bjørn Mork <bjorn@mork.no> 5 + Description: 6 + Boolean. Default: 'N' 7 + 8 + Set this to 'Y' to change the network device link 9 + framing from '802.3' to 'raw-ip'. 10 + 11 + The netdev will change to reflect the link framing 12 + mode. The netdev is an ordinary ethernet device in 13 + '802.3' mode, and the driver expects to exchange 14 + frames with an ethernet header over the USB link. The 15 + netdev is a headerless p-t-p device in 'raw-ip' mode, 16 + and the driver expects to echange IPv4 or IPv6 packets 17 + without any L2 header over the USB link. 18 + 19 + Userspace is in full control of firmware configuration 20 + through the delegation of the QMI protocol. Userspace 21 + is responsible for coordination of driver and firmware 22 + link framing mode, changing this setting to 'Y' if the 23 + firmware is configured for 'raw-ip' mode.
+7
MAINTAINERS
··· 11181 11181 S: Supported 11182 11182 F: drivers/usb/class/usblp.c 11183 11183 11184 + USB QMI WWAN NETWORK DRIVER 11185 + M: Bjørn Mork <bjorn@mork.no> 11186 + L: netdev@vger.kernel.org 11187 + S: Maintained 11188 + F: Documentation/ABI/testing/sysfs-class-net-qmi 11189 + F: drivers/net/usb/qmi_wwan.c 11190 + 11184 11191 USB RTL8150 DRIVER 11185 11192 M: Petko Manolov <petkan@nucleusys.com> 11186 11193 L: linux-usb@vger.kernel.org
+135 -3
drivers/net/usb/qmi_wwan.c
··· 14 14 #include <linux/netdevice.h> 15 15 #include <linux/ethtool.h> 16 16 #include <linux/etherdevice.h> 17 + #include <linux/if_arp.h> 17 18 #include <linux/mii.h> 18 19 #include <linux/usb.h> 19 20 #include <linux/usb/cdc.h> ··· 49 48 struct qmi_wwan_state { 50 49 struct usb_driver *subdriver; 51 50 atomic_t pmcount; 52 - unsigned long unused; 51 + unsigned long flags; 53 52 struct usb_interface *control; 54 53 struct usb_interface *data; 54 + }; 55 + 56 + enum qmi_wwan_flags { 57 + QMI_WWAN_FLAG_RAWIP = 1 << 0, 58 + }; 59 + 60 + static void qmi_wwan_netdev_setup(struct net_device *net) 61 + { 62 + struct usbnet *dev = netdev_priv(net); 63 + struct qmi_wwan_state *info = (void *)&dev->data; 64 + 65 + if (info->flags & QMI_WWAN_FLAG_RAWIP) { 66 + net->header_ops = NULL; /* No header */ 67 + net->type = ARPHRD_NONE; 68 + net->hard_header_len = 0; 69 + net->addr_len = 0; 70 + net->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; 71 + netdev_dbg(net, "mode: raw IP\n"); 72 + } else if (!net->header_ops) { /* don't bother if already set */ 73 + ether_setup(net); 74 + netdev_dbg(net, "mode: Ethernet\n"); 75 + } 76 + 77 + /* recalculate buffers after changing hard_header_len */ 78 + usbnet_change_mtu(net, net->mtu); 79 + } 80 + 81 + static ssize_t raw_ip_show(struct device *d, struct device_attribute *attr, char *buf) 82 + { 83 + struct usbnet *dev = netdev_priv(to_net_dev(d)); 84 + struct qmi_wwan_state *info = (void *)&dev->data; 85 + 86 + return sprintf(buf, "%c\n", info->flags & QMI_WWAN_FLAG_RAWIP ? 'Y' : 'N'); 87 + } 88 + 89 + static ssize_t raw_ip_store(struct device *d, struct device_attribute *attr, const char *buf, size_t len) 90 + { 91 + struct usbnet *dev = netdev_priv(to_net_dev(d)); 92 + struct qmi_wwan_state *info = (void *)&dev->data; 93 + bool enable; 94 + int err; 95 + 96 + if (strtobool(buf, &enable)) 97 + return -EINVAL; 98 + 99 + /* no change? */ 100 + if (enable == (info->flags & QMI_WWAN_FLAG_RAWIP)) 101 + return len; 102 + 103 + /* we don't want to modify a running netdev */ 104 + if (netif_running(dev->net)) { 105 + netdev_err(dev->net, "Cannot change a running device\n"); 106 + return -EBUSY; 107 + } 108 + 109 + /* let other drivers deny the change */ 110 + err = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE, dev->net); 111 + err = notifier_to_errno(err); 112 + if (err) { 113 + netdev_err(dev->net, "Type change was refused\n"); 114 + return err; 115 + } 116 + 117 + if (enable) 118 + info->flags |= QMI_WWAN_FLAG_RAWIP; 119 + else 120 + info->flags &= ~QMI_WWAN_FLAG_RAWIP; 121 + qmi_wwan_netdev_setup(dev->net); 122 + call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE, dev->net); 123 + return len; 124 + } 125 + 126 + static DEVICE_ATTR_RW(raw_ip); 127 + 128 + static struct attribute *qmi_wwan_sysfs_attrs[] = { 129 + &dev_attr_raw_ip.attr, 130 + NULL, 131 + }; 132 + 133 + static struct attribute_group qmi_wwan_sysfs_attr_group = { 134 + .name = "qmi", 135 + .attrs = qmi_wwan_sysfs_attrs, 55 136 }; 56 137 57 138 /* default ethernet address used by the modem */ ··· 163 80 */ 164 81 static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb) 165 82 { 83 + struct qmi_wwan_state *info = (void *)&dev->data; 84 + bool rawip = info->flags & QMI_WWAN_FLAG_RAWIP; 166 85 __be16 proto; 167 86 168 87 /* This check is no longer done by usbnet */ ··· 179 94 proto = htons(ETH_P_IPV6); 180 95 break; 181 96 case 0x00: 97 + if (rawip) 98 + return 0; 182 99 if (is_multicast_ether_addr(skb->data)) 183 100 return 1; 184 101 /* possibly bogus destination - rewrite just in case */ 185 102 skb_reset_mac_header(skb); 186 103 goto fix_dest; 187 104 default: 105 + if (rawip) 106 + return 0; 188 107 /* pass along other packets without modifications */ 189 108 return 1; 190 109 } 110 + if (rawip) { 111 + skb->dev = dev->net; /* normally set by eth_type_trans */ 112 + skb->protocol = proto; 113 + return 1; 114 + } 115 + 191 116 if (skb_headroom(skb) < ETH_HLEN) 192 117 return 0; 193 118 skb_push(skb, ETH_HLEN); ··· 318 223 return rv; 319 224 } 320 225 226 + /* Send CDC SetControlLineState request, setting or clearing the DTR. 227 + * "Required for Autoconnect and 9x30 to wake up" according to the 228 + * GobiNet driver. The requirement has been verified on an MDM9230 229 + * based Sierra Wireless MC7455 230 + */ 231 + static int qmi_wwan_change_dtr(struct usbnet *dev, bool on) 232 + { 233 + u8 intf = dev->intf->cur_altsetting->desc.bInterfaceNumber; 234 + 235 + return usbnet_write_cmd(dev, USB_CDC_REQ_SET_CONTROL_LINE_STATE, 236 + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 237 + on ? 0x01 : 0x00, intf, NULL, 0); 238 + } 239 + 321 240 static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) 322 241 { 323 242 int status = -1; ··· 389 280 usb_driver_release_interface(driver, info->data); 390 281 } 391 282 283 + /* disabling remote wakeup on MDM9x30 devices has the same 284 + * effect as clearing DTR. The device will not respond to QMI 285 + * requests until we set DTR again. This is similar to a 286 + * QMI_CTL SYNC request, clearing a lot of firmware state 287 + * including the client ID allocations. 288 + * 289 + * Our usage model allows a session to span multiple 290 + * open/close events, so we must prevent the firmware from 291 + * clearing out state the clients might need. 292 + * 293 + * MDM9x30 is the first QMI chipset with USB3 support. Abuse 294 + * this fact to enable the quirk. 295 + */ 296 + if (le16_to_cpu(dev->udev->descriptor.bcdUSB) >= 0x0201) { 297 + qmi_wwan_manage_power(dev, 1); 298 + qmi_wwan_change_dtr(dev, true); 299 + } 300 + 392 301 /* Never use the same address on both ends of the link, even if the 393 302 * buggy firmware told us to. Or, if device is assigned the well-known 394 303 * buggy firmware MAC address, replace it with a random address, ··· 421 294 dev->net->dev_addr[0] &= 0xbf; /* clear "IP" bit */ 422 295 } 423 296 dev->net->netdev_ops = &qmi_wwan_netdev_ops; 297 + dev->net->sysfs_groups[0] = &qmi_wwan_sysfs_attr_group; 424 298 err: 425 299 return status; 426 300 } ··· 434 306 435 307 if (info->subdriver && info->subdriver->disconnect) 436 308 info->subdriver->disconnect(info->control); 309 + 310 + /* disable MDM9x30 quirk */ 311 + if (le16_to_cpu(dev->udev->descriptor.bcdUSB) >= 0x0201) { 312 + qmi_wwan_change_dtr(dev, false); 313 + qmi_wwan_manage_power(dev, 0); 314 + } 437 315 438 316 /* allow user to unbind using either control or data */ 439 317 if (intf == info->control) ··· 849 715 {QMI_FIXED_INTF(0x1199, 0x9056, 8)}, /* Sierra Wireless Modem */ 850 716 {QMI_FIXED_INTF(0x1199, 0x9057, 8)}, 851 717 {QMI_FIXED_INTF(0x1199, 0x9061, 8)}, /* Sierra Wireless Modem */ 852 - {QMI_FIXED_INTF(0x1199, 0x9070, 8)}, /* Sierra Wireless MC74xx/EM74xx */ 853 - {QMI_FIXED_INTF(0x1199, 0x9070, 10)}, /* Sierra Wireless MC74xx/EM74xx */ 854 718 {QMI_FIXED_INTF(0x1199, 0x9071, 8)}, /* Sierra Wireless MC74xx/EM74xx */ 855 719 {QMI_FIXED_INTF(0x1199, 0x9071, 10)}, /* Sierra Wireless MC74xx/EM74xx */ 856 720 {QMI_FIXED_INTF(0x1bbb, 0x011e, 4)}, /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */
+4 -1
drivers/net/usb/usbnet.c
··· 324 324 return; 325 325 } 326 326 327 - skb->protocol = eth_type_trans (skb, dev->net); 327 + /* only update if unset to allow minidriver rx_fixup override */ 328 + if (skb->protocol == 0) 329 + skb->protocol = eth_type_trans (skb, dev->net); 330 + 328 331 dev->net->stats.rx_packets++; 329 332 dev->net->stats.rx_bytes += skb->len; 330 333