diff options
Diffstat (limited to 'drivers/net/usb')
-rw-r--r-- | drivers/net/usb/asix.c | 4 | ||||
-rw-r--r-- | drivers/net/usb/cdc_ether.c | 86 | ||||
-rw-r--r-- | drivers/net/usb/qmi_wwan.c | 69 | ||||
-rw-r--r-- | drivers/net/usb/rndis_host.c | 83 | ||||
-rw-r--r-- | drivers/net/usb/smsc75xx.c | 58 | ||||
-rw-r--r-- | drivers/net/usb/smsc75xx.h | 1 | ||||
-rw-r--r-- | drivers/net/usb/smsc95xx.c | 3 | ||||
-rw-r--r-- | drivers/net/usb/usbnet.c | 60 |
8 files changed, 281 insertions, 83 deletions
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index 5ee032cafade..42b5151aa78a 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -355,7 +355,7 @@ static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, u32 packet_len; u32 padbytes = 0xffff0000; - padlen = ((skb->len + 4) % 512) ? 0 : 4; + padlen = ((skb->len + 4) & (dev->maxpacket - 1)) ? 0 : 4; if ((!skb_cloned(skb)) && ((headroom + tailroom) >= (4 + padlen))) { @@ -377,7 +377,7 @@ static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, cpu_to_le32s(&packet_len); skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); - if ((skb->len % 512) == 0) { + if (padlen) { cpu_to_le32s(&padbytes); memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); skb_put(skb, sizeof(padbytes)); diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 90a30026a931..fffee6aee8bb 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -83,6 +83,7 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) struct cdc_state *info = (void *) &dev->data; int status; int rndis; + bool android_rndis_quirk = false; struct usb_driver *driver = driver_of(intf); struct usb_cdc_mdlm_desc *desc = NULL; struct usb_cdc_mdlm_detail_desc *detail = NULL; @@ -195,6 +196,11 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) info->control, info->u->bSlaveInterface0, info->data); + /* fall back to hard-wiring for RNDIS */ + if (rndis) { + android_rndis_quirk = true; + goto next_desc; + } goto bad_desc; } if (info->control != intf) { @@ -271,11 +277,15 @@ next_desc: /* Microsoft ActiveSync based and some regular RNDIS devices lack the * CDC descriptors, so we'll hard-wire the interfaces and not check * for descriptors. + * + * Some Android RNDIS devices have a CDC Union descriptor pointing + * to non-existing interfaces. Ignore that and attempt the same + * hard-wired 0 and 1 interfaces. */ - if (rndis && !info->u) { + if (rndis && (!info->u || android_rndis_quirk)) { info->control = usb_ifnum_to_if(dev->udev, 0); info->data = usb_ifnum_to_if(dev->udev, 1); - if (!info->control || !info->data) { + if (!info->control || !info->data || info->control != intf) { dev_dbg(&intf->dev, "rndis: master #0/%p slave #1/%p\n", info->control, @@ -475,6 +485,8 @@ static const struct driver_info wwan_info = { /*-------------------------------------------------------------------------*/ #define HUAWEI_VENDOR_ID 0x12D1 +#define NOVATEL_VENDOR_ID 0x1410 +#define ZTE_VENDOR_ID 0x19D2 static const struct usb_device_id products [] = { /* @@ -592,6 +604,76 @@ static const struct usb_device_id products [] = { * because of bugs/quirks in a given product (like Zaurus, above). */ { + /* Novatel USB551L */ + /* This match must come *before* the generic CDC-ETHER match so that + * we get FLAG_WWAN set on the device, since it's descriptors are + * generic CDC-ETHER. + */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_PRODUCT + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = NOVATEL_VENDOR_ID, + .idProduct = 0xB001, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bInterfaceProtocol = USB_CDC_PROTO_NONE, + .driver_info = (unsigned long)&wwan_info, +}, { + /* ZTE (Vodafone) K3805-Z */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_PRODUCT + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = ZTE_VENDOR_ID, + .idProduct = 0x1003, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bInterfaceProtocol = USB_CDC_PROTO_NONE, + .driver_info = (unsigned long)&wwan_info, +}, { + /* ZTE (Vodafone) K3806-Z */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_PRODUCT + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = ZTE_VENDOR_ID, + .idProduct = 0x1015, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bInterfaceProtocol = USB_CDC_PROTO_NONE, + .driver_info = (unsigned long)&wwan_info, +}, { + /* ZTE (Vodafone) K4510-Z */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_PRODUCT + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = ZTE_VENDOR_ID, + .idProduct = 0x1173, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bInterfaceProtocol = USB_CDC_PROTO_NONE, + .driver_info = (unsigned long)&wwan_info, +}, { + /* ZTE (Vodafone) K3770-Z */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_PRODUCT + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = ZTE_VENDOR_ID, + .idProduct = 0x1177, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bInterfaceProtocol = USB_CDC_PROTO_NONE, + .driver_info = (unsigned long)&wwan_info, +}, { + /* ZTE (Vodafone) K3772-Z */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_PRODUCT + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = ZTE_VENDOR_ID, + .idProduct = 0x1181, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bInterfaceProtocol = USB_CDC_PROTO_NONE, + .driver_info = (unsigned long)&wwan_info, +}, { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), .driver_info = (unsigned long) &cdc_info, diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 552d24bf862e..63cfd0b2c31a 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -356,15 +356,45 @@ static const struct driver_info qmi_wwan_gobi = { }; /* ZTE suck at making USB descriptors */ +static const struct driver_info qmi_wwan_force_int1 = { + .description = "Qualcomm WWAN/QMI device", + .flags = FLAG_WWAN, + .bind = qmi_wwan_bind_shared, + .unbind = qmi_wwan_unbind_shared, + .manage_power = qmi_wwan_manage_power, + .data = BIT(1), /* interface whitelist bitmap */ +}; + static const struct driver_info qmi_wwan_force_int4 = { - .description = "Qualcomm Gobi wwan/QMI device", + .description = "Qualcomm WWAN/QMI device", .flags = FLAG_WWAN, - .bind = qmi_wwan_bind_gobi, + .bind = qmi_wwan_bind_shared, .unbind = qmi_wwan_unbind_shared, .manage_power = qmi_wwan_manage_power, .data = BIT(4), /* interface whitelist bitmap */ }; +/* Sierra Wireless provide equally useless interface descriptors + * Devices in QMI mode can be switched between two different + * configurations: + * a) USB interface #8 is QMI/wwan + * b) USB interfaces #8, #19 and #20 are QMI/wwan + * + * Both configurations provide a number of other interfaces (serial++), + * some of which have the same endpoint configuration as we expect, so + * a whitelist or blacklist is necessary. + * + * FIXME: The below whitelist should include BIT(20). It does not + * because I cannot get it to work... + */ +static const struct driver_info qmi_wwan_sierra = { + .description = "Sierra Wireless wwan/QMI device", + .flags = FLAG_WWAN, + .bind = qmi_wwan_bind_gobi, + .unbind = qmi_wwan_unbind_shared, + .manage_power = qmi_wwan_manage_power, + .data = BIT(8) | BIT(19), /* interface whitelist bitmap */ +}; #define HUAWEI_VENDOR_ID 0x12D1 #define QMI_GOBI_DEVICE(vend, prod) \ @@ -380,6 +410,14 @@ static const struct usb_device_id products[] = { .bInterfaceProtocol = 8, /* NOTE: This is the *slave* interface of the CDC Union! */ .driver_info = (unsigned long)&qmi_wwan_info, }, + { /* Vodafone/Huawei K5005 (12d1:14c8) and similar modems */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = HUAWEI_VENDOR_ID, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 56, /* NOTE: This is the *slave* interface of the CDC Union! */ + .driver_info = (unsigned long)&qmi_wwan_info, + }, { /* Huawei E392, E398 and possibly others in "Windows mode" * using a combined control and data interface without any CDC * functional descriptors @@ -409,6 +447,15 @@ static const struct usb_device_id products[] = { .bInterfaceProtocol = 0xff, .driver_info = (unsigned long)&qmi_wwan_force_int4, }, + { /* ZTE (Vodafone) K3520-Z */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x19d2, + .idProduct = 0x0055, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .driver_info = (unsigned long)&qmi_wwan_force_int1, + }, { /* ZTE (Vodafone) K3565-Z */ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x19d2, @@ -436,6 +483,15 @@ static const struct usb_device_id products[] = { .bInterfaceProtocol = 0xff, .driver_info = (unsigned long)&qmi_wwan_force_int4, }, + { /* ZTE (Vodafone) K3765-Z */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x19d2, + .idProduct = 0x2002, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .driver_info = (unsigned long)&qmi_wwan_force_int4, + }, { /* ZTE (Vodafone) K4505-Z */ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x19d2, @@ -445,6 +501,15 @@ static const struct usb_device_id products[] = { .bInterfaceProtocol = 0xff, .driver_info = (unsigned long)&qmi_wwan_force_int4, }, + { /* Sierra Wireless MC77xx in QMI mode */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x1199, + .idProduct = 0x68a2, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .driver_info = (unsigned long)&qmi_wwan_sierra, + }, {QMI_GOBI_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ {QMI_GOBI_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ {QMI_GOBI_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Mobile Broadband Module */ diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index c8f1b5b3aff3..0d746b3fdef1 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -77,7 +77,9 @@ static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg, if (dev->driver_info->indication) { dev->driver_info->indication(dev, msg, buflen); } else { - switch (msg->status) { + u32 status = le32_to_cpu(msg->status); + + switch (status) { case RNDIS_STATUS_MEDIA_CONNECT: dev_info(udev, "rndis media connect\n"); break; @@ -85,8 +87,7 @@ static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg, dev_info(udev, "rndis media disconnect\n"); break; default: - dev_info(udev, "rndis indication: 0x%08x\n", - le32_to_cpu(msg->status)); + dev_info(udev, "rndis indication: 0x%08x\n", status); } } } @@ -109,16 +110,17 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) int retval; int partial; unsigned count; - __le32 rsp; - u32 xid = 0, msg_len, request_id; + u32 xid = 0, msg_len, request_id, msg_type, rsp, + status; /* REVISIT when this gets called from contexts other than probe() or * disconnect(): either serialize, or dispatch responses on xid */ + msg_type = le32_to_cpu(buf->msg_type); + /* Issue the request; xid is unique, don't bother byteswapping it */ - if (likely(buf->msg_type != RNDIS_MSG_HALT && - buf->msg_type != RNDIS_MSG_RESET)) { + if (likely(msg_type != RNDIS_MSG_HALT && msg_type != RNDIS_MSG_RESET)) { xid = dev->xid++; if (!xid) xid = dev->xid++; @@ -149,7 +151,7 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) } /* Poll the control channel; the request probably completed immediately */ - rsp = buf->msg_type | RNDIS_MSG_COMPLETION; + rsp = le32_to_cpu(buf->msg_type) | RNDIS_MSG_COMPLETION; for (count = 0; count < 10; count++) { memset(buf, 0, CONTROL_BUFFER_SIZE); retval = usb_control_msg(dev->udev, @@ -160,35 +162,36 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) buf, buflen, RNDIS_CONTROL_TIMEOUT_MS); if (likely(retval >= 8)) { + msg_type = le32_to_cpu(buf->msg_type); msg_len = le32_to_cpu(buf->msg_len); + status = le32_to_cpu(buf->status); request_id = (__force u32) buf->request_id; - if (likely(buf->msg_type == rsp)) { + if (likely(msg_type == rsp)) { if (likely(request_id == xid)) { if (unlikely(rsp == RNDIS_MSG_RESET_C)) return 0; - if (likely(RNDIS_STATUS_SUCCESS - == buf->status)) + if (likely(RNDIS_STATUS_SUCCESS == + status)) return 0; dev_dbg(&info->control->dev, "rndis reply status %08x\n", - le32_to_cpu(buf->status)); + status); return -EL3RST; } dev_dbg(&info->control->dev, "rndis reply id %d expected %d\n", request_id, xid); /* then likely retry */ - } else switch (buf->msg_type) { - case RNDIS_MSG_INDICATE: /* fault/event */ + } else switch (msg_type) { + case RNDIS_MSG_INDICATE: /* fault/event */ rndis_msg_indicate(dev, (void *)buf, buflen); - break; - case RNDIS_MSG_KEEPALIVE: { /* ping */ + case RNDIS_MSG_KEEPALIVE: { /* ping */ struct rndis_keepalive_c *msg = (void *)buf; - msg->msg_type = RNDIS_MSG_KEEPALIVE_C; + msg->msg_type = cpu_to_le32(RNDIS_MSG_KEEPALIVE_C); msg->msg_len = cpu_to_le32(sizeof *msg); - msg->status = RNDIS_STATUS_SUCCESS; + msg->status = cpu_to_le32(RNDIS_STATUS_SUCCESS); retval = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), USB_CDC_SEND_ENCAPSULATED_COMMAND, @@ -236,7 +239,7 @@ EXPORT_SYMBOL_GPL(rndis_command); * ActiveSync 4.1 Windows driver. */ static int rndis_query(struct usbnet *dev, struct usb_interface *intf, - void *buf, __le32 oid, u32 in_len, + void *buf, u32 oid, u32 in_len, void **reply, int *reply_len) { int retval; @@ -251,9 +254,9 @@ static int rndis_query(struct usbnet *dev, struct usb_interface *intf, u.buf = buf; memset(u.get, 0, sizeof *u.get + in_len); - u.get->msg_type = RNDIS_MSG_QUERY; + u.get->msg_type = cpu_to_le32(RNDIS_MSG_QUERY); u.get->msg_len = cpu_to_le32(sizeof *u.get + in_len); - u.get->oid = oid; + u.get->oid = cpu_to_le32(oid); u.get->len = cpu_to_le32(in_len); u.get->offset = cpu_to_le32(20); @@ -324,7 +327,7 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) if (retval < 0) goto fail; - u.init->msg_type = RNDIS_MSG_INIT; + u.init->msg_type = cpu_to_le32(RNDIS_MSG_INIT); u.init->msg_len = cpu_to_le32(sizeof *u.init); u.init->major_version = cpu_to_le32(1); u.init->minor_version = cpu_to_le32(0); @@ -395,22 +398,23 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) /* Check physical medium */ phym = NULL; reply_len = sizeof *phym; - retval = rndis_query(dev, intf, u.buf, OID_GEN_PHYSICAL_MEDIUM, - 0, (void **) &phym, &reply_len); + retval = rndis_query(dev, intf, u.buf, + RNDIS_OID_GEN_PHYSICAL_MEDIUM, + 0, (void **) &phym, &reply_len); if (retval != 0 || !phym) { /* OID is optional so don't fail here. */ - phym_unspec = RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED; + phym_unspec = cpu_to_le32(RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED); phym = &phym_unspec; } if ((flags & FLAG_RNDIS_PHYM_WIRELESS) && - *phym != RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) { + le32_to_cpup(phym) != RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) { netif_dbg(dev, probe, dev->net, "driver requires wireless physical medium, but device is not\n"); retval = -ENODEV; goto halt_fail_and_release; } if ((flags & FLAG_RNDIS_PHYM_NOT_WIRELESS) && - *phym == RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) { + le32_to_cpup(phym) == RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) { netif_dbg(dev, probe, dev->net, "driver requires non-wireless physical medium, but device is wireless.\n"); retval = -ENODEV; @@ -419,8 +423,9 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) /* Get designated host ethernet address */ reply_len = ETH_ALEN; - retval = rndis_query(dev, intf, u.buf, OID_802_3_PERMANENT_ADDRESS, - 48, (void **) &bp, &reply_len); + retval = rndis_query(dev, intf, u.buf, + RNDIS_OID_802_3_PERMANENT_ADDRESS, + 48, (void **) &bp, &reply_len); if (unlikely(retval< 0)) { dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval); goto halt_fail_and_release; @@ -430,12 +435,12 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) /* set a nonzero filter to enable data transfers */ memset(u.set, 0, sizeof *u.set); - u.set->msg_type = RNDIS_MSG_SET; + u.set->msg_type = cpu_to_le32(RNDIS_MSG_SET); u.set->msg_len = cpu_to_le32(4 + sizeof *u.set); - u.set->oid = OID_GEN_CURRENT_PACKET_FILTER; + u.set->oid = cpu_to_le32(RNDIS_OID_GEN_CURRENT_PACKET_FILTER); u.set->len = cpu_to_le32(4); u.set->offset = cpu_to_le32((sizeof *u.set) - 8); - *(__le32 *)(u.buf + sizeof *u.set) = RNDIS_DEFAULT_FILTER; + *(__le32 *)(u.buf + sizeof *u.set) = cpu_to_le32(RNDIS_DEFAULT_FILTER); retval = rndis_command(dev, u.header, CONTROL_BUFFER_SIZE); if (unlikely(retval < 0)) { @@ -450,7 +455,7 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) halt_fail_and_release: memset(u.halt, 0, sizeof *u.halt); - u.halt->msg_type = RNDIS_MSG_HALT; + u.halt->msg_type = cpu_to_le32(RNDIS_MSG_HALT); u.halt->msg_len = cpu_to_le32(sizeof *u.halt); (void) rndis_command(dev, (void *)u.halt, CONTROL_BUFFER_SIZE); fail_and_release: @@ -475,7 +480,7 @@ void rndis_unbind(struct usbnet *dev, struct usb_interface *intf) /* try to clear any rndis state/activity (no i/o from stack!) */ halt = kzalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL); if (halt) { - halt->msg_type = RNDIS_MSG_HALT; + halt->msg_type = cpu_to_le32(RNDIS_MSG_HALT); halt->msg_len = cpu_to_le32(sizeof *halt); (void) rndis_command(dev, (void *)halt, CONTROL_BUFFER_SIZE); kfree(halt); @@ -494,16 +499,16 @@ int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb) while (likely(skb->len)) { struct rndis_data_hdr *hdr = (void *)skb->data; struct sk_buff *skb2; - u32 msg_len, data_offset, data_len; + u32 msg_type, msg_len, data_offset, data_len; + msg_type = le32_to_cpu(hdr->msg_type); msg_len = le32_to_cpu(hdr->msg_len); data_offset = le32_to_cpu(hdr->data_offset); data_len = le32_to_cpu(hdr->data_len); /* don't choke if we see oob, per-packet data, etc */ - if (unlikely(hdr->msg_type != RNDIS_MSG_PACKET || - skb->len < msg_len || - (data_offset + data_len + 8) > msg_len)) { + if (unlikely(msg_type != RNDIS_MSG_PACKET || skb->len < msg_len + || (data_offset + data_len + 8) > msg_len)) { dev->net->stats.rx_frame_errors++; netdev_dbg(dev->net, "bad rndis message %d/%d/%d/%d, len %d\n", le32_to_cpu(hdr->msg_type), @@ -569,7 +574,7 @@ rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) fill: hdr = (void *) __skb_push(skb, sizeof *hdr); memset(hdr, 0, sizeof *hdr); - hdr->msg_type = RNDIS_MSG_PACKET; + hdr->msg_type = cpu_to_le32(RNDIS_MSG_PACKET); hdr->msg_len = cpu_to_le32(skb->len); hdr->data_offset = cpu_to_le32(sizeof(*hdr) - 8); hdr->data_len = cpu_to_le32(len); diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 187d01ccb973..fb1a087b101d 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -98,7 +98,7 @@ static int __must_check smsc75xx_read_reg(struct usbnet *dev, u32 index, if (unlikely(ret < 0)) netdev_warn(dev->net, - "Failed to read register index 0x%08x", index); + "Failed to read reg index 0x%08x: %d", index, ret); le32_to_cpus(buf); *data = *buf; @@ -128,7 +128,7 @@ static int __must_check smsc75xx_write_reg(struct usbnet *dev, u32 index, if (unlikely(ret < 0)) netdev_warn(dev->net, - "Failed to write register index 0x%08x", index); + "Failed to write reg index 0x%08x: %d", index, ret); kfree(buf); @@ -171,7 +171,7 @@ static int smsc75xx_mdio_read(struct net_device *netdev, int phy_id, int idx) idx &= dev->mii.reg_num_mask; addr = ((phy_id << MII_ACCESS_PHY_ADDR_SHIFT) & MII_ACCESS_PHY_ADDR) | ((idx << MII_ACCESS_REG_ADDR_SHIFT) & MII_ACCESS_REG_ADDR) - | MII_ACCESS_READ; + | MII_ACCESS_READ | MII_ACCESS_BUSY; ret = smsc75xx_write_reg(dev, MII_ACCESS, addr); check_warn_goto_done(ret, "Error writing MII_ACCESS"); @@ -210,7 +210,7 @@ static void smsc75xx_mdio_write(struct net_device *netdev, int phy_id, int idx, idx &= dev->mii.reg_num_mask; addr = ((phy_id << MII_ACCESS_PHY_ADDR_SHIFT) & MII_ACCESS_PHY_ADDR) | ((idx << MII_ACCESS_REG_ADDR_SHIFT) & MII_ACCESS_REG_ADDR) - | MII_ACCESS_WRITE; + | MII_ACCESS_WRITE | MII_ACCESS_BUSY; ret = smsc75xx_write_reg(dev, MII_ACCESS, addr); check_warn_goto_done(ret, "Error writing MII_ACCESS"); @@ -508,9 +508,9 @@ static int smsc75xx_link_reset(struct usbnet *dev) u16 lcladv, rmtadv; int ret; - /* clear interrupt status */ - ret = smsc75xx_mdio_read(dev->net, mii->phy_id, PHY_INT_SRC); - check_warn_return(ret, "Error reading PHY_INT_SRC"); + /* write to clear phy interrupt status */ + smsc75xx_mdio_write(dev->net, mii->phy_id, PHY_INT_SRC, + PHY_INT_SRC_CLEAR_ALL); ret = smsc75xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL); check_warn_return(ret, "Error writing INT_STS"); @@ -643,7 +643,7 @@ static int smsc75xx_set_mac_address(struct usbnet *dev) static int smsc75xx_phy_initialize(struct usbnet *dev) { - int bmcr, timeout = 0; + int bmcr, ret, timeout = 0; /* Initialize MII structure */ dev->mii.dev = dev->net; @@ -651,6 +651,7 @@ static int smsc75xx_phy_initialize(struct usbnet *dev) dev->mii.mdio_write = smsc75xx_mdio_write; dev->mii.phy_id_mask = 0x1f; dev->mii.reg_num_mask = 0x1f; + dev->mii.supports_gmii = 1; dev->mii.phy_id = SMSC75XX_INTERNAL_PHY_ID; /* reset phy and wait for reset to complete */ @@ -661,7 +662,7 @@ static int smsc75xx_phy_initialize(struct usbnet *dev) bmcr = smsc75xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR); check_warn_return(bmcr, "Error reading MII_BMCR"); timeout++; - } while ((bmcr & MII_BMCR) && (timeout < 100)); + } while ((bmcr & BMCR_RESET) && (timeout < 100)); if (timeout >= 100) { netdev_warn(dev->net, "timeout on PHY Reset"); @@ -671,10 +672,13 @@ static int smsc75xx_phy_initialize(struct usbnet *dev) smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); + smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000, + ADVERTISE_1000FULL); - /* read to clear */ - smsc75xx_mdio_read(dev->net, dev->mii.phy_id, PHY_INT_SRC); - check_warn_return(bmcr, "Error reading PHY_INT_SRC"); + /* read and write to clear phy interrupt status */ + ret = smsc75xx_mdio_read(dev->net, dev->mii.phy_id, PHY_INT_SRC); + check_warn_return(ret, "Error reading PHY_INT_SRC"); + smsc75xx_mdio_write(dev->net, dev->mii.phy_id, PHY_INT_SRC, 0xffff); smsc75xx_mdio_write(dev->net, dev->mii.phy_id, PHY_INT_MASK, PHY_INT_MASK_DEFAULT); @@ -899,15 +903,20 @@ static int smsc75xx_reset(struct usbnet *dev) netif_dbg(dev, ifup, dev->net, "ID_REV = 0x%08x", buf); - /* Configure GPIO pins as LED outputs */ - ret = smsc75xx_read_reg(dev, LED_GPIO_CFG, &buf); - check_warn_return(ret, "Failed to read LED_GPIO_CFG: %d", ret); + ret = smsc75xx_read_reg(dev, E2P_CMD, &buf); + check_warn_return(ret, "Failed to read E2P_CMD: %d", ret); + + /* only set default GPIO/LED settings if no EEPROM is detected */ + if (!(buf & E2P_CMD_LOADED)) { + ret = smsc75xx_read_reg(dev, LED_GPIO_CFG, &buf); + check_warn_return(ret, "Failed to read LED_GPIO_CFG: %d", ret); - buf &= ~(LED_GPIO_CFG_LED2_FUN_SEL | LED_GPIO_CFG_LED10_FUN_SEL); - buf |= LED_GPIO_CFG_LEDGPIO_EN | LED_GPIO_CFG_LED2_FUN_SEL; + buf &= ~(LED_GPIO_CFG_LED2_FUN_SEL | LED_GPIO_CFG_LED10_FUN_SEL); + buf |= LED_GPIO_CFG_LEDGPIO_EN | LED_GPIO_CFG_LED2_FUN_SEL; - ret = smsc75xx_write_reg(dev, LED_GPIO_CFG, buf); - check_warn_return(ret, "Failed to write LED_GPIO_CFG: %d", ret); + ret = smsc75xx_write_reg(dev, LED_GPIO_CFG, buf); + check_warn_return(ret, "Failed to write LED_GPIO_CFG: %d", ret); + } ret = smsc75xx_write_reg(dev, FLOW, 0); check_warn_return(ret, "Failed to write FLOW: %d", ret); @@ -946,6 +955,14 @@ static int smsc75xx_reset(struct usbnet *dev) ret = smsc75xx_write_reg(dev, INT_EP_CTL, buf); check_warn_return(ret, "Failed to write INT_EP_CTL: %d", ret); + /* allow mac to detect speed and duplex from phy */ + ret = smsc75xx_read_reg(dev, MAC_CR, &buf); + check_warn_return(ret, "Failed to read MAC_CR: %d", ret); + + buf |= (MAC_CR_ADD | MAC_CR_ASD); + ret = smsc75xx_write_reg(dev, MAC_CR, buf); + check_warn_return(ret, "Failed to write MAC_CR: %d", ret); + ret = smsc75xx_read_reg(dev, MAC_TX, &buf); check_warn_return(ret, "Failed to read MAC_TX: %d", ret); @@ -1051,6 +1068,7 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf) dev->net->ethtool_ops = &smsc75xx_ethtool_ops; dev->net->flags |= IFF_MULTICAST; dev->net->hard_header_len += SMSC75XX_TX_OVERHEAD; + dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; return 0; } @@ -1211,7 +1229,7 @@ static const struct driver_info smsc75xx_info = { .rx_fixup = smsc75xx_rx_fixup, .tx_fixup = smsc75xx_tx_fixup, .status = smsc75xx_status, - .flags = FLAG_ETHER | FLAG_SEND_ZLP, + .flags = FLAG_ETHER | FLAG_SEND_ZLP | FLAG_LINK_INTR, }; static const struct usb_device_id products[] = { diff --git a/drivers/net/usb/smsc75xx.h b/drivers/net/usb/smsc75xx.h index 16e98c778344..67eba39e6ee2 100644 --- a/drivers/net/usb/smsc75xx.h +++ b/drivers/net/usb/smsc75xx.h @@ -388,6 +388,7 @@ #define PHY_INT_SRC_ANEG_COMP ((u16)0x0040) #define PHY_INT_SRC_REMOTE_FAULT ((u16)0x0020) #define PHY_INT_SRC_LINK_DOWN ((u16)0x0010) +#define PHY_INT_SRC_CLEAR_ALL ((u16)0xffff) #define PHY_INT_MASK (30) #define PHY_INT_MASK_ENERGY_ON ((u16)0x0080) diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 5f19f84d3494..94ae66999f59 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -1017,6 +1017,7 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) dev->net->ethtool_ops = &smsc95xx_ethtool_ops; dev->net->flags |= IFF_MULTICAST; dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD_CSUM; + dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; return 0; } @@ -1191,7 +1192,7 @@ static const struct driver_info smsc95xx_info = { .rx_fixup = smsc95xx_rx_fixup, .tx_fixup = smsc95xx_tx_fixup, .status = smsc95xx_status, - .flags = FLAG_ETHER | FLAG_SEND_ZLP, + .flags = FLAG_ETHER | FLAG_SEND_ZLP | FLAG_LINK_INTR, }; static const struct usb_device_id products[] = { diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index b7b3f5b0d406..9f58330f1312 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -210,6 +210,7 @@ static int init_status (struct usbnet *dev, struct usb_interface *intf) } else { usb_fill_int_urb(dev->interrupt, dev->udev, pipe, buf, maxp, intr_complete, dev, period); + dev->interrupt->transfer_flags |= URB_FREE_BUFFER; dev_dbg(&intf->dev, "status ep%din, %d bytes period %d\n", usb_pipeendpoint(pipe), maxp, period); @@ -281,17 +282,32 @@ int usbnet_change_mtu (struct net_device *net, int new_mtu) } EXPORT_SYMBOL_GPL(usbnet_change_mtu); +/* The caller must hold list->lock */ +static void __usbnet_queue_skb(struct sk_buff_head *list, + struct sk_buff *newsk, enum skb_state state) +{ + struct skb_data *entry = (struct skb_data *) newsk->cb; + + __skb_queue_tail(list, newsk); + entry->state = state; +} + /*-------------------------------------------------------------------------*/ /* some LK 2.4 HCDs oopsed if we freed or resubmitted urbs from * completion callbacks. 2.5 should have fixed those bugs... */ -static void defer_bh(struct usbnet *dev, struct sk_buff *skb, struct sk_buff_head *list) +static enum skb_state defer_bh(struct usbnet *dev, struct sk_buff *skb, + struct sk_buff_head *list, enum skb_state state) { unsigned long flags; + enum skb_state old_state; + struct skb_data *entry = (struct skb_data *) skb->cb; spin_lock_irqsave(&list->lock, flags); + old_state = entry->state; + entry->state = state; __skb_unlink(skb, list); spin_unlock(&list->lock); spin_lock(&dev->done.lock); @@ -299,6 +315,7 @@ static void defer_bh(struct usbnet *dev, struct sk_buff *skb, struct sk_buff_hea if (dev->done.qlen == 1) tasklet_schedule(&dev->bh); spin_unlock_irqrestore(&dev->done.lock, flags); + return old_state; } /* some work can't be done in tasklets, so we use keventd @@ -339,7 +356,6 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) entry = (struct skb_data *) skb->cb; entry->urb = urb; entry->dev = dev; - entry->state = rx_start; entry->length = 0; usb_fill_bulk_urb (urb, dev->udev, dev->in, @@ -371,7 +387,7 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) tasklet_schedule (&dev->bh); break; case 0: - __skb_queue_tail (&dev->rxq, skb); + __usbnet_queue_skb(&dev->rxq, skb, rx_start); } } else { netif_dbg(dev, ifdown, dev->net, "rx: stopped\n"); @@ -422,16 +438,17 @@ static void rx_complete (struct urb *urb) struct skb_data *entry = (struct skb_data *) skb->cb; struct usbnet *dev = entry->dev; int urb_status = urb->status; + enum skb_state state; skb_put (skb, urb->actual_length); - entry->state = rx_done; + state = rx_done; entry->urb = NULL; switch (urb_status) { /* success */ case 0: if (skb->len < dev->net->hard_header_len) { - entry->state = rx_cleanup; + state = rx_cleanup; dev->net->stats.rx_errors++; dev->net->stats.rx_length_errors++; netif_dbg(dev, rx_err, dev->net, @@ -470,7 +487,7 @@ static void rx_complete (struct urb *urb) "rx throttle %d\n", urb_status); } block: - entry->state = rx_cleanup; + state = rx_cleanup; entry->urb = urb; urb = NULL; break; @@ -481,17 +498,18 @@ block: // FALLTHROUGH default: - entry->state = rx_cleanup; + state = rx_cleanup; dev->net->stats.rx_errors++; netif_dbg(dev, rx_err, dev->net, "rx status %d\n", urb_status); break; } - defer_bh(dev, skb, &dev->rxq); + state = defer_bh(dev, skb, &dev->rxq, state); if (urb) { if (netif_running (dev->net) && - !test_bit (EVENT_RX_HALT, &dev->flags)) { + !test_bit (EVENT_RX_HALT, &dev->flags) && + state != unlink_start) { rx_submit (dev, urb, GFP_ATOMIC); usb_mark_last_busy(dev->udev); return; @@ -578,16 +596,23 @@ EXPORT_SYMBOL_GPL(usbnet_purge_paused_rxq); static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q) { unsigned long flags; - struct sk_buff *skb, *skbnext; + struct sk_buff *skb; int count = 0; spin_lock_irqsave (&q->lock, flags); - skb_queue_walk_safe(q, skb, skbnext) { + while (!skb_queue_empty(q)) { struct skb_data *entry; struct urb *urb; int retval; - entry = (struct skb_data *) skb->cb; + skb_queue_walk(q, skb) { + entry = (struct skb_data *) skb->cb; + if (entry->state != unlink_start) + goto found; + } + break; +found: + entry->state = unlink_start; urb = entry->urb; /* @@ -884,6 +909,7 @@ static const struct ethtool_ops usbnet_ethtool_ops = { .get_drvinfo = usbnet_get_drvinfo, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, + .get_ts_info = ethtool_op_get_ts_info, }; /*-------------------------------------------------------------------------*/ @@ -1038,8 +1064,7 @@ static void tx_complete (struct urb *urb) } usb_autopm_put_interface_async(dev->intf); - entry->state = tx_done; - defer_bh(dev, skb, &dev->txq); + (void) defer_bh(dev, skb, &dev->txq, tx_done); } /*-------------------------------------------------------------------------*/ @@ -1095,7 +1120,6 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, entry = (struct skb_data *) skb->cb; entry->urb = urb; entry->dev = dev; - entry->state = tx_start; entry->length = length; usb_fill_bulk_urb (urb, dev->udev, dev->out, @@ -1154,7 +1178,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, break; case 0: net->trans_start = jiffies; - __skb_queue_tail (&dev->txq, skb); + __usbnet_queue_skb(&dev->txq, skb, tx_start); if (dev->txq.qlen >= TX_QLEN (dev)) netif_stop_queue (net); } @@ -1443,7 +1467,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) status = register_netdev (net); if (status) - goto out3; + goto out4; netif_info(dev, probe, dev->net, "register '%s' at usb-%s-%s, %s, %pM\n", udev->dev.driver->name, @@ -1461,6 +1485,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) return 0; +out4: + usb_free_urb(dev->interrupt); out3: if (info->unbind) info->unbind (dev, udev); |