- 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.)
Please merge to Linus' latest.
- Dave
--- 1.70/drivers/usb/net/usbnet.c Mon Mar 17 16:32:28 2003
+++ edited/drivers/usb/net/usbnet.c Wed Apr 2 10:24:08 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 <linux/config.h>
@@ -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 <linux/ctype.h>
+
+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 <rx h %d p %d id %d", header->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
