ChangeSet 1.1018.1.7, 2003/04/04 16:14:39-08:00, david-b@pacbell.net [PATCH] USB usbnet: dynamic config, cdc-ether, net1080 This patch: - Makes "usbnet" pay attention to device descriptors in the most common cases; there's less need to embed device hardware details. This lets it work with high speed devices, and should help interop with the newer ARM/PXA kernels "usb-eth" (same vid/pid, but different endpoints). - Adds some new CDC Ethernet support, which is partly enabled: the Zaurus SL-5500 code uses it, with the current FRAMING_Z flag overriding normal CDC framing on-the-wire. (Most of the other "minidrivers" use CDC framing, except Net1080 and GeneSys.) - Merges a patch from Johannes to recover from some net1080 framing errors by flushing the fifos ... the chip gets into a wierd mode, this makes the link more robust. (Thanks!) - Gets rid of a family of cpu/logfile saturating loops that could show up in early stages of disconnect processing, while we're getting rx/tx errors continuously since khubd hasn't tried to disconnect() us yet. (Pathological case, with lots of logging enabled: khubd never gets scheduled!) - Uses deeper queues at high speed, so the host controllers can stay busy transferring packets even when IRQs get held off for several milliseconds. That pipelining gives better throughput too -- 4x more with one device, says TTCP. With the possible exception of multicast support, this code should be a fine replacement to "cdc-ether" ... certainly its faster for high speed devices. Some later patch should likely do a switch-over. (Which would also resolve a Zaurus hotplugging bug: "cdc-ether" doesn't blacklist it.) drivers/usb/net/usbnet.c | 765 ++++++++++++++++++++++++++++++++++------------- 1 files changed, 566 insertions(+), 199 deletions(-) diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c --- a/drivers/usb/net/usbnet.c Mon Apr 7 15:14:18 2003 +++ b/drivers/usb/net/usbnet.c Mon Apr 7 15:14:18 2003 @@ -122,6 +122,11 @@ * cleanups and stubbed PXA-250 support (db), fix for framing * issues on Z, net1080, and gl620a (Toby Milne) * + * 31-mar-2003 Use endpoint descriptors: high speed support, simpler sa1100 + * vs pxa25x, and CDC Ethernet. Throttle down log floods on + * disconnect; other cleanups. (db) Flush net1080 fifos + * after several sequential framing errors. (Johannes Erdfelt) + * *-------------------------------------------------------------------------*/ #include @@ -155,16 +160,17 @@ /* minidrivers _could_ be individually configured */ #define CONFIG_USB_AN2720 #define CONFIG_USB_BELKIN +#undef CONFIG_USB_CDCETHER +//#define CONFIG_USB_CDCETHER /* NYET */ #define CONFIG_USB_EPSON2888 #define CONFIG_USB_GENESYS #define CONFIG_USB_NET1080 #define CONFIG_USB_PL2301 -// #define CONFIG_USB_PXA -#define CONFIG_USB_SA1100 +#define CONFIG_USB_ARMLINUX #define CONFIG_USB_ZAURUS -#define DRIVER_VERSION "18-Oct-2002" +#define DRIVER_VERSION "31-Mar-2003" /*-------------------------------------------------------------------------*/ @@ -176,11 +182,11 @@ * Ethernet packets (so queues should be bigger). */ #ifdef REALLY_QUEUE -#define RX_QLEN 4 -#define TX_QLEN 4 +#define RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4) +#define TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4) #else -#define RX_QLEN 1 -#define TX_QLEN 1 +#define RX_QLEN(dev) 1 +#define TX_QLEN(dev) 1 #endif // packets are always ethernet inside @@ -191,6 +197,10 @@ // reawaken network queue this soon after stopping; else watchdog barks #define TX_TIMEOUT_JIFFIES (5*HZ) +// throttle rx/tx briefly after some faults, so khubd might disconnect() +// us (it polls at HZ/4 usually) before we report too many false errors. +#define THROTTLE_JIFFIES (HZ/8) + // for vendor-specific control operations #define CONTROL_TIMEOUT_MS (500) /* msec */ #define CONTROL_TIMEOUT_JIFFIES ((CONTROL_TIMEOUT_MS * HZ)/1000) @@ -200,10 +210,6 @@ /*-------------------------------------------------------------------------*/ -// list of all devices we manage -static DECLARE_MUTEX (usbnet_mutex); -static LIST_HEAD (usbnet_list); - // randomly generated ethernet address static u8 node_id [ETH_ALEN]; @@ -213,17 +219,18 @@ struct usb_device *udev; struct driver_info *driver_info; struct semaphore mutex; - struct list_head dev_list; wait_queue_head_t *wait; + // i/o info: pipes etc + unsigned in, out; + unsigned maxpacket; + struct timer_list delay; + // protocol/interface state struct net_device net; struct net_device_stats stats; int msg_level; - -#ifdef CONFIG_USB_NET1080 - u16 packet_id; -#endif + unsigned long data [5]; // various kinds of pending driver work struct sk_buff_head rxq; @@ -231,7 +238,7 @@ struct sk_buff_head done; struct tasklet_struct bh; - struct work_struct kevent; + struct work_struct kevent; unsigned long flags; # define EVENT_TX_HALT 0 # define EVENT_RX_HALT 1 @@ -243,11 +250,19 @@ char *description; int flags; +/* framing is CDC Ethernet, not writing ZLPs (hw issues), or optionally: */ #define FLAG_FRAMING_NC 0x0001 /* guard against device dropouts */ #define FLAG_FRAMING_GL 0x0002 /* genelink batches packets */ #define FLAG_FRAMING_Z 0x0004 /* zaurus adds a trailer */ + #define FLAG_NO_SETINT 0x0010 /* device can't set_interface() */ + /* init device ... can sleep, or cause probe() failure */ + int (*bind)(struct usbnet *, struct usb_interface *); + + /* cleanup device ... can sleep, but can't fail */ + void (*unbind)(struct usbnet *, struct usb_interface *); + /* reset device ... can sleep */ int (*reset)(struct usbnet *); @@ -263,15 +278,13 @@ // FIXME -- also an interrupt mechanism // useful for at least PL2301/2302 and GL620USB-A + // and CDC use them to report 'is it connected' changes - /* framework currently "knows" bulk EPs talk packets */ + /* for new devices, use the descriptor-reading code instead */ int in; /* rx endpoint */ int out; /* tx endpoint */ - int epsize; }; -#define EP_SIZE(usbnet) ((usbnet)->driver_info->epsize) - // we record the state for each of our queued skbs enum skb_state { illegal = 0, @@ -300,14 +313,6 @@ #define RUN_CONTEXT (in_irq () ? "in_irq" \ : (in_interrupt () ? "in_interrupt" : "can sleep")) -/* mostly for PDA style devices, which are always present */ -static int always_connected (struct usbnet *dev) -{ - return 0; -} - -/*-------------------------------------------------------------------------*/ - #ifdef DEBUG #define devdbg(usbnet, fmt, arg...) \ printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net.name, ## arg) @@ -315,11 +320,76 @@ #define devdbg(usbnet, fmt, arg...) do {} while(0) #endif +#define deverr(usbnet, fmt, arg...) \ + printk(KERN_ERR "%s: " fmt "\n" , (usbnet)->net.name, ## arg) +#define devwarn(usbnet, fmt, arg...) \ + printk(KERN_WARNING "%s: " fmt "\n" , (usbnet)->net.name, ## arg) + #define devinfo(usbnet, fmt, arg...) \ do { if ((usbnet)->msg_level >= 1) \ printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net.name, ## arg); \ } while (0) +/*-------------------------------------------------------------------------*/ + +/* mostly for PDA style devices, which are always connected if present */ +static int always_connected (struct usbnet *dev) +{ + return 0; +} + +/* handles CDC Ethernet and many other network "bulk data" interfaces */ +static int +get_endpoints (struct usbnet *dev, struct usb_interface *intf) +{ + int tmp; + struct usb_host_interface *alt; + struct usb_host_endpoint *in, *out; + + for (tmp = 0; tmp < intf->max_altsetting; tmp++) { + unsigned ep; + + in = out = 0; + alt = intf->altsetting + tmp; + + /* take the first altsetting with in-bulk + out-bulk; + * ignore other endpoints and altsetttings. + */ + for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) { + struct usb_host_endpoint *e; + + e = alt->endpoint + ep; + if (e->desc.bmAttributes != USB_ENDPOINT_XFER_BULK) + continue; + if (e->desc.bEndpointAddress & USB_DIR_IN) { + if (!in) + in = e; + } else { + if (!out) + out = e; + } + if (in && out) + goto found; + } + } + return -EINVAL; + +found: + if (alt->desc.bAlternateSetting != 0 + || !(dev->driver_info->flags & FLAG_NO_SETINT)) { + tmp = usb_set_interface (dev->udev, alt->desc.bInterfaceNumber, + alt->desc.bAlternateSetting); + if (tmp < 0) + return tmp; + } + + dev->in = usb_rcvbulkpipe (dev->udev, + in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + dev->out = usb_sndbulkpipe (dev->udev, + out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + return 0; +} + #ifdef CONFIG_USB_AN2720 @@ -340,7 +410,6 @@ // no check_connect available! .in = 2, .out = 2, // direction distinguishes these - .epsize =64, }; #endif /* CONFIG_USB_AN2720 */ @@ -359,15 +428,226 @@ static const struct driver_info belkin_info = { .description = "Belkin, eTEK, or compatible", - - .in = 1, .out = 1, // direction distinguishes these - .epsize =64, }; #endif /* CONFIG_USB_BELKIN */ +#if defined (CONFIG_USB_CDCETHER) || defined (CONFIG_USB_ZAURUS) + +/*------------------------------------------------------------------------- + * + * Communications Device Class, Ethernet Control model + * + * Takes two interfaces. The DATA interface is inactive till an altsetting + * is selected. Configuration data includes class descriptors. + * + * Zaurus uses nonstandard framing, but is otherwise CDC Ether. + * + *-------------------------------------------------------------------------*/ + +/* "Header Functional Descriptor" from CDC spec 5.2.3.1 */ +struct header_desc { + u8 bLength; + u8 bDescriptorType; + u8 bDescriptorSubType; + + u16 bcdCDC; +} __attribute__ ((packed)); + +/* "Union Functional Descriptor" from CDC spec 5.2.3.X */ +struct union_desc { + u8 bLength; + u8 bDescriptorType; + u8 bDescriptorSubType; + + u8 bMasterInterface0; + u8 bSlaveInterface0; + /* ... and there could be other slave interfaces */ +} __attribute__ ((packed)); + +/* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */ +struct ether_desc { + u8 bLength; + u8 bDescriptorType; + u8 bDescriptorSubType; + + u8 iMACAddress; + u32 bmEthernetStatistics; + u16 wMaxSegmentSize; + u16 wNumberMCFilters; + u8 bNumberPowerFilters; +} __attribute__ ((packed)); + +struct cdc_info { + struct header_desc *header; + struct union_desc *u; + struct ether_desc *ether; + struct usb_interface *control; + struct usb_interface *data; +}; + +#include + +static u8 nibble (unsigned char c) +{ + if (likely (isdigit (c))) + return c - '0'; + c = toupper (c); + if (likely (isxdigit (c))) + return 10 + c - 'A'; + return 0; +} + +static inline int get_ethernet_addr (struct usbnet *dev, struct ether_desc *e) +{ + int tmp, i; + unsigned char buf [13]; + + tmp = usb_string (dev->udev, e->iMACAddress, buf, sizeof buf); + if (tmp < 0) + return tmp; + else if (tmp != 12) + return -EINVAL; + for (i = tmp = 0; i < 6; i++, tmp += 2) + dev->net.dev_addr [i] = + (nibble (buf [tmp]) << 4) + nibble (buf [tmp + 1]); + return 0; +} + +static struct usb_driver usbnet_driver; + +static int cdc_bind (struct usbnet *dev, struct usb_interface *intf) +{ + u8 *buf = intf->altsetting->extra; + int len = intf->altsetting->extralen; + struct usb_interface_descriptor *d; + struct cdc_info *info = (void *) &dev->data; + int status; + + if (sizeof dev->data < sizeof *info) + return -EDOM; + + /* expect strict spec conformance for the descriptors */ + memset (info, 0, sizeof *info); + info->control = intf; + while (len > 3) { + /* ignore bDescriptorType != CS_INTERFACE */ + if (buf [1] != 0x24) + goto next_desc; + + /* bDescriptorSubType identifies three "must have" descriptors; + * save them for later. + */ + switch (buf [2]) { + case 0x00: /* Header, mostly useless */ + if (info->header) + goto bad_desc; + info->header = (void *) buf; + if (info->header->bLength != sizeof *info->header) + goto bad_desc; + break; + case 0x06: /* Union (groups interfaces) */ + if (info->u) + goto bad_desc; + info->u = (void *) buf; + if (info->u->bLength != sizeof *info->u) + goto bad_desc; + d = &intf->altsetting->desc; + if (info->u->bMasterInterface0 != d->bInterfaceNumber) + goto bad_desc; + info->data = dev->udev->actconfig->interface; + if (intf != (info->data + info->u->bMasterInterface0)) + goto bad_desc; + + /* a data interface altsetting does the real i/o */ + info->data += info->u->bSlaveInterface0; + d = &info->data->altsetting->desc; + if (info->u->bSlaveInterface0 != d->bInterfaceNumber + || d->bInterfaceClass != USB_CLASS_CDC_DATA) + goto bad_desc; + if (usb_interface_claimed (info->data)) + return -EBUSY; + break; + case 0x0F: /* Ethernet Networking */ + if (info->ether) + goto bad_desc; + info->ether = (void *) buf; + if (info->ether->bLength != sizeof *info->ether) + goto bad_desc; + break; + } +next_desc: + len -= buf [0]; /* bLength */ + buf += buf [0]; + } + if (!info->header || !info ->u || !info->ether) + goto bad_desc; + + status = get_ethernet_addr (dev, info->ether); + if (status < 0) + return status; + + /* claim data interface and set it up ... with side effects. + * network traffic can't flow until an altsetting is enabled. + */ + usb_driver_claim_interface (&usbnet_driver, info->data, dev); + status = get_endpoints (dev, info->data); + if (status < 0) { + usb_driver_release_interface (&usbnet_driver, info->data); + return status; + } + + /* FIXME cdc-ether has some multicast code too, though it complains + * in routine cases. info->ether describes the multicast support. + */ + + dev->net.mtu = cpu_to_le16p (&info->ether->wMaxSegmentSize) + - ETH_HLEN; + if ((dev->driver_info->flags & FLAG_FRAMING_Z) == 0) + strcpy (dev->net.name, "eth%d"); + return 0; + +bad_desc: + // devdbg (dev, "bad CDC descriptors"); + return -ENODEV; +} + +static void cdc_unbind (struct usbnet *dev, struct usb_interface *intf) +{ + struct cdc_info *info = (void *) &dev->data; + + /* disconnect master --> disconnect slave */ + if (intf == info->control && info->data) { + usb_driver_release_interface (&usbnet_driver, info->data); + info->data = 0; + } + + /* and vice versa (just in case) */ + else if (intf == info->data && info->control) { + usb_driver_release_interface (&usbnet_driver, info->control); + info->control = 0; + } + +} + +#endif /* CONFIG_USB_ZAURUS || CONFIG_USB_CDCETHER */ + + +#ifdef CONFIG_USB_CDCETHER + +static const struct driver_info cdc_info = { + .description = "CDC Ethernet Device", + // .check_connect = cdc_check_connect, + .bind = cdc_bind, + .unbind = cdc_unbind, +}; + +#endif /* CONFIG_USB_CDCETHER */ + + + #ifdef CONFIG_USB_EPSON2888 /*------------------------------------------------------------------------- @@ -386,7 +666,6 @@ .check_connect = always_connected, .in = 4, .out = 3, - .epsize = 64, }; #endif /* CONFIG_USB_EPSON2888 */ @@ -704,7 +983,7 @@ *packet_len = length; // add padding byte - if ((skb->len % EP_SIZE (dev)) == 0) + if ((skb->len % dev->maxpacket) == 0) skb_put (skb, 1); return skb; @@ -717,7 +996,6 @@ .tx_fixup = genelink_tx_fixup, .in = 1, .out = 2, - .epsize =64, #ifdef GENELINK_ACK .check_connect =genelink_check_connect, @@ -737,6 +1015,9 @@ * *-------------------------------------------------------------------------*/ +#define dev_packet_id data[0] +#define frame_errors data[1] + /* * NetChip framing of ethernet packets, supporting additional error * checks for links that may drop bulk packets from inside messages. @@ -1064,6 +1345,60 @@ return 0; } +static void nc_flush_complete (struct urb *urb, struct pt_regs *regs) +{ + kfree (urb->context); + usb_free_urb(urb); +} + +static void nc_ensure_sync (struct usbnet *dev) +{ + dev->frame_errors++; + if (dev->frame_errors > 5) { + struct urb *urb; + struct usb_ctrlrequest *req; + int status; + + /* Send a flush */ + urb = usb_alloc_urb (0, SLAB_ATOMIC); + if (!urb) + return; + + req = kmalloc (sizeof *req, GFP_ATOMIC); + if (!req) { + usb_free_urb (urb); + return; + } + + req->bRequestType = USB_DIR_OUT + | USB_TYPE_VENDOR + | USB_RECIP_DEVICE; + req->bRequest = REQUEST_REGISTER; + req->wValue = cpu_to_le16 (USBCTL_FLUSH_THIS + | USBCTL_FLUSH_OTHER); + req->wIndex = cpu_to_le16 (REG_USBCTL); + req->wLength = cpu_to_le16 (0); + + /* queue an async control request, we don't need + * to do anything when it finishes except clean up. + */ + usb_fill_control_urb (urb, dev->udev, + usb_sndctrlpipe (dev->udev, 0), + (unsigned char *) req, + NULL, 0, + nc_flush_complete, req); + status = usb_submit_urb (urb, GFP_ATOMIC); + if (status) { + kfree (req); + usb_free_urb (urb); + return; + } + + devdbg (dev, "flush net1080; too many framing errors"); + dev->frame_errors = 0; + } +} + static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb) { struct nc_header *header; @@ -1076,6 +1411,7 @@ dbg ("rx framesize %d range %d..%d mtu %d", skb->len, (int)MIN_FRAMED, (int)FRAMED_SIZE (dev->net.mtu), dev->net.mtu); + nc_ensure_sync (dev); return 0; } @@ -1085,15 +1421,18 @@ if (FRAMED_SIZE (header->packet_len) > MAX_PACKET) { dev->stats.rx_frame_errors++; dbg ("packet too big, %d", header->packet_len); + nc_ensure_sync (dev); return 0; } else if (header->hdr_len < MIN_HEADER) { dev->stats.rx_frame_errors++; dbg ("header too short, %d", header->hdr_len); + nc_ensure_sync (dev); return 0; } else if (header->hdr_len > MIN_HEADER) { // out of band data for us? dbg ("header OOB, %d bytes", header->hdr_len - MIN_HEADER); + nc_ensure_sync (dev); // switch (vendor/product ids) { ... } } skb_pull (skb, header->hdr_len); @@ -1114,6 +1453,7 @@ dev->stats.rx_frame_errors++; dbg ("bad packet len %d (expected %d)", skb->len, header->packet_len); + nc_ensure_sync (dev); return 0; } if (header->packet_id != get_unaligned (&trailer->packet_id)) { @@ -1126,6 +1466,7 @@ devdbg (dev, "frame hdr_len, header->packet_len, header->packet_id); #endif + dev->frame_errors = 0; return 1; } @@ -1143,11 +1484,13 @@ if ((padlen + sizeof (struct nc_trailer)) <= tailroom && sizeof (struct nc_header) <= headroom) + /* There's enough head and tail room */ return skb; if ((sizeof (struct nc_header) + padlen + sizeof (struct nc_trailer)) < (headroom + tailroom)) { + /* There's enough total room, so just readjust */ skb->data = memmove (skb->head + sizeof (struct nc_header), skb->data, skb->len); @@ -1155,6 +1498,8 @@ return skb; } } + + /* Create a new skb to use with the correct size */ skb2 = skb_copy_expand (skb, sizeof (struct nc_header), sizeof (struct nc_trailer) + padlen, @@ -1170,9 +1515,6 @@ .check_connect =net1080_check_connect, .rx_fixup = net1080_rx_fixup, .tx_fixup = net1080_tx_fixup, - - .in = 1, .out = 1, // direction distinguishes these - .epsize =64, }; #endif /* CONFIG_USB_NET1080 */ @@ -1237,37 +1579,13 @@ .flags = FLAG_NO_SETINT, /* some PL-2302 versions seem to fail usb_set_interface() */ .reset = pl_reset, - - .in = 3, .out = 2, - .epsize =64, }; #endif /* CONFIG_USB_PL2301 */ -#ifdef CONFIG_USB_PXA - -/*------------------------------------------------------------------------- - * - * PXA250 and PXA210 use XScale cores (ARM v5TE) with better USB support, - * and different USB endpoint numbering than the SA1100 devices. - * - *-------------------------------------------------------------------------*/ - -static const struct driver_info pxa_info = { - .description = "PXA-250 Linux Device", - .check_connect = always_connected, - - .in = 1, .out = 2, - .epsize = 64, -}; - -#endif /* CONFIG_USB_PXA */ - - - -#ifdef CONFIG_USB_SA1100 +#ifdef CONFIG_USB_ARMLINUX /*------------------------------------------------------------------------- * @@ -1279,25 +1597,24 @@ * This describes the driver currently in standard ARM Linux kernels. * The Zaurus uses a different driver (see later). * + * PXA25x and PXA210 use XScale cores (ARM v5TE) with better USB support + * and different USB endpoint numbering than the SA1100 devices. The + * mach-pxa/usb-eth.c driver re-uses the device ids from mach-sa1100 + * so we rely on the endpoint descriptors. + * *-------------------------------------------------------------------------*/ static const struct driver_info linuxdev_info = { - .description = "SA-1100 Linux Device", + .description = "Linux Device", .check_connect = always_connected, - - .in = 2, .out = 1, - .epsize = 64, }; static const struct driver_info yopy_info = { .description = "Yopy", .check_connect = always_connected, - - .in = 2, .out = 1, - .epsize = 64, }; -#endif /* CONFIG_USB_SA1100 */ +#endif /* CONFIG_USB_ARMLINUX */ #ifdef CONFIG_USB_ZAURUS @@ -1349,10 +1666,9 @@ .description = "Sharp Zaurus SL-5x00", .flags = FLAG_FRAMING_Z, .check_connect = always_connected, + .bind = cdc_bind, + .unbind = cdc_unbind, .tx_fixup = zaurus_tx_fixup, - - .in = 2, .out = 1, - .epsize = 64, }; static const struct driver_info zaurus_sla300_info = { .description = "Sharp Zaurus SL-A300", @@ -1361,7 +1677,6 @@ .tx_fixup = zaurus_tx_fixup, .in = 1, .out = 2, - .epsize = 64, }; static const struct driver_info zaurus_slb500_info = { /* Japanese B500 ~= US SL-5600 */ @@ -1371,7 +1686,6 @@ .tx_fixup = zaurus_tx_fixup, .in = 1, .out = 2, - .epsize = 64, }; // SL-5600 and C-700 are PXA based; should resemble A300 @@ -1403,7 +1717,7 @@ return -EINVAL; #endif // no second zero-length packet read wanted after mtu-sized packets - if (((new_mtu + sizeof (struct ethhdr)) % EP_SIZE (dev)) == 0) + if (((new_mtu + sizeof (struct ethhdr)) % dev->maxpacket) == 0) return -EDOM; net->mtu = new_mtu; return 0; @@ -1444,10 +1758,9 @@ { set_bit (work, &dev->flags); if (!schedule_work (&dev->kevent)) - err ("%s: kevent %d may have been dropped", - dev->net.name, work); + deverr (dev, "kevent %d may have been dropped", work); else - dbg ("%s: kevent %d scheduled", dev->net.name, work); + devdbg (dev, "kevent %d scheduled", work); } /*-------------------------------------------------------------------------*/ @@ -1480,7 +1793,7 @@ size = (sizeof (struct ethhdr) + dev->net.mtu); if ((skb = alloc_skb (size, flags)) == 0) { - dbg ("no rx skb"); + devdbg (dev, "no rx skb"); defer_kevent (dev, EVENT_RX_MEMORY); usb_free_urb (urb); return; @@ -1492,14 +1805,14 @@ entry->state = rx_start; entry->length = 0; - usb_fill_bulk_urb (urb, dev->udev, - usb_rcvbulkpipe (dev->udev, dev->driver_info->in), + usb_fill_bulk_urb (urb, dev->udev, dev->in, skb->data, size, rx_complete, skb); urb->transfer_flags |= URB_ASYNC_UNLINK; spin_lock_irqsave (&dev->rxq.lock, lockflags); if (netif_running (&dev->net) + && netif_device_present (&dev->net) && !test_bit (EVENT_RX_HALT, &dev->flags)) { switch (retval = usb_submit_urb (urb, GFP_ATOMIC)){ case -EPIPE: @@ -1508,15 +1821,19 @@ case -ENOMEM: defer_kevent (dev, EVENT_RX_MEMORY); break; + case -ENODEV: + devdbg (dev, "device gone"); + netif_device_detach (&dev->net); + break; default: - dbg ("%s rx submit, %d", dev->net.name, retval); + devdbg (dev, "rx submit, %d", retval); tasklet_schedule (&dev->bh); break; case 0: __skb_queue_tail (&dev->rxq, skb); } } else { - dbg ("rx: stopped"); + devdbg (dev, "rx: stopped"); retval = -ENOLINK; } spin_unlock_irqrestore (&dev->rxq.lock, lockflags); @@ -1553,7 +1870,7 @@ if (status != NET_RX_SUCCESS) devdbg (dev, "netif_rx status %d", status); } else { - dbg ("drop"); + devdbg (dev, "drop"); error: dev->stats.rx_errors++; skb_queue_tail (&dev->done, skb); @@ -1580,7 +1897,7 @@ entry->state = rx_cleanup; dev->stats.rx_errors++; dev->stats.rx_length_errors++; - dbg ("rx length %d", skb->len); + devdbg (dev, "rx length %d", skb->len); } break; @@ -1589,15 +1906,31 @@ // we avoid the highspeed version of the ETIMEOUT/EILSEQ // storm, recovering as needed. case -EPIPE: + dev->stats.rx_errors++; defer_kevent (dev, EVENT_RX_HALT); // FALLTHROUGH // software-driven interface shutdown - case -ECONNRESET: // according to API spec - case -ECONNABORTED: // some (now fixed?) UHCI bugs - dbg ("%s rx shutdown, code %d", dev->net.name, urb_status); + case -ECONNRESET: // async unlink + case -ESHUTDOWN: // hardware gone +#ifdef VERBOSE + devdbg (dev, "rx shutdown, code %d", urb_status); +#endif + goto block; + + // we get controller i/o faults during khubd disconnect() delays. + // throttle down resubmits, to avoid log floods; just temporarily, + // so we still recover when the fault isn't a khubd delay. + case -EPROTO: // ehci + case -ETIMEDOUT: // ohci + case -EILSEQ: // uhci + dev->stats.rx_errors++; + if (!timer_pending (&dev->delay)) { + mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES); + devdbg (dev, "rx throttle %d", urb_status); + } +block: entry->state = rx_cleanup; - // do urb frees only in the tasklet (UHCI has oopsed ...) entry->urb = urb; urb = 0; break; @@ -1608,12 +1941,9 @@ // FALLTHROUGH default: - // on unplug we get ETIMEDOUT (ohci) or EILSEQ (uhci) - // until khubd sees its interrupt and disconnects us. - // that can easily be hundreds of passes through here. entry->state = rx_cleanup; dev->stats.rx_errors++; - dbg ("%s rx: status %d", dev->net.name, urb_status); + devdbg (dev, "rx status %d", urb_status); break; } @@ -1628,7 +1958,7 @@ usb_free_urb (urb); } #ifdef VERBOSE - dbg ("no read resubmitted"); + devdbg (dev, "no read resubmitted"); #endif /* VERBOSE */ } @@ -1636,7 +1966,7 @@ // unlink pending rx/tx; completion handlers do all other cleanup -static int unlink_urbs (struct sk_buff_head *q) +static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q) { unsigned long flags; struct sk_buff *skb, *skbnext; @@ -1656,7 +1986,7 @@ // these (async) unlinks complete immediately retval = usb_unlink_urb (urb); if (retval != -EINPROGRESS && retval != 0) - dbg ("unlink urb err, %d", retval); + devdbg (dev, "unlink urb err, %d", retval); else count++; } @@ -1688,7 +2018,7 @@ // ensure there are no more active urbs add_wait_queue (&unlink_wakeup, &wait); dev->wait = &unlink_wakeup; - temp = unlink_urbs (&dev->txq) + unlink_urbs (&dev->rxq); + temp = unlink_urbs (dev, &dev->txq) + unlink_urbs (dev, &dev->rxq); // maybe wait for deletions to finish. while (skb_queue_len (&dev->rxq) @@ -1696,11 +2026,16 @@ && skb_queue_len (&dev->done)) { set_current_state (TASK_UNINTERRUPTIBLE); schedule_timeout (UNLINK_TIMEOUT_JIFFIES); - dbg ("waited for %d urb completions", temp); + devdbg (dev, "waited for %d urb completions", temp); } dev->wait = 0; remove_wait_queue (&unlink_wakeup, &wait); + // deferred work (task, timer, softirq) must also stop + flush_scheduled_work (); + del_timer_sync (&dev->delay); + tasklet_kill (&dev->bh); + mutex_unlock (&dev->mutex); return 0; } @@ -1738,7 +2073,7 @@ if (dev->msg_level >= 2) devinfo (dev, "open: enable queueing " "(rx %d, tx %d) mtu %d %s framing", - RX_QLEN, TX_QLEN, dev->net.mtu, + RX_QLEN (dev), TX_QLEN (dev), dev->net.mtu, (info->flags & (FLAG_FRAMING_NC | FLAG_FRAMING_GL)) ? ((info->flags & FLAG_FRAMING_NC) ? "NetChip" @@ -1755,7 +2090,8 @@ /*-------------------------------------------------------------------------*/ -static int usbnet_ethtool_ioctl (struct net_device *net, void *useraddr) +static inline int +usbnet_ethtool_ioctl (struct net_device *net, void *useraddr) { struct usbnet *dev = (struct usbnet *) net->priv; u32 cmd; @@ -1829,9 +2165,8 @@ /* work that cannot be done in interrupt context uses keventd. * - * NOTE: "uhci" and "usb-uhci" may have trouble with this since they don't - * queue control transfers to individual devices, and other threads could - * trigger control requests concurrently. hope that's rare. + * NOTE: with 2.5 we could do more of this using completion callbacks, + * especially now that control transfers can be queued. */ static void kevent (void *data) @@ -1841,24 +2176,22 @@ /* usb_clear_halt() needs a thread context */ if (test_bit (EVENT_TX_HALT, &dev->flags)) { - unlink_urbs (&dev->txq); - status = usb_clear_halt (dev->udev, - usb_sndbulkpipe (dev->udev, dev->driver_info->out)); + unlink_urbs (dev, &dev->txq); + status = usb_clear_halt (dev->udev, dev->out); if (status < 0) - err ("%s: can't clear tx halt, status %d", - dev->net.name, status); + deverr (dev, "can't clear tx halt, status %d", + status); else { clear_bit (EVENT_TX_HALT, &dev->flags); netif_wake_queue (&dev->net); } } if (test_bit (EVENT_RX_HALT, &dev->flags)) { - unlink_urbs (&dev->rxq); - status = usb_clear_halt (dev->udev, - usb_rcvbulkpipe (dev->udev, dev->driver_info->in)); + unlink_urbs (dev, &dev->rxq); + status = usb_clear_halt (dev->udev, dev->in); if (status < 0) - err ("%s: can't clear rx halt, status %d", - dev->net.name, status); + deverr (dev, "can't clear rx halt, status %d", + status); else { clear_bit (EVENT_RX_HALT, &dev->flags); tasklet_schedule (&dev->bh); @@ -1881,8 +2214,8 @@ } if (dev->flags) - dbg ("%s: kevent done, flags = 0x%lx", - dev->net.name, dev->flags); + devdbg (dev, "kevent done, flags = 0x%lx", + dev->flags); } /*-------------------------------------------------------------------------*/ @@ -1893,8 +2226,35 @@ struct skb_data *entry = (struct skb_data *) skb->cb; struct usbnet *dev = entry->dev; - if (urb->status == -EPIPE) - defer_kevent (dev, EVENT_TX_HALT); + if (urb->status == 0) { + dev->stats.tx_packets++; + dev->stats.tx_bytes += entry->length; + } else { + dev->stats.tx_errors++; + + switch (urb->status) { + case -EPIPE: + defer_kevent (dev, EVENT_TX_HALT); + break; + + // like rx, tx gets controller i/o faults during khubd delays + // and so it uses the same throttling mechanism. + case -EPROTO: // ehci + case -ETIMEDOUT: // ohci + case -EILSEQ: // uhci + if (!timer_pending (&dev->delay)) { + mod_timer (&dev->delay, + jiffies + THROTTLE_JIFFIES); + devdbg (dev, "tx throttle %d", urb->status); + } + netif_stop_queue (&dev->net); + break; + default: + devdbg (dev, "tx err %d", entry->urb->status); + break; + } + } + urb->dev = 0; entry->state = tx_done; defer_bh (dev, skb); @@ -1906,7 +2266,7 @@ { struct usbnet *dev = (struct usbnet *) net->priv; - unlink_urbs (&dev->txq); + unlink_urbs (dev, &dev->txq); tasklet_schedule (&dev->bh); // FIXME: device recovery -- reset? @@ -1933,14 +2293,14 @@ if (info->tx_fixup) { skb = info->tx_fixup (dev, skb, GFP_ATOMIC); if (!skb) { - dbg ("can't tx_fixup skb"); + devdbg (dev, "can't tx_fixup skb"); goto drop; } } length = skb->len; if (!(urb = usb_alloc_urb (0, GFP_ATOMIC))) { - dbg ("no urb"); + devdbg (dev, "no urb"); goto drop; } @@ -1965,20 +2325,24 @@ } else #endif /* CONFIG_USB_NET1080 */ - /* don't assume the hardware handles USB_ZERO_PACKET */ - if ((length % EP_SIZE (dev)) == 0) - skb->len++; - - usb_fill_bulk_urb (urb, dev->udev, - usb_sndbulkpipe (dev->udev, info->out), + usb_fill_bulk_urb (urb, dev->udev, dev->out, skb->data, skb->len, tx_complete, skb); urb->transfer_flags |= URB_ASYNC_UNLINK; + /* don't assume the hardware handles USB_ZERO_PACKET + * NOTE: strictly conforming cdc-ether devices should expect + * the ZLP here, but ignore the one-byte packet. + * + * FIXME zero that byte, if it doesn't require a new skb. + */ + if ((length % dev->maxpacket) == 0) + urb->transfer_buffer_length++; + spin_lock_irqsave (&dev->txq.lock, flags); #ifdef CONFIG_USB_NET1080 if (info->flags & FLAG_FRAMING_NC) { - header->packet_id = cpu_to_le16 (dev->packet_id++); + header->packet_id = cpu_to_le16 ((u16)dev->dev_packet_id++); put_unaligned (header->packet_id, &trailer->packet_id); #if 0 devdbg (dev, "frame >tx h %d p %d id %d", @@ -1994,12 +2358,12 @@ defer_kevent (dev, EVENT_TX_HALT); break; default: - dbg ("%s tx: submit urb err %d", net->name, retval); + devdbg (dev, "tx: submit urb err %d", retval); break; case 0: net->trans_start = jiffies; __skb_queue_tail (&dev->txq, skb); - if (dev->txq.qlen >= TX_QLEN) + if (dev->txq.qlen >= TX_QLEN (dev)) netif_stop_queue (net); } spin_unlock_irqrestore (&dev->txq.lock, flags); @@ -2024,7 +2388,7 @@ /*-------------------------------------------------------------------------*/ -// tasklet ... work that avoided running in_irq() +// tasklet (work deferred from completions, in_irq) or timer static void usbnet_bh (unsigned long param) { @@ -2040,23 +2404,12 @@ rx_process (dev, skb); continue; case tx_done: - if (entry->urb->status) { - // can this statistic become more specific? - dev->stats.tx_errors++; - dbg ("%s tx: err %d", dev->net.name, - entry->urb->status); - } else { - dev->stats.tx_packets++; - dev->stats.tx_bytes += entry->length; - } - // FALLTHROUGH: case rx_cleanup: usb_free_urb (entry->urb); dev_kfree_skb (skb); continue; default: - dbg ("%s: bogus skb state %d", - dev->net.name, entry->state); + devdbg (dev, "bogus skb state %d", entry->state); } } @@ -2068,23 +2421,28 @@ // or are we maybe short a few urbs? } else if (netif_running (&dev->net) + && netif_device_present (&dev->net) + && !timer_pending (&dev->delay) && !test_bit (EVENT_RX_HALT, &dev->flags)) { int temp = dev->rxq.qlen; + int qlen = RX_QLEN (dev); - if (temp < RX_QLEN) { + if (temp < qlen) { struct urb *urb; int i; - for (i = 0; i < 3 && dev->rxq.qlen < RX_QLEN; i++) { + + // don't refill the queue all at once + for (i = 0; i < 10 && dev->rxq.qlen < qlen; i++) { if ((urb = usb_alloc_urb (0, GFP_ATOMIC)) != 0) rx_submit (dev, urb, GFP_ATOMIC); } if (temp != dev->rxq.qlen) devdbg (dev, "rxqlen %d --> %d", temp, dev->rxq.qlen); - if (dev->rxq.qlen < RX_QLEN) + if (dev->rxq.qlen < qlen) tasklet_schedule (&dev->bh); } - if (dev->txq.qlen < TX_QLEN) + if (dev->txq.qlen < TX_QLEN (dev)) netif_wake_queue (&dev->net); } } @@ -2117,13 +2475,8 @@ unregister_netdev (&dev->net); - mutex_lock (&usbnet_mutex); - mutex_lock (&dev->mutex); - list_del (&dev->dev_list); - mutex_unlock (&usbnet_mutex); - - // assuming we used keventd, it must quiesce too - flush_scheduled_work (); + if (dev->driver_info->unbind) + dev->driver_info->unbind (dev, intf); kfree (dev); usb_put_dev (xdev); @@ -2142,20 +2495,12 @@ struct usb_host_interface *interface; struct driver_info *info; struct usb_device *xdev; + int status; info = (struct driver_info *) prod->driver_info; - xdev = interface_to_usbdev (udev); interface = &udev->altsetting [udev->act_altsetting]; - if (!(info->flags & FLAG_NO_SETINT)) { - if (usb_set_interface (xdev, interface->desc.bInterfaceNumber, - interface->desc.bAlternateSetting) < 0) { - err ("set_interface failed"); - return -EIO; - } - } - // set up our own records if (!(dev = kmalloc (sizeof *dev, GFP_KERNEL))) { dbg ("can't kmalloc dev"); @@ -2168,13 +2513,15 @@ dev->udev = xdev; dev->driver_info = info; dev->msg_level = msg_level; - INIT_LIST_HEAD (&dev->dev_list); skb_queue_head_init (&dev->rxq); skb_queue_head_init (&dev->txq); skb_queue_head_init (&dev->done); dev->bh.func = usbnet_bh; dev->bh.data = (unsigned long) dev; INIT_WORK (&dev->kevent, kevent, dev); + dev->delay.function = usbnet_bh; + dev->delay.data = (unsigned long) dev; + init_timer (&dev->delay); // set up network interface records net = &dev->net; @@ -2200,31 +2547,41 @@ net->tx_timeout = usbnet_tx_timeout; net->do_ioctl = usbnet_ioctl; + // allow device-specific bind/init procedures + // NOTE net->name still not usable ... + if (info->bind) + status = info->bind (dev, udev); + else if (!info->in || info->out) + status = get_endpoints (dev, udev); + else { + dev->in = usb_rcvbulkpipe (xdev, info->in); + dev->out = usb_sndbulkpipe (xdev, info->out); + if (!(info->flags & FLAG_NO_SETINT)) + status = usb_set_interface (xdev, + interface->desc.bInterfaceNumber, + interface->desc.bAlternateSetting); + else + status = 0; + + } + if (status < 0) { + kfree (dev); + return status; + } + dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1); + register_netdev (&dev->net); - devinfo (dev, "register usbnet usb-%s-%s, %s", + devinfo (dev, "register usbnet at usb-%s-%s, %s", xdev->bus->bus_name, xdev->devpath, dev->driver_info->description); -#ifdef CONFIG_USB_ZAURUS - if (dev->driver_info == &zaurus_sl5x00_info) { - int status; - status = usb_set_configuration (xdev, 1); - devinfo (dev, "set config --> %d", status); - status = usb_set_interface (xdev, 1, 1); - devinfo (dev, "set altsetting --> %d", status); - } -#endif - // ok, it's ready to go. - usb_set_intfdata(udev, dev); - mutex_lock (&usbnet_mutex); - list_add (&dev->dev_list, &usbnet_list); + usb_set_intfdata (udev, dev); mutex_unlock (&dev->mutex); // start as if the link is up netif_device_attach (&dev->net); - mutex_unlock (&usbnet_mutex); return 0; } @@ -2298,28 +2655,19 @@ }, #endif -#ifdef CONFIG_USB_PXA -/* - * PXA250 or PXA210 ... these use a "usb-eth" driver much like - * the sa1100 one. - */ -{ - // Compaq "Itsy" vendor/product id, version "2.0" - USB_DEVICE_VER (0x049F, 0x505A, 0x0200, 0x0200), - .driver_info = (unsigned long) &pxa_info, -}, -#endif - -#ifdef CONFIG_USB_SA1100 +#ifdef CONFIG_USB_ARMLINUX /* * SA-1100 using standard ARM Linux kernels, or compatible. * Often used when talking to Linux PDAs (iPaq, Yopy, etc). * The sa-1100 "usb-eth" driver handles the basic framing. + * + * PXA25x or PXA210 ... these use a "usb-eth" driver much like + * the sa1100 one, but hardware uses different endpoint numbers. */ { // 1183 = 0x049F, both used as hex values? - // Compaq "Itsy" vendor/product id, version "0.0" - USB_DEVICE_VER (0x049F, 0x505A, 0, 0), + // Compaq "Itsy" vendor/product id + USB_DEVICE (0x049F, 0x505A), .driver_info = (unsigned long) &linuxdev_info, }, { USB_DEVICE (0x0E7E, 0x1001), // G.Mate "Yopy" @@ -2337,9 +2685,10 @@ | USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x04DD, .idProduct = 0x8004, - .bInterfaceClass = 0x0a, - .bInterfaceSubClass = 0x00, - .bInterfaceProtocol = 0x00, + /* match the master interface */ + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = 6 /* Ethernet model */, + .bInterfaceProtocol = 0, .driver_info = (unsigned long) &zaurus_sl5x00_info, }, { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO @@ -2359,6 +2708,24 @@ .bInterfaceSubClass = 0x0a, .bInterfaceProtocol = 0x00, .driver_info = (unsigned long) &zaurus_slb500_info, +}, +#endif + +#ifdef CONFIG_USB_CDCETHER +{ + /* CDC Ether uses two interfaces, not necessarily consecutive. + * We match the main interface, ignoring the optional device + * class so we could handle devices that aren't exclusively + * CDC ether. + * + * NOTE: this match must come AFTER entries working around + * bugs/quirks in a given product (like Zaurus, above). + */ + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = 6 /* Ethernet model */, + .bInterfaceProtocol = 0, + .driver_info = (unsigned long) &cdc_info, }, #endif