|
@@ -315,7 +315,7 @@ EXPORT_SYMBOL_GPL(usbnet_defer_kevent);
|
|
|
|
|
|
static void rx_complete (struct urb *urb);
|
|
static void rx_complete (struct urb *urb);
|
|
|
|
|
|
-static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
|
|
|
|
|
|
+static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
|
|
{
|
|
{
|
|
struct sk_buff *skb;
|
|
struct sk_buff *skb;
|
|
struct skb_data *entry;
|
|
struct skb_data *entry;
|
|
@@ -327,7 +327,7 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
|
|
netif_dbg(dev, rx_err, dev->net, "no rx skb\n");
|
|
netif_dbg(dev, rx_err, dev->net, "no rx skb\n");
|
|
usbnet_defer_kevent (dev, EVENT_RX_MEMORY);
|
|
usbnet_defer_kevent (dev, EVENT_RX_MEMORY);
|
|
usb_free_urb (urb);
|
|
usb_free_urb (urb);
|
|
- return;
|
|
|
|
|
|
+ return -ENOMEM;
|
|
}
|
|
}
|
|
skb_reserve (skb, NET_IP_ALIGN);
|
|
skb_reserve (skb, NET_IP_ALIGN);
|
|
|
|
|
|
@@ -357,6 +357,9 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
|
|
netif_dbg(dev, ifdown, dev->net, "device gone\n");
|
|
netif_dbg(dev, ifdown, dev->net, "device gone\n");
|
|
netif_device_detach (dev->net);
|
|
netif_device_detach (dev->net);
|
|
break;
|
|
break;
|
|
|
|
+ case -EHOSTUNREACH:
|
|
|
|
+ retval = -ENOLINK;
|
|
|
|
+ break;
|
|
default:
|
|
default:
|
|
netif_dbg(dev, rx_err, dev->net,
|
|
netif_dbg(dev, rx_err, dev->net,
|
|
"rx submit, %d\n", retval);
|
|
"rx submit, %d\n", retval);
|
|
@@ -374,6 +377,7 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
|
|
dev_kfree_skb_any (skb);
|
|
dev_kfree_skb_any (skb);
|
|
usb_free_urb (urb);
|
|
usb_free_urb (urb);
|
|
}
|
|
}
|
|
|
|
+ return retval;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -912,6 +916,7 @@ fail_halt:
|
|
/* tasklet could resubmit itself forever if memory is tight */
|
|
/* tasklet could resubmit itself forever if memory is tight */
|
|
if (test_bit (EVENT_RX_MEMORY, &dev->flags)) {
|
|
if (test_bit (EVENT_RX_MEMORY, &dev->flags)) {
|
|
struct urb *urb = NULL;
|
|
struct urb *urb = NULL;
|
|
|
|
+ int resched = 1;
|
|
|
|
|
|
if (netif_running (dev->net))
|
|
if (netif_running (dev->net))
|
|
urb = usb_alloc_urb (0, GFP_KERNEL);
|
|
urb = usb_alloc_urb (0, GFP_KERNEL);
|
|
@@ -922,10 +927,12 @@ fail_halt:
|
|
status = usb_autopm_get_interface(dev->intf);
|
|
status = usb_autopm_get_interface(dev->intf);
|
|
if (status < 0)
|
|
if (status < 0)
|
|
goto fail_lowmem;
|
|
goto fail_lowmem;
|
|
- rx_submit (dev, urb, GFP_KERNEL);
|
|
|
|
|
|
+ if (rx_submit (dev, urb, GFP_KERNEL) == -ENOLINK)
|
|
|
|
+ resched = 0;
|
|
usb_autopm_put_interface(dev->intf);
|
|
usb_autopm_put_interface(dev->intf);
|
|
fail_lowmem:
|
|
fail_lowmem:
|
|
- tasklet_schedule (&dev->bh);
|
|
|
|
|
|
+ if (resched)
|
|
|
|
+ tasklet_schedule (&dev->bh);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1175,8 +1182,11 @@ static void usbnet_bh (unsigned long param)
|
|
// don't refill the queue all at once
|
|
// don't refill the queue all at once
|
|
for (i = 0; i < 10 && dev->rxq.qlen < qlen; i++) {
|
|
for (i = 0; i < 10 && dev->rxq.qlen < qlen; i++) {
|
|
urb = usb_alloc_urb (0, GFP_ATOMIC);
|
|
urb = usb_alloc_urb (0, GFP_ATOMIC);
|
|
- if (urb != NULL)
|
|
|
|
- rx_submit (dev, urb, GFP_ATOMIC);
|
|
|
|
|
|
+ if (urb != NULL) {
|
|
|
|
+ if (rx_submit (dev, urb, GFP_ATOMIC) ==
|
|
|
|
+ -ENOLINK)
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
if (temp != dev->rxq.qlen)
|
|
if (temp != dev->rxq.qlen)
|
|
netif_dbg(dev, link, dev->net,
|
|
netif_dbg(dev, link, dev->net,
|