Commit a11a6544 authored by Oliver Neukum's avatar Oliver Neukum Committed by David S. Miller

support for USB autosuspend in the asix driver

this implements support for USB autosuspend in the asix USB ethernet
driver.
Signed-off-by: default avatarOliver Neukum <oneukum@suse.de>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent bc7f75fa
...@@ -1474,6 +1474,7 @@ static struct usb_driver asix_driver = { ...@@ -1474,6 +1474,7 @@ static struct usb_driver asix_driver = {
.suspend = usbnet_suspend, .suspend = usbnet_suspend,
.resume = usbnet_resume, .resume = usbnet_resume,
.disconnect = usbnet_disconnect, .disconnect = usbnet_disconnect,
.supports_autosuspend = 1,
}; };
static int __init asix_init(void) static int __init asix_init(void)
......
...@@ -590,6 +590,7 @@ static int usbnet_stop (struct net_device *net) ...@@ -590,6 +590,7 @@ static int usbnet_stop (struct net_device *net)
dev->flags = 0; dev->flags = 0;
del_timer_sync (&dev->delay); del_timer_sync (&dev->delay);
tasklet_kill (&dev->bh); tasklet_kill (&dev->bh);
usb_autopm_put_interface(dev->intf);
return 0; return 0;
} }
...@@ -603,9 +604,19 @@ static int usbnet_stop (struct net_device *net) ...@@ -603,9 +604,19 @@ static int usbnet_stop (struct net_device *net)
static int usbnet_open (struct net_device *net) static int usbnet_open (struct net_device *net)
{ {
struct usbnet *dev = netdev_priv(net); struct usbnet *dev = netdev_priv(net);
int retval = 0; int retval;
struct driver_info *info = dev->driver_info; struct driver_info *info = dev->driver_info;
if ((retval = usb_autopm_get_interface(dev->intf)) < 0) {
if (netif_msg_ifup (dev))
devinfo (dev,
"resumption fail (%d) usbnet usb-%s-%s, %s",
retval,
dev->udev->bus->bus_name, dev->udev->devpath,
info->description);
goto done_nopm;
}
// put into "known safe" state // put into "known safe" state
if (info->reset && (retval = info->reset (dev)) < 0) { if (info->reset && (retval = info->reset (dev)) < 0) {
if (netif_msg_ifup (dev)) if (netif_msg_ifup (dev))
...@@ -659,7 +670,10 @@ static int usbnet_open (struct net_device *net) ...@@ -659,7 +670,10 @@ static int usbnet_open (struct net_device *net)
// delay posting reads until we're fully open // delay posting reads until we're fully open
tasklet_schedule (&dev->bh); tasklet_schedule (&dev->bh);
return retval;
done: done:
usb_autopm_put_interface(dev->intf);
done_nopm:
return retval; return retval;
} }
...@@ -1143,6 +1157,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) ...@@ -1143,6 +1157,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
dev = netdev_priv(net); dev = netdev_priv(net);
dev->udev = xdev; dev->udev = xdev;
dev->intf = udev;
dev->driver_info = info; dev->driver_info = info;
dev->driver_name = name; dev->driver_name = name;
dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV
...@@ -1267,12 +1282,18 @@ int usbnet_suspend (struct usb_interface *intf, pm_message_t message) ...@@ -1267,12 +1282,18 @@ int usbnet_suspend (struct usb_interface *intf, pm_message_t message)
struct usbnet *dev = usb_get_intfdata(intf); struct usbnet *dev = usb_get_intfdata(intf);
if (!dev->suspend_count++) { if (!dev->suspend_count++) {
/* accelerate emptying of the rx and queues, to avoid /*
* accelerate emptying of the rx and queues, to avoid
* having everything error out. * having everything error out.
*/ */
netif_device_detach (dev->net); netif_device_detach (dev->net);
(void) unlink_urbs (dev, &dev->rxq); (void) unlink_urbs (dev, &dev->rxq);
(void) unlink_urbs (dev, &dev->txq); (void) unlink_urbs (dev, &dev->txq);
/*
* reattach so runtime management can use and
* wake the device
*/
netif_device_attach (dev->net);
} }
return 0; return 0;
} }
...@@ -1282,10 +1303,9 @@ int usbnet_resume (struct usb_interface *intf) ...@@ -1282,10 +1303,9 @@ int usbnet_resume (struct usb_interface *intf)
{ {
struct usbnet *dev = usb_get_intfdata(intf); struct usbnet *dev = usb_get_intfdata(intf);
if (!--dev->suspend_count) { if (!--dev->suspend_count)
netif_device_attach (dev->net);
tasklet_schedule (&dev->bh); tasklet_schedule (&dev->bh);
}
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(usbnet_resume); EXPORT_SYMBOL_GPL(usbnet_resume);
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
struct usbnet { struct usbnet {
/* housekeeping */ /* housekeeping */
struct usb_device *udev; struct usb_device *udev;
struct usb_interface *intf;
struct driver_info *driver_info; struct driver_info *driver_info;
const char *driver_name; const char *driver_name;
wait_queue_head_t *wait; wait_queue_head_t *wait;
......
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