Hi,

this implements autosuspend support for the asix subdriver of usbnet.
It works by autoresume when the device is opened and autosuspending when
it is closed. The logic is all put into the generic framework. All
the subdriver has to do is setting the flag.

To support this the suspend() method is changed so that the device is not
reported unready until resumption, as this prevents a new address being
assigned to the device, blocking autoresumption.
This method will have to be revisited if the freezer is removed, but the old
routine is also buggy without the freezer, as it switches the device off
while it may still be used.

It works for me, but I'd like general comments.

        Regards
                Oliver
---

--- a/drivers/net/usb/usbnet.h  2007-07-30 14:23:08.000000000 +0200
+++ b/drivers/net/usb/usbnet.h  2007-07-31 11:08:12.000000000 +0200
@@ -28,6 +28,7 @@
 struct usbnet {
        /* housekeeping */
        struct usb_device       *udev;
+       struct usb_interface    *intf;
        struct driver_info      *driver_info;
        const char              *driver_name;
        wait_queue_head_t       *wait;
--- a/drivers/net/usb/usbnet.c  2007-07-30 14:27:40.000000000 +0200
+++ b/drivers/net/usb/usbnet.c  2007-07-31 11:07:51.000000000 +0200
@@ -590,6 +590,7 @@ static int usbnet_stop (struct net_devic
        dev->flags = 0;
        del_timer_sync (&dev->delay);
        tasklet_kill (&dev->bh);
+       usb_autopm_put_interface(dev->intf);
 
        return 0;
 }
@@ -603,9 +604,19 @@ static int usbnet_stop (struct net_devic
 static int usbnet_open (struct net_device *net)
 {
        struct usbnet           *dev = netdev_priv(net);
-       int                     retval = 0;
+       int                     retval;
        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
        if (info->reset && (retval = info->reset (dev)) < 0) {
                if (netif_msg_ifup (dev))
@@ -659,7 +670,10 @@ static int usbnet_open (struct net_devic
 
        // delay posting reads until we're fully open
        tasklet_schedule (&dev->bh);
+       return retval;
 done:
+       usb_autopm_put_interface(dev->intf);
+done_nopm:
        return retval;
 }
 
@@ -1143,6 +1157,7 @@ usbnet_probe (struct usb_interface *udev
 
        dev = netdev_priv(net);
        dev->udev = xdev;
+       dev->intf = udev;
        dev->driver_info = info;
        dev->driver_name = name;
        dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV
@@ -1273,6 +1288,9 @@ int usbnet_suspend (struct usb_interface
                netif_device_detach (dev->net);
                (void) unlink_urbs (dev, &dev->rxq);
                (void) unlink_urbs (dev, &dev->txq);
+               /* reattach so runtime management can use and
+                * wake the device */
+               netif_device_attach (dev->net);
        }
        return 0;
 }
@@ -1282,10 +1300,9 @@ int usbnet_resume (struct usb_interface 
 {
        struct usbnet           *dev = usb_get_intfdata(intf);
 
-       if (!--dev->suspend_count) {
-               netif_device_attach (dev->net);
+       if (!--dev->suspend_count)
                tasklet_schedule (&dev->bh);
-       }
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(usbnet_resume);
--- a/drivers/net/usb/asix.c    2007-07-30 14:18:38.000000000 +0200
+++ b/drivers/net/usb/asix.c    2007-07-30 16:04:45.000000000 +0200
@@ -844,6 +844,7 @@ static int ax88172_bind(struct usbnet *d
        dev->mii.phy_id_mask = 0x3f;
        dev->mii.reg_num_mask = 0x1f;
        dev->mii.phy_id = asix_get_phy_addr(dev);
+       dev->intf = intf;
        dev->net->do_ioctl = asix_ioctl;
 
        dev->net->set_multicast_list = ax88172_set_multicast;
@@ -969,6 +970,7 @@ static int ax88772_bind(struct usbnet *d
        dev->mii.mdio_write = asix_mdio_write;
        dev->mii.phy_id_mask = 0x1f;
        dev->mii.reg_num_mask = 0x1f;
+       dev->intf = intf;
        dev->net->do_ioctl = asix_ioctl;
        dev->mii.phy_id = asix_get_phy_addr(dev);
 
@@ -1267,6 +1269,7 @@ static int ax88178_bind(struct usbnet *d
        dev->mii.supports_gmii = 1;
        dev->net->do_ioctl = asix_ioctl;
        dev->mii.phy_id = asix_get_phy_addr(dev);
+       dev->intf = intf;
        dev->net->set_multicast_list = asix_set_multicast;
        dev->net->ethtool_ops = &ax88178_ethtool_ops;
        dev->net->change_mtu = &ax88178_change_mtu;
@@ -1474,6 +1477,7 @@ static struct usb_driver asix_driver = {
        .suspend =      usbnet_suspend,
        .resume =       usbnet_resume,
        .disconnect =   usbnet_disconnect,
+       .supports_autosuspend = 1,
 };
 
 static int __init asix_init(void)

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to