Commit 5204f427 authored by Oliver Neukum's avatar Oliver Neukum Committed by Greg Kroah-Hartman

[PATCH] USB: make kaweth deal with ENOMEM

this fixes the logic kaweth uses to deal with ENOMEM from
usb_submit_urb(). Using the interrupt endpoint's completion
handller is longer an option because automagic resubmission
has been removed. Thus we use workqueues which can be delayed
so that kswapd can do its job and can use GFP_NOIO which is much
likelier to succeed.
parent 175a917f
......@@ -217,8 +217,10 @@ struct kaweth_device
__u32 status;
int end;
int removed;
int suspend_lowmem;
int suspend_lowmem_rx;
int suspend_lowmem_ctrl;
int linkstate;
struct work_struct lowmem_work;
struct usb_device *dev;
struct net_device *net;
......@@ -477,14 +479,29 @@ static int kaweth_resubmit_rx_urb(struct kaweth_device *, int);
/****************************************************************
int_callback
*****************************************************************/
static void kaweth_resubmit_int_urb(struct kaweth_device *kaweth, int mf)
{
int status;
status = usb_submit_urb (kaweth->irq_urb, mf);
if (unlikely(status == -ENOMEM)) {
kaweth->suspend_lowmem_ctrl = 1;
schedule_delayed_work(&kaweth->lowmem_work, HZ/4);
} else {
kaweth->suspend_lowmem_ctrl = 0;
}
if (status)
err ("can't resubmit intr, %s-%s, status %d",
kaweth->dev->bus->bus_name,
kaweth->dev->devpath, status);
}
static void int_callback(struct urb *u, struct pt_regs *regs)
{
struct kaweth_device *kaweth = u->context;
int act_state, status;
/* we abuse the interrupt urb for rebsubmitting under low memory saving a timer */
if (kaweth->suspend_lowmem)
kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
int act_state;
switch (u->status) {
case 0: /* success */
......@@ -508,13 +525,24 @@ static void int_callback(struct urb *u, struct pt_regs *regs)
kaweth->linkstate = act_state;
}
resubmit:
status = usb_submit_urb (u, SLAB_ATOMIC);
if (status)
err ("can't resubmit intr, %s-%s, status %d",
kaweth->dev->bus->bus_name,
kaweth->dev->devpath, status);
kaweth_resubmit_int_urb(kaweth, GFP_ATOMIC);
}
static void kaweth_resubmit_tl(void *d)
{
struct kaweth_device *kaweth = (struct kaweth_device *)d;
if (kaweth->status | KAWETH_STATUS_CLOSING)
return;
if (kaweth->suspend_lowmem_rx)
kaweth_resubmit_rx_urb(kaweth, GFP_NOIO);
if (kaweth->suspend_lowmem_ctrl)
kaweth_resubmit_int_urb(kaweth, GFP_NOIO);
}
/****************************************************************
* kaweth_resubmit_rx_urb
****************************************************************/
......@@ -534,11 +562,13 @@ static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth,
kaweth->rx_urb->transfer_dma = kaweth->rxbufferhandle;
if((result = usb_submit_urb(kaweth->rx_urb, mem_flags))) {
if (result == -ENOMEM)
kaweth->suspend_lowmem = 1;
if (result == -ENOMEM) {
kaweth->suspend_lowmem_rx = 1;
schedule_delayed_work(&kaweth->lowmem_work, HZ/4);
}
kaweth_err("resubmitting rx_urb %d failed", result);
} else {
kaweth->suspend_lowmem = 0;
kaweth->suspend_lowmem_rx = 0;
}
return result;
......@@ -667,6 +697,13 @@ static int kaweth_close(struct net_device *net)
usb_unlink_urb(kaweth->irq_urb);
usb_unlink_urb(kaweth->rx_urb);
flush_scheduled_work();
/* a scheduled work may have resubmitted,
we hit them again */
usb_unlink_urb(kaweth->irq_urb);
usb_unlink_urb(kaweth->rx_urb);
kaweth->status &= ~KAWETH_STATUS_CLOSING;
return 0;
......@@ -1077,6 +1114,8 @@ static int kaweth_probe(
memset(&kaweth->stats, 0, sizeof(kaweth->stats));
INIT_WORK(&kaweth->lowmem_work, kaweth_resubmit_tl, (void *)kaweth);
SET_MODULE_OWNER(netdev);
usb_set_intfdata(intf, kaweth);
......
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