Commit eca765b0 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[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.)
parent 22a8591b
...@@ -122,6 +122,11 @@ ...@@ -122,6 +122,11 @@
* cleanups and stubbed PXA-250 support (db), fix for framing * cleanups and stubbed PXA-250 support (db), fix for framing
* issues on Z, net1080, and gl620a (Toby Milne) * 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> #include <linux/config.h>
...@@ -155,16 +160,17 @@ ...@@ -155,16 +160,17 @@
/* minidrivers _could_ be individually configured */ /* minidrivers _could_ be individually configured */
#define CONFIG_USB_AN2720 #define CONFIG_USB_AN2720
#define CONFIG_USB_BELKIN #define CONFIG_USB_BELKIN
#undef CONFIG_USB_CDCETHER
//#define CONFIG_USB_CDCETHER /* NYET */
#define CONFIG_USB_EPSON2888 #define CONFIG_USB_EPSON2888
#define CONFIG_USB_GENESYS #define CONFIG_USB_GENESYS
#define CONFIG_USB_NET1080 #define CONFIG_USB_NET1080
#define CONFIG_USB_PL2301 #define CONFIG_USB_PL2301
// #define CONFIG_USB_PXA #define CONFIG_USB_ARMLINUX
#define CONFIG_USB_SA1100
#define CONFIG_USB_ZAURUS #define CONFIG_USB_ZAURUS
#define DRIVER_VERSION "18-Oct-2002" #define DRIVER_VERSION "31-Mar-2003"
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -176,11 +182,11 @@ ...@@ -176,11 +182,11 @@
* Ethernet packets (so queues should be bigger). * Ethernet packets (so queues should be bigger).
*/ */
#ifdef REALLY_QUEUE #ifdef REALLY_QUEUE
#define RX_QLEN 4 #define RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4)
#define TX_QLEN 4 #define TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4)
#else #else
#define RX_QLEN 1 #define RX_QLEN(dev) 1
#define TX_QLEN 1 #define TX_QLEN(dev) 1
#endif #endif
// packets are always ethernet inside // packets are always ethernet inside
...@@ -191,6 +197,10 @@ ...@@ -191,6 +197,10 @@
// reawaken network queue this soon after stopping; else watchdog barks // reawaken network queue this soon after stopping; else watchdog barks
#define TX_TIMEOUT_JIFFIES (5*HZ) #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 // for vendor-specific control operations
#define CONTROL_TIMEOUT_MS (500) /* msec */ #define CONTROL_TIMEOUT_MS (500) /* msec */
#define CONTROL_TIMEOUT_JIFFIES ((CONTROL_TIMEOUT_MS * HZ)/1000) #define CONTROL_TIMEOUT_JIFFIES ((CONTROL_TIMEOUT_MS * HZ)/1000)
...@@ -200,10 +210,6 @@ ...@@ -200,10 +210,6 @@
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
// list of all devices we manage
static DECLARE_MUTEX (usbnet_mutex);
static LIST_HEAD (usbnet_list);
// randomly generated ethernet address // randomly generated ethernet address
static u8 node_id [ETH_ALEN]; static u8 node_id [ETH_ALEN];
...@@ -213,17 +219,18 @@ struct usbnet { ...@@ -213,17 +219,18 @@ struct usbnet {
struct usb_device *udev; struct usb_device *udev;
struct driver_info *driver_info; struct driver_info *driver_info;
struct semaphore mutex; struct semaphore mutex;
struct list_head dev_list;
wait_queue_head_t *wait; wait_queue_head_t *wait;
// i/o info: pipes etc
unsigned in, out;
unsigned maxpacket;
struct timer_list delay;
// protocol/interface state // protocol/interface state
struct net_device net; struct net_device net;
struct net_device_stats stats; struct net_device_stats stats;
int msg_level; int msg_level;
unsigned long data [5];
#ifdef CONFIG_USB_NET1080
u16 packet_id;
#endif
// various kinds of pending driver work // various kinds of pending driver work
struct sk_buff_head rxq; struct sk_buff_head rxq;
...@@ -231,7 +238,7 @@ struct usbnet { ...@@ -231,7 +238,7 @@ struct usbnet {
struct sk_buff_head done; struct sk_buff_head done;
struct tasklet_struct bh; struct tasklet_struct bh;
struct work_struct kevent; struct work_struct kevent;
unsigned long flags; unsigned long flags;
# define EVENT_TX_HALT 0 # define EVENT_TX_HALT 0
# define EVENT_RX_HALT 1 # define EVENT_RX_HALT 1
...@@ -243,11 +250,19 @@ struct driver_info { ...@@ -243,11 +250,19 @@ struct driver_info {
char *description; char *description;
int flags; 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_NC 0x0001 /* guard against device dropouts */
#define FLAG_FRAMING_GL 0x0002 /* genelink batches packets */ #define FLAG_FRAMING_GL 0x0002 /* genelink batches packets */
#define FLAG_FRAMING_Z 0x0004 /* zaurus adds a trailer */ #define FLAG_FRAMING_Z 0x0004 /* zaurus adds a trailer */
#define FLAG_NO_SETINT 0x0010 /* device can't set_interface() */ #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 */ /* reset device ... can sleep */
int (*reset)(struct usbnet *); int (*reset)(struct usbnet *);
...@@ -263,15 +278,13 @@ struct driver_info { ...@@ -263,15 +278,13 @@ struct driver_info {
// FIXME -- also an interrupt mechanism // FIXME -- also an interrupt mechanism
// useful for at least PL2301/2302 and GL620USB-A // 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 in; /* rx endpoint */
int out; /* tx 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 // we record the state for each of our queued skbs
enum skb_state { enum skb_state {
illegal = 0, illegal = 0,
...@@ -300,14 +313,6 @@ MODULE_PARM_DESC (msg_level, "Initial message level (default = 1)"); ...@@ -300,14 +313,6 @@ MODULE_PARM_DESC (msg_level, "Initial message level (default = 1)");
#define RUN_CONTEXT (in_irq () ? "in_irq" \ #define RUN_CONTEXT (in_irq () ? "in_irq" \
: (in_interrupt () ? "in_interrupt" : "can sleep")) : (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 #ifdef DEBUG
#define devdbg(usbnet, fmt, arg...) \ #define devdbg(usbnet, fmt, arg...) \
printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net.name, ## arg) printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net.name, ## arg)
...@@ -315,11 +320,76 @@ static int always_connected (struct usbnet *dev) ...@@ -315,11 +320,76 @@ static int always_connected (struct usbnet *dev)
#define devdbg(usbnet, fmt, arg...) do {} while(0) #define devdbg(usbnet, fmt, arg...) do {} while(0)
#endif #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...) \ #define devinfo(usbnet, fmt, arg...) \
do { if ((usbnet)->msg_level >= 1) \ do { if ((usbnet)->msg_level >= 1) \
printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net.name, ## arg); \ printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net.name, ## arg); \
} while (0) } 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 #ifdef CONFIG_USB_AN2720
...@@ -340,7 +410,6 @@ static const struct driver_info an2720_info = { ...@@ -340,7 +410,6 @@ static const struct driver_info an2720_info = {
// no check_connect available! // no check_connect available!
.in = 2, .out = 2, // direction distinguishes these .in = 2, .out = 2, // direction distinguishes these
.epsize =64,
}; };
#endif /* CONFIG_USB_AN2720 */ #endif /* CONFIG_USB_AN2720 */
...@@ -359,14 +428,225 @@ static const struct driver_info an2720_info = { ...@@ -359,14 +428,225 @@ static const struct driver_info an2720_info = {
static const struct driver_info belkin_info = { static const struct driver_info belkin_info = {
.description = "Belkin, eTEK, or compatible", .description = "Belkin, eTEK, or compatible",
.in = 1, .out = 1, // direction distinguishes these
.epsize =64,
}; };
#endif /* CONFIG_USB_BELKIN */ #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 #ifdef CONFIG_USB_EPSON2888
...@@ -386,7 +666,6 @@ static const struct driver_info epson2888_info = { ...@@ -386,7 +666,6 @@ static const struct driver_info epson2888_info = {
.check_connect = always_connected, .check_connect = always_connected,
.in = 4, .out = 3, .in = 4, .out = 3,
.epsize = 64,
}; };
#endif /* CONFIG_USB_EPSON2888 */ #endif /* CONFIG_USB_EPSON2888 */
...@@ -704,7 +983,7 @@ genelink_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags) ...@@ -704,7 +983,7 @@ genelink_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags)
*packet_len = length; *packet_len = length;
// add padding byte // add padding byte
if ((skb->len % EP_SIZE (dev)) == 0) if ((skb->len % dev->maxpacket) == 0)
skb_put (skb, 1); skb_put (skb, 1);
return skb; return skb;
...@@ -717,7 +996,6 @@ static const struct driver_info genelink_info = { ...@@ -717,7 +996,6 @@ static const struct driver_info genelink_info = {
.tx_fixup = genelink_tx_fixup, .tx_fixup = genelink_tx_fixup,
.in = 1, .out = 2, .in = 1, .out = 2,
.epsize =64,
#ifdef GENELINK_ACK #ifdef GENELINK_ACK
.check_connect =genelink_check_connect, .check_connect =genelink_check_connect,
...@@ -737,6 +1015,9 @@ static const struct driver_info genelink_info = { ...@@ -737,6 +1015,9 @@ static const struct driver_info genelink_info = {
* *
*-------------------------------------------------------------------------*/ *-------------------------------------------------------------------------*/
#define dev_packet_id data[0]
#define frame_errors data[1]
/* /*
* NetChip framing of ethernet packets, supporting additional error * NetChip framing of ethernet packets, supporting additional error
* checks for links that may drop bulk packets from inside messages. * checks for links that may drop bulk packets from inside messages.
...@@ -1064,6 +1345,60 @@ static int net1080_check_connect (struct usbnet *dev) ...@@ -1064,6 +1345,60 @@ static int net1080_check_connect (struct usbnet *dev)
return 0; 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) static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
{ {
struct nc_header *header; struct nc_header *header;
...@@ -1076,6 +1411,7 @@ static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb) ...@@ -1076,6 +1411,7 @@ static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
dbg ("rx framesize %d range %d..%d mtu %d", skb->len, dbg ("rx framesize %d range %d..%d mtu %d", skb->len,
(int)MIN_FRAMED, (int)FRAMED_SIZE (dev->net.mtu), (int)MIN_FRAMED, (int)FRAMED_SIZE (dev->net.mtu),
dev->net.mtu); dev->net.mtu);
nc_ensure_sync (dev);
return 0; return 0;
} }
...@@ -1085,15 +1421,18 @@ static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb) ...@@ -1085,15 +1421,18 @@ static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
if (FRAMED_SIZE (header->packet_len) > MAX_PACKET) { if (FRAMED_SIZE (header->packet_len) > MAX_PACKET) {
dev->stats.rx_frame_errors++; dev->stats.rx_frame_errors++;
dbg ("packet too big, %d", header->packet_len); dbg ("packet too big, %d", header->packet_len);
nc_ensure_sync (dev);
return 0; return 0;
} else if (header->hdr_len < MIN_HEADER) { } else if (header->hdr_len < MIN_HEADER) {
dev->stats.rx_frame_errors++; dev->stats.rx_frame_errors++;
dbg ("header too short, %d", header->hdr_len); dbg ("header too short, %d", header->hdr_len);
nc_ensure_sync (dev);
return 0; return 0;
} else if (header->hdr_len > MIN_HEADER) { } else if (header->hdr_len > MIN_HEADER) {
// out of band data for us? // out of band data for us?
dbg ("header OOB, %d bytes", dbg ("header OOB, %d bytes",
header->hdr_len - MIN_HEADER); header->hdr_len - MIN_HEADER);
nc_ensure_sync (dev);
// switch (vendor/product ids) { ... } // switch (vendor/product ids) { ... }
} }
skb_pull (skb, header->hdr_len); skb_pull (skb, header->hdr_len);
...@@ -1114,6 +1453,7 @@ static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb) ...@@ -1114,6 +1453,7 @@ static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
dev->stats.rx_frame_errors++; dev->stats.rx_frame_errors++;
dbg ("bad packet len %d (expected %d)", dbg ("bad packet len %d (expected %d)",
skb->len, header->packet_len); skb->len, header->packet_len);
nc_ensure_sync (dev);
return 0; return 0;
} }
if (header->packet_id != get_unaligned (&trailer->packet_id)) { if (header->packet_id != get_unaligned (&trailer->packet_id)) {
...@@ -1126,6 +1466,7 @@ static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb) ...@@ -1126,6 +1466,7 @@ static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
devdbg (dev, "frame <rx h %d p %d id %d", header->hdr_len, devdbg (dev, "frame <rx h %d p %d id %d", header->hdr_len,
header->packet_len, header->packet_id); header->packet_len, header->packet_id);
#endif #endif
dev->frame_errors = 0;
return 1; return 1;
} }
...@@ -1143,11 +1484,13 @@ net1080_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags) ...@@ -1143,11 +1484,13 @@ net1080_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags)
if ((padlen + sizeof (struct nc_trailer)) <= tailroom if ((padlen + sizeof (struct nc_trailer)) <= tailroom
&& sizeof (struct nc_header) <= headroom) && sizeof (struct nc_header) <= headroom)
/* There's enough head and tail room */
return skb; return skb;
if ((sizeof (struct nc_header) + padlen if ((sizeof (struct nc_header) + padlen
+ sizeof (struct nc_trailer)) < + sizeof (struct nc_trailer)) <
(headroom + tailroom)) { (headroom + tailroom)) {
/* There's enough total room, so just readjust */
skb->data = memmove (skb->head skb->data = memmove (skb->head
+ sizeof (struct nc_header), + sizeof (struct nc_header),
skb->data, skb->len); skb->data, skb->len);
...@@ -1155,6 +1498,8 @@ net1080_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags) ...@@ -1155,6 +1498,8 @@ net1080_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags)
return skb; return skb;
} }
} }
/* Create a new skb to use with the correct size */
skb2 = skb_copy_expand (skb, skb2 = skb_copy_expand (skb,
sizeof (struct nc_header), sizeof (struct nc_header),
sizeof (struct nc_trailer) + padlen, sizeof (struct nc_trailer) + padlen,
...@@ -1170,9 +1515,6 @@ static const struct driver_info net1080_info = { ...@@ -1170,9 +1515,6 @@ static const struct driver_info net1080_info = {
.check_connect =net1080_check_connect, .check_connect =net1080_check_connect,
.rx_fixup = net1080_rx_fixup, .rx_fixup = net1080_rx_fixup,
.tx_fixup = net1080_tx_fixup, .tx_fixup = net1080_tx_fixup,
.in = 1, .out = 1, // direction distinguishes these
.epsize =64,
}; };
#endif /* CONFIG_USB_NET1080 */ #endif /* CONFIG_USB_NET1080 */
...@@ -1237,37 +1579,13 @@ static const struct driver_info prolific_info = { ...@@ -1237,37 +1579,13 @@ static const struct driver_info prolific_info = {
.flags = FLAG_NO_SETINT, .flags = FLAG_NO_SETINT,
/* some PL-2302 versions seem to fail usb_set_interface() */ /* some PL-2302 versions seem to fail usb_set_interface() */
.reset = pl_reset, .reset = pl_reset,
.in = 3, .out = 2,
.epsize =64,
}; };
#endif /* CONFIG_USB_PL2301 */ #endif /* CONFIG_USB_PL2301 */
#ifdef CONFIG_USB_PXA #ifdef CONFIG_USB_ARMLINUX
/*-------------------------------------------------------------------------
*
* 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
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
...@@ -1279,25 +1597,24 @@ static const struct driver_info pxa_info = { ...@@ -1279,25 +1597,24 @@ static const struct driver_info pxa_info = {
* This describes the driver currently in standard ARM Linux kernels. * This describes the driver currently in standard ARM Linux kernels.
* The Zaurus uses a different driver (see later). * 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 = { static const struct driver_info linuxdev_info = {
.description = "SA-1100 Linux Device", .description = "Linux Device",
.check_connect = always_connected, .check_connect = always_connected,
.in = 2, .out = 1,
.epsize = 64,
}; };
static const struct driver_info yopy_info = { static const struct driver_info yopy_info = {
.description = "Yopy", .description = "Yopy",
.check_connect = always_connected, .check_connect = always_connected,
.in = 2, .out = 1,
.epsize = 64,
}; };
#endif /* CONFIG_USB_SA1100 */ #endif /* CONFIG_USB_ARMLINUX */
#ifdef CONFIG_USB_ZAURUS #ifdef CONFIG_USB_ZAURUS
...@@ -1349,10 +1666,9 @@ static const struct driver_info zaurus_sl5x00_info = { ...@@ -1349,10 +1666,9 @@ static const struct driver_info zaurus_sl5x00_info = {
.description = "Sharp Zaurus SL-5x00", .description = "Sharp Zaurus SL-5x00",
.flags = FLAG_FRAMING_Z, .flags = FLAG_FRAMING_Z,
.check_connect = always_connected, .check_connect = always_connected,
.bind = cdc_bind,
.unbind = cdc_unbind,
.tx_fixup = zaurus_tx_fixup, .tx_fixup = zaurus_tx_fixup,
.in = 2, .out = 1,
.epsize = 64,
}; };
static const struct driver_info zaurus_sla300_info = { static const struct driver_info zaurus_sla300_info = {
.description = "Sharp Zaurus SL-A300", .description = "Sharp Zaurus SL-A300",
...@@ -1361,7 +1677,6 @@ static const struct driver_info zaurus_sla300_info = { ...@@ -1361,7 +1677,6 @@ static const struct driver_info zaurus_sla300_info = {
.tx_fixup = zaurus_tx_fixup, .tx_fixup = zaurus_tx_fixup,
.in = 1, .out = 2, .in = 1, .out = 2,
.epsize = 64,
}; };
static const struct driver_info zaurus_slb500_info = { static const struct driver_info zaurus_slb500_info = {
/* Japanese B500 ~= US SL-5600 */ /* Japanese B500 ~= US SL-5600 */
...@@ -1371,7 +1686,6 @@ static const struct driver_info zaurus_slb500_info = { ...@@ -1371,7 +1686,6 @@ static const struct driver_info zaurus_slb500_info = {
.tx_fixup = zaurus_tx_fixup, .tx_fixup = zaurus_tx_fixup,
.in = 1, .out = 2, .in = 1, .out = 2,
.epsize = 64,
}; };
// SL-5600 and C-700 are PXA based; should resemble A300 // SL-5600 and C-700 are PXA based; should resemble A300
...@@ -1403,7 +1717,7 @@ static int usbnet_change_mtu (struct net_device *net, int new_mtu) ...@@ -1403,7 +1717,7 @@ static int usbnet_change_mtu (struct net_device *net, int new_mtu)
return -EINVAL; return -EINVAL;
#endif #endif
// no second zero-length packet read wanted after mtu-sized packets // 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; return -EDOM;
net->mtu = new_mtu; net->mtu = new_mtu;
return 0; return 0;
...@@ -1444,10 +1758,9 @@ static void defer_kevent (struct usbnet *dev, int work) ...@@ -1444,10 +1758,9 @@ static void defer_kevent (struct usbnet *dev, int work)
{ {
set_bit (work, &dev->flags); set_bit (work, &dev->flags);
if (!schedule_work (&dev->kevent)) if (!schedule_work (&dev->kevent))
err ("%s: kevent %d may have been dropped", deverr (dev, "kevent %d may have been dropped", work);
dev->net.name, work);
else else
dbg ("%s: kevent %d scheduled", dev->net.name, work); devdbg (dev, "kevent %d scheduled", work);
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -1480,7 +1793,7 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags) ...@@ -1480,7 +1793,7 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
size = (sizeof (struct ethhdr) + dev->net.mtu); size = (sizeof (struct ethhdr) + dev->net.mtu);
if ((skb = alloc_skb (size, flags)) == 0) { if ((skb = alloc_skb (size, flags)) == 0) {
dbg ("no rx skb"); devdbg (dev, "no rx skb");
defer_kevent (dev, EVENT_RX_MEMORY); defer_kevent (dev, EVENT_RX_MEMORY);
usb_free_urb (urb); usb_free_urb (urb);
return; return;
...@@ -1492,14 +1805,14 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags) ...@@ -1492,14 +1805,14 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
entry->state = rx_start; entry->state = rx_start;
entry->length = 0; entry->length = 0;
usb_fill_bulk_urb (urb, dev->udev, usb_fill_bulk_urb (urb, dev->udev, dev->in,
usb_rcvbulkpipe (dev->udev, dev->driver_info->in),
skb->data, size, rx_complete, skb); skb->data, size, rx_complete, skb);
urb->transfer_flags |= URB_ASYNC_UNLINK; urb->transfer_flags |= URB_ASYNC_UNLINK;
spin_lock_irqsave (&dev->rxq.lock, lockflags); spin_lock_irqsave (&dev->rxq.lock, lockflags);
if (netif_running (&dev->net) if (netif_running (&dev->net)
&& netif_device_present (&dev->net)
&& !test_bit (EVENT_RX_HALT, &dev->flags)) { && !test_bit (EVENT_RX_HALT, &dev->flags)) {
switch (retval = usb_submit_urb (urb, GFP_ATOMIC)){ switch (retval = usb_submit_urb (urb, GFP_ATOMIC)){
case -EPIPE: case -EPIPE:
...@@ -1508,15 +1821,19 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags) ...@@ -1508,15 +1821,19 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
case -ENOMEM: case -ENOMEM:
defer_kevent (dev, EVENT_RX_MEMORY); defer_kevent (dev, EVENT_RX_MEMORY);
break; break;
case -ENODEV:
devdbg (dev, "device gone");
netif_device_detach (&dev->net);
break;
default: default:
dbg ("%s rx submit, %d", dev->net.name, retval); devdbg (dev, "rx submit, %d", retval);
tasklet_schedule (&dev->bh); tasklet_schedule (&dev->bh);
break; break;
case 0: case 0:
__skb_queue_tail (&dev->rxq, skb); __skb_queue_tail (&dev->rxq, skb);
} }
} else { } else {
dbg ("rx: stopped"); devdbg (dev, "rx: stopped");
retval = -ENOLINK; retval = -ENOLINK;
} }
spin_unlock_irqrestore (&dev->rxq.lock, lockflags); spin_unlock_irqrestore (&dev->rxq.lock, lockflags);
...@@ -1553,7 +1870,7 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb) ...@@ -1553,7 +1870,7 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
if (status != NET_RX_SUCCESS) if (status != NET_RX_SUCCESS)
devdbg (dev, "netif_rx status %d", status); devdbg (dev, "netif_rx status %d", status);
} else { } else {
dbg ("drop"); devdbg (dev, "drop");
error: error:
dev->stats.rx_errors++; dev->stats.rx_errors++;
skb_queue_tail (&dev->done, skb); skb_queue_tail (&dev->done, skb);
...@@ -1580,7 +1897,7 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs) ...@@ -1580,7 +1897,7 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
entry->state = rx_cleanup; entry->state = rx_cleanup;
dev->stats.rx_errors++; dev->stats.rx_errors++;
dev->stats.rx_length_errors++; dev->stats.rx_length_errors++;
dbg ("rx length %d", skb->len); devdbg (dev, "rx length %d", skb->len);
} }
break; break;
...@@ -1589,15 +1906,31 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs) ...@@ -1589,15 +1906,31 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
// we avoid the highspeed version of the ETIMEOUT/EILSEQ // we avoid the highspeed version of the ETIMEOUT/EILSEQ
// storm, recovering as needed. // storm, recovering as needed.
case -EPIPE: case -EPIPE:
dev->stats.rx_errors++;
defer_kevent (dev, EVENT_RX_HALT); defer_kevent (dev, EVENT_RX_HALT);
// FALLTHROUGH // FALLTHROUGH
// software-driven interface shutdown // software-driven interface shutdown
case -ECONNRESET: // according to API spec case -ECONNRESET: // async unlink
case -ECONNABORTED: // some (now fixed?) UHCI bugs case -ESHUTDOWN: // hardware gone
dbg ("%s rx shutdown, code %d", dev->net.name, urb_status); #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; entry->state = rx_cleanup;
// do urb frees only in the tasklet (UHCI has oopsed ...)
entry->urb = urb; entry->urb = urb;
urb = 0; urb = 0;
break; break;
...@@ -1608,12 +1941,9 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs) ...@@ -1608,12 +1941,9 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
// FALLTHROUGH // FALLTHROUGH
default: 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; entry->state = rx_cleanup;
dev->stats.rx_errors++; dev->stats.rx_errors++;
dbg ("%s rx: status %d", dev->net.name, urb_status); devdbg (dev, "rx status %d", urb_status);
break; break;
} }
...@@ -1628,7 +1958,7 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs) ...@@ -1628,7 +1958,7 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
usb_free_urb (urb); usb_free_urb (urb);
} }
#ifdef VERBOSE #ifdef VERBOSE
dbg ("no read resubmitted"); devdbg (dev, "no read resubmitted");
#endif /* VERBOSE */ #endif /* VERBOSE */
} }
...@@ -1636,7 +1966,7 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs) ...@@ -1636,7 +1966,7 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
// unlink pending rx/tx; completion handlers do all other cleanup // 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; unsigned long flags;
struct sk_buff *skb, *skbnext; struct sk_buff *skb, *skbnext;
...@@ -1656,7 +1986,7 @@ static int unlink_urbs (struct sk_buff_head *q) ...@@ -1656,7 +1986,7 @@ static int unlink_urbs (struct sk_buff_head *q)
// these (async) unlinks complete immediately // these (async) unlinks complete immediately
retval = usb_unlink_urb (urb); retval = usb_unlink_urb (urb);
if (retval != -EINPROGRESS && retval != 0) if (retval != -EINPROGRESS && retval != 0)
dbg ("unlink urb err, %d", retval); devdbg (dev, "unlink urb err, %d", retval);
else else
count++; count++;
} }
...@@ -1688,7 +2018,7 @@ static int usbnet_stop (struct net_device *net) ...@@ -1688,7 +2018,7 @@ static int usbnet_stop (struct net_device *net)
// ensure there are no more active urbs // ensure there are no more active urbs
add_wait_queue (&unlink_wakeup, &wait); add_wait_queue (&unlink_wakeup, &wait);
dev->wait = &unlink_wakeup; 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. // maybe wait for deletions to finish.
while (skb_queue_len (&dev->rxq) while (skb_queue_len (&dev->rxq)
...@@ -1696,11 +2026,16 @@ static int usbnet_stop (struct net_device *net) ...@@ -1696,11 +2026,16 @@ static int usbnet_stop (struct net_device *net)
&& skb_queue_len (&dev->done)) { && skb_queue_len (&dev->done)) {
set_current_state (TASK_UNINTERRUPTIBLE); set_current_state (TASK_UNINTERRUPTIBLE);
schedule_timeout (UNLINK_TIMEOUT_JIFFIES); schedule_timeout (UNLINK_TIMEOUT_JIFFIES);
dbg ("waited for %d urb completions", temp); devdbg (dev, "waited for %d urb completions", temp);
} }
dev->wait = 0; dev->wait = 0;
remove_wait_queue (&unlink_wakeup, &wait); 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); mutex_unlock (&dev->mutex);
return 0; return 0;
} }
...@@ -1738,7 +2073,7 @@ static int usbnet_open (struct net_device *net) ...@@ -1738,7 +2073,7 @@ static int usbnet_open (struct net_device *net)
if (dev->msg_level >= 2) if (dev->msg_level >= 2)
devinfo (dev, "open: enable queueing " devinfo (dev, "open: enable queueing "
"(rx %d, tx %d) mtu %d %s framing", "(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 | FLAG_FRAMING_GL))
? ((info->flags & FLAG_FRAMING_NC) ? ((info->flags & FLAG_FRAMING_NC)
? "NetChip" ? "NetChip"
...@@ -1755,7 +2090,8 @@ static int usbnet_open (struct net_device *net) ...@@ -1755,7 +2090,8 @@ static int usbnet_open (struct net_device *net)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
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; struct usbnet *dev = (struct usbnet *) net->priv;
u32 cmd; u32 cmd;
...@@ -1829,9 +2165,8 @@ static int usbnet_ioctl (struct net_device *net, struct ifreq *rq, int cmd) ...@@ -1829,9 +2165,8 @@ static int usbnet_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
/* work that cannot be done in interrupt context uses keventd. /* work that cannot be done in interrupt context uses keventd.
* *
* NOTE: "uhci" and "usb-uhci" may have trouble with this since they don't * NOTE: with 2.5 we could do more of this using completion callbacks,
* queue control transfers to individual devices, and other threads could * especially now that control transfers can be queued.
* trigger control requests concurrently. hope that's rare.
*/ */
static void static void
kevent (void *data) kevent (void *data)
...@@ -1841,24 +2176,22 @@ kevent (void *data) ...@@ -1841,24 +2176,22 @@ kevent (void *data)
/* usb_clear_halt() needs a thread context */ /* usb_clear_halt() needs a thread context */
if (test_bit (EVENT_TX_HALT, &dev->flags)) { if (test_bit (EVENT_TX_HALT, &dev->flags)) {
unlink_urbs (&dev->txq); unlink_urbs (dev, &dev->txq);
status = usb_clear_halt (dev->udev, status = usb_clear_halt (dev->udev, dev->out);
usb_sndbulkpipe (dev->udev, dev->driver_info->out));
if (status < 0) if (status < 0)
err ("%s: can't clear tx halt, status %d", deverr (dev, "can't clear tx halt, status %d",
dev->net.name, status); status);
else { else {
clear_bit (EVENT_TX_HALT, &dev->flags); clear_bit (EVENT_TX_HALT, &dev->flags);
netif_wake_queue (&dev->net); netif_wake_queue (&dev->net);
} }
} }
if (test_bit (EVENT_RX_HALT, &dev->flags)) { if (test_bit (EVENT_RX_HALT, &dev->flags)) {
unlink_urbs (&dev->rxq); unlink_urbs (dev, &dev->rxq);
status = usb_clear_halt (dev->udev, status = usb_clear_halt (dev->udev, dev->in);
usb_rcvbulkpipe (dev->udev, dev->driver_info->in));
if (status < 0) if (status < 0)
err ("%s: can't clear rx halt, status %d", deverr (dev, "can't clear rx halt, status %d",
dev->net.name, status); status);
else { else {
clear_bit (EVENT_RX_HALT, &dev->flags); clear_bit (EVENT_RX_HALT, &dev->flags);
tasklet_schedule (&dev->bh); tasklet_schedule (&dev->bh);
...@@ -1881,8 +2214,8 @@ kevent (void *data) ...@@ -1881,8 +2214,8 @@ kevent (void *data)
} }
if (dev->flags) if (dev->flags)
dbg ("%s: kevent done, flags = 0x%lx", devdbg (dev, "kevent done, flags = 0x%lx",
dev->net.name, dev->flags); dev->flags);
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -1893,8 +2226,35 @@ static void tx_complete (struct urb *urb, struct pt_regs *regs) ...@@ -1893,8 +2226,35 @@ static void tx_complete (struct urb *urb, struct pt_regs *regs)
struct skb_data *entry = (struct skb_data *) skb->cb; struct skb_data *entry = (struct skb_data *) skb->cb;
struct usbnet *dev = entry->dev; struct usbnet *dev = entry->dev;
if (urb->status == -EPIPE) if (urb->status == 0) {
defer_kevent (dev, EVENT_TX_HALT); 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; urb->dev = 0;
entry->state = tx_done; entry->state = tx_done;
defer_bh (dev, skb); defer_bh (dev, skb);
...@@ -1906,7 +2266,7 @@ static void usbnet_tx_timeout (struct net_device *net) ...@@ -1906,7 +2266,7 @@ static void usbnet_tx_timeout (struct net_device *net)
{ {
struct usbnet *dev = (struct usbnet *) net->priv; struct usbnet *dev = (struct usbnet *) net->priv;
unlink_urbs (&dev->txq); unlink_urbs (dev, &dev->txq);
tasklet_schedule (&dev->bh); tasklet_schedule (&dev->bh);
// FIXME: device recovery -- reset? // FIXME: device recovery -- reset?
...@@ -1933,14 +2293,14 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) ...@@ -1933,14 +2293,14 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
if (info->tx_fixup) { if (info->tx_fixup) {
skb = info->tx_fixup (dev, skb, GFP_ATOMIC); skb = info->tx_fixup (dev, skb, GFP_ATOMIC);
if (!skb) { if (!skb) {
dbg ("can't tx_fixup skb"); devdbg (dev, "can't tx_fixup skb");
goto drop; goto drop;
} }
} }
length = skb->len; length = skb->len;
if (!(urb = usb_alloc_urb (0, GFP_ATOMIC))) { if (!(urb = usb_alloc_urb (0, GFP_ATOMIC))) {
dbg ("no urb"); devdbg (dev, "no urb");
goto drop; goto drop;
} }
...@@ -1965,20 +2325,24 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) ...@@ -1965,20 +2325,24 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
} else } else
#endif /* CONFIG_USB_NET1080 */ #endif /* CONFIG_USB_NET1080 */
/* don't assume the hardware handles USB_ZERO_PACKET */ usb_fill_bulk_urb (urb, dev->udev, dev->out,
if ((length % EP_SIZE (dev)) == 0)
skb->len++;
usb_fill_bulk_urb (urb, dev->udev,
usb_sndbulkpipe (dev->udev, info->out),
skb->data, skb->len, tx_complete, skb); skb->data, skb->len, tx_complete, skb);
urb->transfer_flags |= URB_ASYNC_UNLINK; 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); spin_lock_irqsave (&dev->txq.lock, flags);
#ifdef CONFIG_USB_NET1080 #ifdef CONFIG_USB_NET1080
if (info->flags & FLAG_FRAMING_NC) { 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); put_unaligned (header->packet_id, &trailer->packet_id);
#if 0 #if 0
devdbg (dev, "frame >tx h %d p %d id %d", devdbg (dev, "frame >tx h %d p %d id %d",
...@@ -1994,12 +2358,12 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) ...@@ -1994,12 +2358,12 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
defer_kevent (dev, EVENT_TX_HALT); defer_kevent (dev, EVENT_TX_HALT);
break; break;
default: default:
dbg ("%s tx: submit urb err %d", net->name, retval); devdbg (dev, "tx: submit urb err %d", retval);
break; break;
case 0: case 0:
net->trans_start = jiffies; net->trans_start = jiffies;
__skb_queue_tail (&dev->txq, skb); __skb_queue_tail (&dev->txq, skb);
if (dev->txq.qlen >= TX_QLEN) if (dev->txq.qlen >= TX_QLEN (dev))
netif_stop_queue (net); netif_stop_queue (net);
} }
spin_unlock_irqrestore (&dev->txq.lock, flags); spin_unlock_irqrestore (&dev->txq.lock, flags);
...@@ -2024,7 +2388,7 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) ...@@ -2024,7 +2388,7 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
// tasklet ... work that avoided running in_irq() // tasklet (work deferred from completions, in_irq) or timer
static void usbnet_bh (unsigned long param) static void usbnet_bh (unsigned long param)
{ {
...@@ -2040,23 +2404,12 @@ static void usbnet_bh (unsigned long param) ...@@ -2040,23 +2404,12 @@ static void usbnet_bh (unsigned long param)
rx_process (dev, skb); rx_process (dev, skb);
continue; continue;
case tx_done: 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: case rx_cleanup:
usb_free_urb (entry->urb); usb_free_urb (entry->urb);
dev_kfree_skb (skb); dev_kfree_skb (skb);
continue; continue;
default: default:
dbg ("%s: bogus skb state %d", devdbg (dev, "bogus skb state %d", entry->state);
dev->net.name, entry->state);
} }
} }
...@@ -2068,23 +2421,28 @@ static void usbnet_bh (unsigned long param) ...@@ -2068,23 +2421,28 @@ static void usbnet_bh (unsigned long param)
// or are we maybe short a few urbs? // or are we maybe short a few urbs?
} else if (netif_running (&dev->net) } else if (netif_running (&dev->net)
&& netif_device_present (&dev->net)
&& !timer_pending (&dev->delay)
&& !test_bit (EVENT_RX_HALT, &dev->flags)) { && !test_bit (EVENT_RX_HALT, &dev->flags)) {
int temp = dev->rxq.qlen; int temp = dev->rxq.qlen;
int qlen = RX_QLEN (dev);
if (temp < RX_QLEN) { if (temp < qlen) {
struct urb *urb; struct urb *urb;
int i; 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) if ((urb = usb_alloc_urb (0, GFP_ATOMIC)) != 0)
rx_submit (dev, urb, GFP_ATOMIC); rx_submit (dev, urb, GFP_ATOMIC);
} }
if (temp != dev->rxq.qlen) if (temp != dev->rxq.qlen)
devdbg (dev, "rxqlen %d --> %d", devdbg (dev, "rxqlen %d --> %d",
temp, dev->rxq.qlen); temp, dev->rxq.qlen);
if (dev->rxq.qlen < RX_QLEN) if (dev->rxq.qlen < qlen)
tasklet_schedule (&dev->bh); tasklet_schedule (&dev->bh);
} }
if (dev->txq.qlen < TX_QLEN) if (dev->txq.qlen < TX_QLEN (dev))
netif_wake_queue (&dev->net); netif_wake_queue (&dev->net);
} }
} }
...@@ -2117,13 +2475,8 @@ static void usbnet_disconnect (struct usb_interface *intf) ...@@ -2117,13 +2475,8 @@ static void usbnet_disconnect (struct usb_interface *intf)
unregister_netdev (&dev->net); unregister_netdev (&dev->net);
mutex_lock (&usbnet_mutex); if (dev->driver_info->unbind)
mutex_lock (&dev->mutex); dev->driver_info->unbind (dev, intf);
list_del (&dev->dev_list);
mutex_unlock (&usbnet_mutex);
// assuming we used keventd, it must quiesce too
flush_scheduled_work ();
kfree (dev); kfree (dev);
usb_put_dev (xdev); usb_put_dev (xdev);
...@@ -2142,20 +2495,12 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) ...@@ -2142,20 +2495,12 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
struct usb_host_interface *interface; struct usb_host_interface *interface;
struct driver_info *info; struct driver_info *info;
struct usb_device *xdev; struct usb_device *xdev;
int status;
info = (struct driver_info *) prod->driver_info; info = (struct driver_info *) prod->driver_info;
xdev = interface_to_usbdev (udev); xdev = interface_to_usbdev (udev);
interface = &udev->altsetting [udev->act_altsetting]; 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 // set up our own records
if (!(dev = kmalloc (sizeof *dev, GFP_KERNEL))) { if (!(dev = kmalloc (sizeof *dev, GFP_KERNEL))) {
dbg ("can't kmalloc dev"); dbg ("can't kmalloc dev");
...@@ -2168,13 +2513,15 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) ...@@ -2168,13 +2513,15 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
dev->udev = xdev; dev->udev = xdev;
dev->driver_info = info; dev->driver_info = info;
dev->msg_level = msg_level; dev->msg_level = msg_level;
INIT_LIST_HEAD (&dev->dev_list);
skb_queue_head_init (&dev->rxq); skb_queue_head_init (&dev->rxq);
skb_queue_head_init (&dev->txq); skb_queue_head_init (&dev->txq);
skb_queue_head_init (&dev->done); skb_queue_head_init (&dev->done);
dev->bh.func = usbnet_bh; dev->bh.func = usbnet_bh;
dev->bh.data = (unsigned long) dev; dev->bh.data = (unsigned long) dev;
INIT_WORK (&dev->kevent, kevent, 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 // set up network interface records
net = &dev->net; net = &dev->net;
...@@ -2200,31 +2547,41 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) ...@@ -2200,31 +2547,41 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
net->tx_timeout = usbnet_tx_timeout; net->tx_timeout = usbnet_tx_timeout;
net->do_ioctl = usbnet_ioctl; 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); 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, xdev->bus->bus_name, xdev->devpath,
dev->driver_info->description); 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. // ok, it's ready to go.
usb_set_intfdata(udev, dev); usb_set_intfdata (udev, dev);
mutex_lock (&usbnet_mutex);
list_add (&dev->dev_list, &usbnet_list);
mutex_unlock (&dev->mutex); mutex_unlock (&dev->mutex);
// start as if the link is up // start as if the link is up
netif_device_attach (&dev->net); netif_device_attach (&dev->net);
mutex_unlock (&usbnet_mutex);
return 0; return 0;
} }
...@@ -2298,28 +2655,19 @@ static const struct usb_device_id products [] = { ...@@ -2298,28 +2655,19 @@ static const struct usb_device_id products [] = {
}, },
#endif #endif
#ifdef CONFIG_USB_PXA #ifdef CONFIG_USB_ARMLINUX
/*
* 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
/* /*
* SA-1100 using standard ARM Linux kernels, or compatible. * SA-1100 using standard ARM Linux kernels, or compatible.
* Often used when talking to Linux PDAs (iPaq, Yopy, etc). * Often used when talking to Linux PDAs (iPaq, Yopy, etc).
* The sa-1100 "usb-eth" driver handles the basic framing. * 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? // 1183 = 0x049F, both used as hex values?
// Compaq "Itsy" vendor/product id, version "0.0" // Compaq "Itsy" vendor/product id
USB_DEVICE_VER (0x049F, 0x505A, 0, 0), USB_DEVICE (0x049F, 0x505A),
.driver_info = (unsigned long) &linuxdev_info, .driver_info = (unsigned long) &linuxdev_info,
}, { }, {
USB_DEVICE (0x0E7E, 0x1001), // G.Mate "Yopy" USB_DEVICE (0x0E7E, 0x1001), // G.Mate "Yopy"
...@@ -2337,9 +2685,10 @@ static const struct usb_device_id products [] = { ...@@ -2337,9 +2685,10 @@ static const struct usb_device_id products [] = {
| USB_DEVICE_ID_MATCH_DEVICE, | USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x04DD, .idVendor = 0x04DD,
.idProduct = 0x8004, .idProduct = 0x8004,
.bInterfaceClass = 0x0a, /* match the master interface */
.bInterfaceSubClass = 0x00, .bInterfaceClass = USB_CLASS_COMM,
.bInterfaceProtocol = 0x00, .bInterfaceSubClass = 6 /* Ethernet model */,
.bInterfaceProtocol = 0,
.driver_info = (unsigned long) &zaurus_sl5x00_info, .driver_info = (unsigned long) &zaurus_sl5x00_info,
}, { }, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
...@@ -2360,6 +2709,24 @@ static const struct usb_device_id products [] = { ...@@ -2360,6 +2709,24 @@ static const struct usb_device_id products [] = {
.bInterfaceProtocol = 0x00, .bInterfaceProtocol = 0x00,
.driver_info = (unsigned long) &zaurus_slb500_info, .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 #endif
{ }, // END { }, // END
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment