autosuspend for asix driver

Oliver Neukum <[email protected]>
Newsgroups gmane.linux.usb.devel
Organization SuSE Linux
Message-ID <[email protected]>
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/
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.