Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 349633
b: refs/heads/master
c: 70c37bf
h: refs/heads/master
i:
  349631: 1dc92fb
v: v3
  • Loading branch information
Bjørn Mork authored and David S. Miller committed Jan 30, 2013
1 parent 8b9083d commit ef59a81
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 6cdd20c380eb62eab757c5a6ccc90dac7ecd774b
refs/heads/master: 70c37bf97f2a91accba76080db69144f3b69f736
25 changes: 25 additions & 0 deletions trunk/drivers/net/usb/usbnet.c
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,12 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
unsigned long lockflags;
size_t size = dev->rx_urb_size;

/* prevent rx skb allocation when error ratio is high */
if (test_bit(EVENT_RX_KILL, &dev->flags)) {
usb_free_urb(urb);
return -ENOLINK;
}

skb = __netdev_alloc_skb_ip_align(dev->net, size, flags);
if (!skb) {
netif_dbg(dev, rx_err, dev->net, "no rx skb\n");
Expand Down Expand Up @@ -539,6 +545,17 @@ static void rx_complete (struct urb *urb)
break;
}

/* stop rx if packet error rate is high */
if (++dev->pkt_cnt > 30) {
dev->pkt_cnt = 0;
dev->pkt_err = 0;
} else {
if (state == rx_cleanup)
dev->pkt_err++;
if (dev->pkt_err > 20)
set_bit(EVENT_RX_KILL, &dev->flags);
}

state = defer_bh(dev, skb, &dev->rxq, state);

if (urb) {
Expand Down Expand Up @@ -791,6 +808,11 @@ int usbnet_open (struct net_device *net)
(dev->driver_info->flags & FLAG_FRAMING_AX) ? "ASIX" :
"simple");

/* reset rx error state */
dev->pkt_cnt = 0;
dev->pkt_err = 0;
clear_bit(EVENT_RX_KILL, &dev->flags);

// delay posting reads until we're fully open
tasklet_schedule (&dev->bh);
if (info->manage_power) {
Expand Down Expand Up @@ -1254,6 +1276,9 @@ static void usbnet_bh (unsigned long param)
}
}

/* restart RX again after disabling due to high error rate */
clear_bit(EVENT_RX_KILL, &dev->flags);

// waiting for all pending urbs to complete?
if (dev->wait) {
if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) {
Expand Down
2 changes: 2 additions & 0 deletions trunk/include/linux/usb/usbnet.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ struct usbnet {
wait_queue_head_t *wait;
struct mutex phy_mutex;
unsigned char suspend_count;
unsigned char pkt_cnt, pkt_err;

/* i/o info: pipes etc */
unsigned in, out;
Expand Down Expand Up @@ -70,6 +71,7 @@ struct usbnet {
# define EVENT_DEV_OPEN 7
# define EVENT_DEVICE_REPORT_IDLE 8
# define EVENT_NO_RUNTIME_PM 9
# define EVENT_RX_KILL 10
};

static inline struct usb_driver *driver_of(struct usb_interface *intf)
Expand Down

0 comments on commit ef59a81

Please sign in to comment.