diff options
Diffstat (limited to 'drivers/usb/core')
| -rw-r--r-- | drivers/usb/core/Kconfig | 4 | ||||
| -rw-r--r-- | drivers/usb/core/driver.c | 845 | ||||
| -rw-r--r-- | drivers/usb/core/hcd.c | 13 | ||||
| -rw-r--r-- | drivers/usb/core/hcd.h | 10 | ||||
| -rw-r--r-- | drivers/usb/core/hub.c | 65 | ||||
| -rw-r--r-- | drivers/usb/core/message.c | 1 | ||||
| -rw-r--r-- | drivers/usb/core/usb.c | 35 | ||||
| -rw-r--r-- | drivers/usb/core/usb.h | 49 | 
8 files changed, 410 insertions, 612 deletions
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index ad925946f86..97a819c23ef 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -91,8 +91,8 @@ config USB_DYNAMIC_MINORS  	  If you are unsure about this, say N here.  config USB_SUSPEND -	bool "USB selective suspend/resume and wakeup" -	depends on USB && PM +	bool "USB runtime power management (suspend/resume and wakeup)" +	depends on USB && PM_RUNTIME  	help  	  If you say Y here, you can use driver calls or the sysfs  	  "power/level" file to suspend or resume individual USB diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 638d54693a1..6850ec6576f 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -25,7 +25,7 @@  #include <linux/device.h>  #include <linux/usb.h>  #include <linux/usb/quirks.h> -#include <linux/workqueue.h> +#include <linux/pm_runtime.h>  #include "hcd.h"  #include "usb.h" @@ -221,7 +221,7 @@ static int usb_probe_device(struct device *dev)  {  	struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);  	struct usb_device *udev = to_usb_device(dev); -	int error = -ENODEV; +	int error = 0;  	dev_dbg(dev, "%s\n", __func__); @@ -230,18 +230,23 @@ static int usb_probe_device(struct device *dev)  	/* The device should always appear to be in use  	 * unless the driver suports autosuspend.  	 */ -	udev->pm_usage_cnt = !(udriver->supports_autosuspend); +	if (!udriver->supports_autosuspend) +		error = usb_autoresume_device(udev); -	error = udriver->probe(udev); +	if (!error) +		error = udriver->probe(udev);  	return error;  }  /* called from driver core with dev locked */  static int usb_unbind_device(struct device *dev)  { +	struct usb_device *udev = to_usb_device(dev);  	struct usb_device_driver *udriver = to_usb_device_driver(dev->driver); -	udriver->disconnect(to_usb_device(dev)); +	udriver->disconnect(udev); +	if (!udriver->supports_autosuspend) +		usb_autosuspend_device(udev);  	return 0;  } @@ -293,17 +298,16 @@ static int usb_probe_interface(struct device *dev)  	if (error)  		return error; -	/* Interface "power state" doesn't correspond to any hardware -	 * state whatsoever.  We use it to record when it's bound to -	 * a driver that may start I/0:  it's not frozen/quiesced. -	 */ -	mark_active(intf);  	intf->condition = USB_INTERFACE_BINDING; -	/* The interface should always appear to be in use -	 * unless the driver suports autosuspend. +	/* Bound interfaces are initially active.  They are +	 * runtime-PM-enabled only if the driver has autosuspend support. +	 * They are sensitive to their children's power states.  	 */ -	atomic_set(&intf->pm_usage_cnt, !driver->supports_autosuspend); +	pm_runtime_set_active(dev); +	pm_suspend_ignore_children(dev, false); +	if (driver->supports_autosuspend) +		pm_runtime_enable(dev);  	/* Carry out a deferred switch to altsetting 0 */  	if (intf->needs_altsetting0) { @@ -323,10 +327,14 @@ static int usb_probe_interface(struct device *dev)  	return error;   err: -	mark_quiesced(intf);  	intf->needs_remote_wakeup = 0;  	intf->condition = USB_INTERFACE_UNBOUND;  	usb_cancel_queued_reset(intf); + +	/* Unbound interfaces are always runtime-PM-disabled and -suspended */ +	pm_runtime_disable(dev); +	pm_runtime_set_suspended(dev); +  	usb_autosuspend_device(udev);  	return error;  } @@ -376,9 +384,17 @@ static int usb_unbind_interface(struct device *dev)  	usb_set_intfdata(intf, NULL);  	intf->condition = USB_INTERFACE_UNBOUND; -	mark_quiesced(intf);  	intf->needs_remote_wakeup = 0; +	/* Unbound interfaces are always runtime-PM-disabled and -suspended */ +	pm_runtime_disable(dev); +	pm_runtime_set_suspended(dev); + +	/* Undo any residual pm_autopm_get_interface_* calls */ +	for (r = atomic_read(&intf->pm_usage_cnt); r > 0; --r) +		usb_autopm_put_interface_no_suspend(intf); +	atomic_set(&intf->pm_usage_cnt, 0); +  	if (!error)  		usb_autosuspend_device(udev); @@ -409,7 +425,6 @@ int usb_driver_claim_interface(struct usb_driver *driver,  				struct usb_interface *iface, void *priv)  {  	struct device *dev = &iface->dev; -	struct usb_device *udev = interface_to_usbdev(iface);  	int retval = 0;  	if (dev->driver) @@ -419,11 +434,16 @@ int usb_driver_claim_interface(struct usb_driver *driver,  	usb_set_intfdata(iface, priv);  	iface->needs_binding = 0; -	usb_pm_lock(udev);  	iface->condition = USB_INTERFACE_BOUND; -	mark_active(iface); -	atomic_set(&iface->pm_usage_cnt, !driver->supports_autosuspend); -	usb_pm_unlock(udev); + +	/* Bound interfaces are initially active.  They are +	 * runtime-PM-enabled only if the driver has autosuspend support. +	 * They are sensitive to their children's power states. +	 */ +	pm_runtime_set_active(dev); +	pm_suspend_ignore_children(dev, false); +	if (driver->supports_autosuspend) +		pm_runtime_enable(dev);  	/* if interface was already added, bind now; else let  	 * the future device_add() bind it, bypassing probe() @@ -982,7 +1002,6 @@ static void do_unbind_rebind(struct usb_device *udev, int action)  	}  } -/* Caller has locked udev's pm_mutex */  static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)  {  	struct usb_device_driver	*udriver; @@ -1006,7 +1025,6 @@ static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)  	return status;  } -/* Caller has locked udev's pm_mutex */  static int usb_resume_device(struct usb_device *udev, pm_message_t msg)  {  	struct usb_device_driver	*udriver; @@ -1040,27 +1058,20 @@ static int usb_resume_device(struct usb_device *udev, pm_message_t msg)  	return status;  } -/* Caller has locked intf's usb_device's pm mutex */  static int usb_suspend_interface(struct usb_device *udev,  		struct usb_interface *intf, pm_message_t msg)  {  	struct usb_driver	*driver;  	int			status = 0; -	/* with no hardware, USB interfaces only use FREEZE and ON states */ -	if (udev->state == USB_STATE_NOTATTACHED || !is_active(intf)) -		goto done; - -	/* This can happen; see usb_driver_release_interface() */ -	if (intf->condition == USB_INTERFACE_UNBOUND) +	if (udev->state == USB_STATE_NOTATTACHED || +			intf->condition == USB_INTERFACE_UNBOUND)  		goto done;  	driver = to_usb_driver(intf->dev.driver);  	if (driver->suspend) {  		status = driver->suspend(intf, msg); -		if (status == 0) -			mark_quiesced(intf); -		else if (!(msg.event & PM_EVENT_AUTO)) +		if (status && !(msg.event & PM_EVENT_AUTO))  			dev_err(&intf->dev, "%s error %d\n",  					"suspend", status);  	} else { @@ -1068,7 +1079,6 @@ static int usb_suspend_interface(struct usb_device *udev,  		intf->needs_binding = 1;  		dev_warn(&intf->dev, "no %s for driver %s?\n",  				"suspend", driver->name); -		mark_quiesced(intf);  	}   done: @@ -1076,14 +1086,13 @@ static int usb_suspend_interface(struct usb_device *udev,  	return status;  } -/* Caller has locked intf's usb_device's pm_mutex */  static int usb_resume_interface(struct usb_device *udev,  		struct usb_interface *intf, pm_message_t msg, int reset_resume)  {  	struct usb_driver	*driver;  	int			status = 0; -	if (udev->state == USB_STATE_NOTATTACHED || is_active(intf)) +	if (udev->state == USB_STATE_NOTATTACHED)  		goto done;  	/* Don't let autoresume interfere with unbinding */ @@ -1134,90 +1143,11 @@ static int usb_resume_interface(struct usb_device *udev,  done:  	dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status); -	if (status == 0 && intf->condition == USB_INTERFACE_BOUND) -		mark_active(intf);  	/* Later we will unbind the driver and/or reprobe, if necessary */  	return status;  } -#ifdef	CONFIG_USB_SUSPEND - -/* Internal routine to check whether we may autosuspend a device. */ -static int autosuspend_check(struct usb_device *udev, int reschedule) -{ -	int			i; -	struct usb_interface	*intf; -	unsigned long		suspend_time, j; - -	/* For autosuspend, fail fast if anything is in use or autosuspend -	 * is disabled.  Also fail if any interfaces require remote wakeup -	 * but it isn't available. -	 */ -	if (udev->pm_usage_cnt > 0) -		return -EBUSY; -	if (udev->autosuspend_delay < 0 || udev->autosuspend_disabled) -		return -EPERM; - -	suspend_time = udev->last_busy + udev->autosuspend_delay; -	if (udev->actconfig) { -		for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { -			intf = udev->actconfig->interface[i]; -			if (!is_active(intf)) -				continue; -			if (atomic_read(&intf->pm_usage_cnt) > 0) -				return -EBUSY; -			if (intf->needs_remote_wakeup && -					!udev->do_remote_wakeup) { -				dev_dbg(&udev->dev, "remote wakeup needed " -						"for autosuspend\n"); -				return -EOPNOTSUPP; -			} - -			/* Don't allow autosuspend if the device will need -			 * a reset-resume and any of its interface drivers -			 * doesn't include support. -			 */ -			if (udev->quirks & USB_QUIRK_RESET_RESUME) { -				struct usb_driver *driver; - -				driver = to_usb_driver(intf->dev.driver); -				if (!driver->reset_resume || -				    intf->needs_remote_wakeup) -					return -EOPNOTSUPP; -			} -		} -	} - -	/* If everything is okay but the device hasn't been idle for long -	 * enough, queue a delayed autosuspend request.  If the device -	 * _has_ been idle for long enough and the reschedule flag is set, -	 * likewise queue a delayed (1 second) autosuspend request. -	 */ -	j = jiffies; -	if (time_before(j, suspend_time)) -		reschedule = 1; -	else -		suspend_time = j + HZ; -	if (reschedule) { -		if (!timer_pending(&udev->autosuspend.timer)) { -			queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, -				round_jiffies_up_relative(suspend_time - j)); -		} -		return -EAGAIN; -	} -	return 0; -} - -#else - -static inline int autosuspend_check(struct usb_device *udev, int reschedule) -{ -	return 0; -} - -#endif	/* CONFIG_USB_SUSPEND */ -  /**   * usb_suspend_both - suspend a USB device and its interfaces   * @udev: the usb_device to suspend @@ -1229,27 +1159,12 @@ static inline int autosuspend_check(struct usb_device *udev, int reschedule)   * all the interfaces which were suspended are resumed so that they remain   * in the same state as the device.   * - * If an autosuspend is in progress the routine checks first to make sure - * that neither the device itself or any of its active interfaces is in use - * (pm_usage_cnt is greater than 0).  If they are, the autosuspend fails. - * - * If the suspend succeeds, the routine recursively queues an autosuspend - * request for @udev's parent device, thereby propagating the change up - * the device tree.  If all of the parent's children are now suspended, - * the parent will autosuspend in turn. - * - * The suspend method calls are subject to mutual exclusion under control - * of @udev's pm_mutex.  Many of these calls are also under the protection - * of @udev's device lock (including all requests originating outside the - * USB subsystem), but autosuspend requests generated by a child device or - * interface driver may not be.  Usbcore will insure that the method calls - * do not arrive during bind, unbind, or reset operations.  However, drivers - * must be prepared to handle suspend calls arriving at unpredictable times. - * The only way to block such calls is to do an autoresume (preventing - * autosuspends) while holding @udev's device lock (preventing outside - * suspends). - * - * The caller must hold @udev->pm_mutex. + * Autosuspend requests originating from a child device or an interface + * driver may be made without the protection of @udev's device lock, but + * all other suspend calls will hold the lock.  Usbcore will insure that + * method calls do not arrive during bind, unbind, or reset operations. + * However drivers must be prepared to handle suspend calls arriving at + * unpredictable times.   *   * This routine can run only in process context.   */ @@ -1258,20 +1173,11 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)  	int			status = 0;  	int			i = 0;  	struct usb_interface	*intf; -	struct usb_device	*parent = udev->parent;  	if (udev->state == USB_STATE_NOTATTACHED ||  			udev->state == USB_STATE_SUSPENDED)  		goto done; -	udev->do_remote_wakeup = device_may_wakeup(&udev->dev); - -	if (msg.event & PM_EVENT_AUTO) { -		status = autosuspend_check(udev, 0); -		if (status < 0) -			goto done; -	} -  	/* Suspend all the interfaces and then udev itself */  	if (udev->actconfig) {  		for (; i < udev->actconfig->desc.bNumInterfaces; i++) { @@ -1286,35 +1192,21 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)  	/* If the suspend failed, resume interfaces that did get suspended */  	if (status != 0) { -		pm_message_t msg2; - -		msg2.event = msg.event ^ (PM_EVENT_SUSPEND | PM_EVENT_RESUME); +		msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME);  		while (--i >= 0) {  			intf = udev->actconfig->interface[i]; -			usb_resume_interface(udev, intf, msg2, 0); +			usb_resume_interface(udev, intf, msg, 0);  		} -		/* Try another autosuspend when the interfaces aren't busy */ -		if (msg.event & PM_EVENT_AUTO) -			autosuspend_check(udev, status == -EBUSY); - -	/* If the suspend succeeded then prevent any more URB submissions, -	 * flush any outstanding URBs, and propagate the suspend up the tree. +	/* If the suspend succeeded then prevent any more URB submissions +	 * and flush any outstanding URBs.  	 */  	} else { -		cancel_delayed_work(&udev->autosuspend);  		udev->can_submit = 0;  		for (i = 0; i < 16; ++i) {  			usb_hcd_flush_endpoint(udev, udev->ep_out[i]);  			usb_hcd_flush_endpoint(udev, udev->ep_in[i]);  		} - -		/* If this is just a FREEZE or a PRETHAW, udev might -		 * not really be suspended.  Only true suspends get -		 * propagated up the device tree. -		 */ -		if (parent && udev->state == USB_STATE_SUSPENDED) -			usb_autosuspend_device(parent);  	}   done: @@ -1331,23 +1223,12 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)   * the resume method for @udev and then calls the resume methods for all   * the interface drivers in @udev.   * - * Before starting the resume, the routine calls itself recursively for - * the parent device of @udev, thereby propagating the change up the device - * tree and assuring that @udev will be able to resume.  If the parent is - * unable to resume successfully, the routine fails. - * - * The resume method calls are subject to mutual exclusion under control - * of @udev's pm_mutex.  Many of these calls are also under the protection - * of @udev's device lock (including all requests originating outside the - * USB subsystem), but autoresume requests generated by a child device or - * interface driver may not be.  Usbcore will insure that the method calls - * do not arrive during bind, unbind, or reset operations.  However, drivers - * must be prepared to handle resume calls arriving at unpredictable times. - * The only way to block such calls is to do an autoresume (preventing - * other autoresumes) while holding @udev's device lock (preventing outside - * resumes). - * - * The caller must hold @udev->pm_mutex. + * Autoresume requests originating from a child device or an interface + * driver may be made without the protection of @udev's device lock, but + * all other resume calls will hold the lock.  Usbcore will insure that + * method calls do not arrive during bind, unbind, or reset operations. + * However drivers must be prepared to handle resume calls arriving at + * unpredictable times.   *   * This routine can run only in process context.   */ @@ -1356,48 +1237,18 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)  	int			status = 0;  	int			i;  	struct usb_interface	*intf; -	struct usb_device	*parent = udev->parent; -	cancel_delayed_work(&udev->autosuspend);  	if (udev->state == USB_STATE_NOTATTACHED) {  		status = -ENODEV;  		goto done;  	}  	udev->can_submit = 1; -	/* Propagate the resume up the tree, if necessary */ -	if (udev->state == USB_STATE_SUSPENDED) { -		if (parent) { -			status = usb_autoresume_device(parent); -			if (status == 0) { -				status = usb_resume_device(udev, msg); -				if (status || udev->state == -						USB_STATE_NOTATTACHED) { -					usb_autosuspend_device(parent); - -					/* It's possible usb_resume_device() -					 * failed after the port was -					 * unsuspended, causing udev to be -					 * logically disconnected.  We don't -					 * want usb_disconnect() to autosuspend -					 * the parent again, so tell it that -					 * udev disconnected while still -					 * suspended. */ -					if (udev->state == -							USB_STATE_NOTATTACHED) -						udev->discon_suspended = 1; -				} -			} -		} else { - -			/* We can't progagate beyond the USB subsystem, -			 * so if a root hub's controller is suspended -			 * then we're stuck. */ -			status = usb_resume_device(udev, msg); -		} -	} else if (udev->reset_resume) +	/* Resume the device */ +	if (udev->state == USB_STATE_SUSPENDED || udev->reset_resume)  		status = usb_resume_device(udev, msg); +	/* Resume the interfaces */  	if (status == 0 && udev->actconfig) {  		for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {  			intf = udev->actconfig->interface[i]; @@ -1413,104 +1264,46 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)  	return status;  } -/** - * usb_external_suspend_device - external suspend of a USB device and its interfaces - * @udev: the usb_device to suspend - * @msg: Power Management message describing this state transition - * - * This routine handles external suspend requests: ones not generated - * internally by a USB driver (autosuspend) but rather coming from the user - * (via sysfs) or the PM core (system sleep).  The suspend will be carried - * out regardless of @udev's usage counter or those of its interfaces, - * and regardless of whether or not remote wakeup is enabled.  Of course, - * interface drivers still have the option of failing the suspend (if - * there are unsuspended children, for example). - * - * The caller must hold @udev's device lock. - */ -int usb_external_suspend_device(struct usb_device *udev, pm_message_t msg) -{ -	int	status; - -	do_unbind_rebind(udev, DO_UNBIND); -	usb_pm_lock(udev); -	status = usb_suspend_both(udev, msg); -	usb_pm_unlock(udev); -	return status; -} - -/** - * usb_external_resume_device - external resume of a USB device and its interfaces - * @udev: the usb_device to resume - * @msg: Power Management message describing this state transition - * - * This routine handles external resume requests: ones not generated - * internally by a USB driver (autoresume) but rather coming from the user - * (via sysfs), the PM core (system resume), or the device itself (remote - * wakeup).  @udev's usage counter is unaffected. - * - * The caller must hold @udev's device lock. - */ -int usb_external_resume_device(struct usb_device *udev, pm_message_t msg) -{ -	int	status; - -	usb_pm_lock(udev); -	status = usb_resume_both(udev, msg); -	udev->last_busy = jiffies; -	usb_pm_unlock(udev); -	if (status == 0) -		do_unbind_rebind(udev, DO_REBIND); - -	/* Now that the device is awake, we can start trying to autosuspend -	 * it again. */ -	if (status == 0) -		usb_try_autosuspend_device(udev); -	return status; -} - +/* The device lock is held by the PM core */  int usb_suspend(struct device *dev, pm_message_t msg)  { -	struct usb_device	*udev; - -	udev = to_usb_device(dev); +	struct usb_device	*udev = to_usb_device(dev); -	/* If udev is already suspended, we can skip this suspend and -	 * we should also skip the upcoming system resume.  High-speed -	 * root hubs are an exception; they need to resume whenever the -	 * system wakes up in order for USB-PERSIST port handover to work -	 * properly. -	 */ -	if (udev->state == USB_STATE_SUSPENDED) { -		if (udev->parent || udev->speed != USB_SPEED_HIGH) -			udev->skip_sys_resume = 1; -		return 0; -	} - -	udev->skip_sys_resume = 0; -	return usb_external_suspend_device(udev, msg); +	do_unbind_rebind(udev, DO_UNBIND); +	udev->do_remote_wakeup = device_may_wakeup(&udev->dev); +	return usb_suspend_both(udev, msg);  } +/* The device lock is held by the PM core */  int usb_resume(struct device *dev, pm_message_t msg)  { -	struct usb_device	*udev; +	struct usb_device	*udev = to_usb_device(dev);  	int			status; -	udev = to_usb_device(dev); +	/* For PM complete calls, all we do is rebind interfaces */ +	if (msg.event == PM_EVENT_ON) { +		if (udev->state != USB_STATE_NOTATTACHED) +			do_unbind_rebind(udev, DO_REBIND); +		status = 0; -	/* If udev->skip_sys_resume is set then udev was already suspended -	 * when the system sleep started, so we don't want to resume it -	 * during this system wakeup. +	/* For all other calls, take the device back to full power and +	 * tell the PM core in case it was autosuspended previously.  	 */ -	if (udev->skip_sys_resume) -		return 0; -	status = usb_external_resume_device(udev, msg); +	} else { +		status = usb_resume_both(udev, msg); +		if (status == 0) { +			pm_runtime_disable(dev); +			pm_runtime_set_active(dev); +			pm_runtime_enable(dev); +			udev->last_busy = jiffies; +		} +	}  	/* Avoid PM error messages for devices disconnected while suspended  	 * as we'll display regular disconnect messages just a bit later.  	 */  	if (status == -ENODEV) -		return 0; +		status = 0;  	return status;  } @@ -1560,54 +1353,6 @@ int usb_disable_autosuspend(struct usb_device *udev)  }  EXPORT_SYMBOL_GPL(usb_disable_autosuspend); -/* Internal routine to adjust a device's usage counter and change - * its autosuspend state. - */ -static int usb_autopm_do_device(struct usb_device *udev, int inc_usage_cnt) -{ -	int	status = 0; - -	usb_pm_lock(udev); -	udev->pm_usage_cnt += inc_usage_cnt; -	WARN_ON(udev->pm_usage_cnt < 0); -	if (inc_usage_cnt) -		udev->last_busy = jiffies; -	if (inc_usage_cnt >= 0 && udev->pm_usage_cnt > 0) { -		if (udev->state == USB_STATE_SUSPENDED) -			status = usb_resume_both(udev, PMSG_AUTO_RESUME); -		if (status != 0) -			udev->pm_usage_cnt -= inc_usage_cnt; -		else if (inc_usage_cnt) -			udev->last_busy = jiffies; -	} else if (inc_usage_cnt <= 0 && udev->pm_usage_cnt <= 0) { -		status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND); -	} -	usb_pm_unlock(udev); -	return status; -} - -/* usb_autosuspend_work - callback routine to autosuspend a USB device */ -void usb_autosuspend_work(struct work_struct *work) -{ -	struct usb_device *udev = -		container_of(work, struct usb_device, autosuspend.work); - -	usb_autopm_do_device(udev, 0); -} - -/* usb_autoresume_work - callback routine to autoresume a USB device */ -void usb_autoresume_work(struct work_struct *work) -{ -	struct usb_device *udev = -		container_of(work, struct usb_device, autoresume); - -	/* Wake it up, let the drivers do their thing, and then put it -	 * back to sleep. -	 */ -	if (usb_autopm_do_device(udev, 1) == 0) -		usb_autopm_do_device(udev, -1); -} -  /**   * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces   * @udev: the usb_device to autosuspend @@ -1616,12 +1361,9 @@ void usb_autoresume_work(struct work_struct *work)   * @udev and wants to allow it to autosuspend.  Examples would be when   * @udev's device file in usbfs is closed or after a configuration change.   * - * @udev's usage counter is decremented.  If it or any of the usage counters - * for an active interface is greater than 0, no autosuspend request will be - * queued.  (If an interface driver does not support autosuspend then its - * usage counter is permanently positive.)  Furthermore, if an interface - * driver requires remote-wakeup capability during autosuspend but remote - * wakeup is disabled, the autosuspend will fail. + * @udev's usage counter is decremented; if it drops to 0 and all the + * interfaces are inactive then a delayed autosuspend will be attempted. + * The attempt may fail (see autosuspend_check()).   *   * The caller must hold @udev's device lock.   * @@ -1631,9 +1373,11 @@ void usb_autosuspend_device(struct usb_device *udev)  {  	int	status; -	status = usb_autopm_do_device(udev, -1); -	dev_vdbg(&udev->dev, "%s: cnt %d\n", -			__func__, udev->pm_usage_cnt); +	udev->last_busy = jiffies; +	status = pm_runtime_put_sync(&udev->dev); +	dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n", +			__func__, atomic_read(&udev->dev.power.usage_count), +			status);  }  /** @@ -1643,9 +1387,9 @@ void usb_autosuspend_device(struct usb_device *udev)   * This routine should be called when a core subsystem thinks @udev may   * be ready to autosuspend.   * - * @udev's usage counter left unchanged.  If it or any of the usage counters - * for an active interface is greater than 0, or autosuspend is not allowed - * for any other reason, no autosuspend request will be queued. + * @udev's usage counter left unchanged.  If it is 0 and all the interfaces + * are inactive then an autosuspend will be attempted.  The attempt may + * fail or be delayed.   *   * The caller must hold @udev's device lock.   * @@ -1653,9 +1397,12 @@ void usb_autosuspend_device(struct usb_device *udev)   */  void usb_try_autosuspend_device(struct usb_device *udev)  { -	usb_autopm_do_device(udev, 0); -	dev_vdbg(&udev->dev, "%s: cnt %d\n", -			__func__, udev->pm_usage_cnt); +	int	status; + +	status = pm_runtime_idle(&udev->dev); +	dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n", +			__func__, atomic_read(&udev->dev.power.usage_count), +			status);  }  /** @@ -1664,9 +1411,9 @@ void usb_try_autosuspend_device(struct usb_device *udev)   *   * This routine should be called when a core subsystem wants to use @udev   * and needs to guarantee that it is not suspended.  No autosuspend will - * occur until usb_autosuspend_device is called.  (Note that this will not - * prevent suspend events originating in the PM core.)  Examples would be - * when @udev's device file in usbfs is opened or when a remote-wakeup + * occur until usb_autosuspend_device() is called.  (Note that this will + * not prevent suspend events originating in the PM core.)  Examples would + * be when @udev's device file in usbfs is opened or when a remote-wakeup   * request is received.   *   * @udev's usage counter is incremented to prevent subsequent autosuspends. @@ -1680,42 +1427,14 @@ int usb_autoresume_device(struct usb_device *udev)  {  	int	status; -	status = usb_autopm_do_device(udev, 1); -	dev_vdbg(&udev->dev, "%s: status %d cnt %d\n", -			__func__, status, udev->pm_usage_cnt); -	return status; -} - -/* Internal routine to adjust an interface's usage counter and change - * its device's autosuspend state. - */ -static int usb_autopm_do_interface(struct usb_interface *intf, -		int inc_usage_cnt) -{ -	struct usb_device	*udev = interface_to_usbdev(intf); -	int			status = 0; - -	usb_pm_lock(udev); -	if (intf->condition == USB_INTERFACE_UNBOUND) -		status = -ENODEV; -	else { -		atomic_add(inc_usage_cnt, &intf->pm_usage_cnt); -		udev->last_busy = jiffies; -		if (inc_usage_cnt >= 0 && -				atomic_read(&intf->pm_usage_cnt) > 0) { -			if (udev->state == USB_STATE_SUSPENDED) -				status = usb_resume_both(udev, -						PMSG_AUTO_RESUME); -			if (status != 0) -				atomic_sub(inc_usage_cnt, &intf->pm_usage_cnt); -			else -				udev->last_busy = jiffies; -		} else if (inc_usage_cnt <= 0 && -				atomic_read(&intf->pm_usage_cnt) <= 0) { -			status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND); -		} -	} -	usb_pm_unlock(udev); +	status = pm_runtime_get_sync(&udev->dev); +	if (status < 0) +		pm_runtime_put_sync(&udev->dev); +	dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n", +			__func__, atomic_read(&udev->dev.power.usage_count), +			status); +	if (status > 0) +		status = 0;  	return status;  } @@ -1729,34 +1448,25 @@ static int usb_autopm_do_interface(struct usb_interface *intf,   * closed.   *   * The routine decrements @intf's usage counter.  When the counter reaches - * 0, a delayed autosuspend request for @intf's device is queued.  When - * the delay expires, if @intf->pm_usage_cnt is still <= 0 along with all - * the other usage counters for the sibling interfaces and @intf's - * usb_device, the device and all its interfaces will be autosuspended. - * - * Note that @intf->pm_usage_cnt is owned by the interface driver.  The - * core will not change its value other than the increment and decrement - * in usb_autopm_get_interface and usb_autopm_put_interface.  The driver - * may use this simple counter-oriented discipline or may set the value - * any way it likes. + * 0, a delayed autosuspend request for @intf's device is attempted.  The + * attempt may fail (see autosuspend_check()).   *   * If the driver has set @intf->needs_remote_wakeup then autosuspend will   * take place only if the device's remote-wakeup facility is enabled.   * - * Suspend method calls queued by this routine can arrive at any time - * while @intf is resumed and its usage counter is equal to 0.  They are - * not protected by the usb_device's lock but only by its pm_mutex. - * Drivers must provide their own synchronization. - *   * This routine can run only in process context.   */  void usb_autopm_put_interface(struct usb_interface *intf)  { -	int	status; +	struct usb_device	*udev = interface_to_usbdev(intf); +	int			status; -	status = usb_autopm_do_interface(intf, -1); -	dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", -			__func__, status, atomic_read(&intf->pm_usage_cnt)); +	udev->last_busy = jiffies; +	atomic_dec(&intf->pm_usage_cnt); +	status = pm_runtime_put_sync(&intf->dev); +	dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", +			__func__, atomic_read(&intf->dev.power.usage_count), +			status);  }  EXPORT_SYMBOL_GPL(usb_autopm_put_interface); @@ -1764,11 +1474,11 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface);   * usb_autopm_put_interface_async - decrement a USB interface's PM-usage counter   * @intf: the usb_interface whose counter should be decremented   * - * This routine does essentially the same thing as - * usb_autopm_put_interface(): it decrements @intf's usage counter and - * queues a delayed autosuspend request if the counter is <= 0.  The - * difference is that it does not acquire the device's pm_mutex; - * callers must handle all synchronization issues themselves. + * This routine does much the same thing as usb_autopm_put_interface(): + * It decrements @intf's usage counter and schedules a delayed + * autosuspend request if the counter is <= 0.  The difference is that it + * does not perform any synchronization; callers should hold a private + * lock and handle all synchronization issues themselves.   *   * Typically a driver would call this routine during an URB's completion   * handler, if no more URBs were pending. @@ -1778,28 +1488,58 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface);  void usb_autopm_put_interface_async(struct usb_interface *intf)  {  	struct usb_device	*udev = interface_to_usbdev(intf); +	unsigned long		last_busy;  	int			status = 0; -	if (intf->condition == USB_INTERFACE_UNBOUND) { -		status = -ENODEV; -	} else { -		udev->last_busy = jiffies; -		atomic_dec(&intf->pm_usage_cnt); -		if (udev->autosuspend_disabled || udev->autosuspend_delay < 0) -			status = -EPERM; -		else if (atomic_read(&intf->pm_usage_cnt) <= 0 && -				!timer_pending(&udev->autosuspend.timer)) { -			queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, +	last_busy = udev->last_busy; +	udev->last_busy = jiffies; +	atomic_dec(&intf->pm_usage_cnt); +	pm_runtime_put_noidle(&intf->dev); + +	if (!udev->autosuspend_disabled) { +		/* Optimization: Don't schedule a delayed autosuspend if +		 * the timer is already running and the expiration time +		 * wouldn't change. +		 * +		 * We have to use the interface's timer.  Attempts to +		 * schedule a suspend for the device would fail because +		 * the interface is still active. +		 */ +		if (intf->dev.power.timer_expires == 0 || +				round_jiffies_up(last_busy) != +				round_jiffies_up(jiffies)) { +			status = pm_schedule_suspend(&intf->dev, +					jiffies_to_msecs(  					round_jiffies_up_relative( -						udev->autosuspend_delay)); +						udev->autosuspend_delay)));  		}  	} -	dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", -			__func__, status, atomic_read(&intf->pm_usage_cnt)); +	dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", +			__func__, atomic_read(&intf->dev.power.usage_count), +			status);  }  EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async);  /** + * usb_autopm_put_interface_no_suspend - decrement a USB interface's PM-usage counter + * @intf: the usb_interface whose counter should be decremented + * + * This routine decrements @intf's usage counter but does not carry out an + * autosuspend. + * + * This routine can run in atomic context. + */ +void usb_autopm_put_interface_no_suspend(struct usb_interface *intf) +{ +	struct usb_device	*udev = interface_to_usbdev(intf); + +	udev->last_busy = jiffies; +	atomic_dec(&intf->pm_usage_cnt); +	pm_runtime_put_noidle(&intf->dev); +} +EXPORT_SYMBOL_GPL(usb_autopm_put_interface_no_suspend); + +/**   * usb_autopm_get_interface - increment a USB interface's PM-usage counter   * @intf: the usb_interface whose counter should be incremented   * @@ -1811,25 +1551,8 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async);   * or @intf is unbound.  A typical example would be a character-device   * driver when its device file is opened.   * - * - * The routine increments @intf's usage counter.  (However if the - * autoresume fails then the counter is re-decremented.)  So long as the - * counter is greater than 0, autosuspend will not be allowed for @intf - * or its usb_device.  When the driver is finished using @intf it should - * call usb_autopm_put_interface() to decrement the usage counter and - * queue a delayed autosuspend request (if the counter is <= 0). - * - * - * Note that @intf->pm_usage_cnt is owned by the interface driver.  The - * core will not change its value other than the increment and decrement - * in usb_autopm_get_interface and usb_autopm_put_interface.  The driver - * may use this simple counter-oriented discipline or may set the value - * any way it likes. - * - * Resume method calls generated by this routine can arrive at any time - * while @intf is suspended.  They are not protected by the usb_device's - * lock but only by its pm_mutex.  Drivers must provide their own - * synchronization. + * @intf's usage counter is incremented to prevent subsequent autosuspends. + * However if the autoresume fails then the counter is re-decremented.   *   * This routine can run only in process context.   */ @@ -1837,9 +1560,16 @@ int usb_autopm_get_interface(struct usb_interface *intf)  {  	int	status; -	status = usb_autopm_do_interface(intf, 1); -	dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", -			__func__, status, atomic_read(&intf->pm_usage_cnt)); +	status = pm_runtime_get_sync(&intf->dev); +	if (status < 0) +		pm_runtime_put_sync(&intf->dev); +	else +		atomic_inc(&intf->pm_usage_cnt); +	dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", +			__func__, atomic_read(&intf->dev.power.usage_count), +			status); +	if (status > 0) +		status = 0;  	return status;  }  EXPORT_SYMBOL_GPL(usb_autopm_get_interface); @@ -1849,41 +1579,201 @@ EXPORT_SYMBOL_GPL(usb_autopm_get_interface);   * @intf: the usb_interface whose counter should be incremented   *   * This routine does much the same thing as - * usb_autopm_get_interface(): it increments @intf's usage counter and - * queues an autoresume request if the result is > 0.  The differences - * are that it does not acquire the device's pm_mutex (callers must - * handle all synchronization issues themselves), and it does not - * autoresume the device directly (it only queues a request).  After a - * successful call, the device will generally not yet be resumed. + * usb_autopm_get_interface(): It increments @intf's usage counter and + * queues an autoresume request if the device is suspended.  The + * differences are that it does not perform any synchronization (callers + * should hold a private lock and handle all synchronization issues + * themselves), and it does not autoresume the device directly (it only + * queues a request).  After a successful call, the device may not yet be + * resumed.   *   * This routine can run in atomic context.   */  int usb_autopm_get_interface_async(struct usb_interface *intf)  { -	struct usb_device	*udev = interface_to_usbdev(intf); -	int			status = 0; +	int		status = 0; +	enum rpm_status	s; -	if (intf->condition == USB_INTERFACE_UNBOUND) -		status = -ENODEV; -	else { +	/* Don't request a resume unless the interface is already suspending +	 * or suspended.  Doing so would force a running suspend timer to be +	 * cancelled. +	 */ +	pm_runtime_get_noresume(&intf->dev); +	s = ACCESS_ONCE(intf->dev.power.runtime_status); +	if (s == RPM_SUSPENDING || s == RPM_SUSPENDED) +		status = pm_request_resume(&intf->dev); + +	if (status < 0 && status != -EINPROGRESS) +		pm_runtime_put_noidle(&intf->dev); +	else  		atomic_inc(&intf->pm_usage_cnt); -		if (atomic_read(&intf->pm_usage_cnt) > 0 && -				udev->state == USB_STATE_SUSPENDED) -			queue_work(ksuspend_usb_wq, &udev->autoresume); -	} -	dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", -			__func__, status, atomic_read(&intf->pm_usage_cnt)); +	dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", +			__func__, atomic_read(&intf->dev.power.usage_count), +			status); +	if (status > 0) +		status = 0;  	return status;  }  EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async); -#else +/** + * usb_autopm_get_interface_no_resume - increment a USB interface's PM-usage counter + * @intf: the usb_interface whose counter should be incremented + * + * This routine increments @intf's usage counter but does not carry out an + * autoresume. + * + * This routine can run in atomic context. + */ +void usb_autopm_get_interface_no_resume(struct usb_interface *intf) +{ +	struct usb_device	*udev = interface_to_usbdev(intf); + +	udev->last_busy = jiffies; +	atomic_inc(&intf->pm_usage_cnt); +	pm_runtime_get_noresume(&intf->dev); +} +EXPORT_SYMBOL_GPL(usb_autopm_get_interface_no_resume); + +/* Internal routine to check whether we may autosuspend a device. */ +static int autosuspend_check(struct usb_device *udev) +{ +	int			i; +	struct usb_interface	*intf; +	unsigned long		suspend_time, j; + +	/* Fail if autosuspend is disabled, or any interfaces are in use, or +	 * any interface drivers require remote wakeup but it isn't available. +	 */ +	udev->do_remote_wakeup = device_may_wakeup(&udev->dev); +	if (udev->actconfig) { +		for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { +			intf = udev->actconfig->interface[i]; + +			/* We don't need to check interfaces that are +			 * disabled for runtime PM.  Either they are unbound +			 * or else their drivers don't support autosuspend +			 * and so they are permanently active. +			 */ +			if (intf->dev.power.disable_depth) +				continue; +			if (atomic_read(&intf->dev.power.usage_count) > 0) +				return -EBUSY; +			if (intf->needs_remote_wakeup && +					!udev->do_remote_wakeup) { +				dev_dbg(&udev->dev, "remote wakeup needed " +						"for autosuspend\n"); +				return -EOPNOTSUPP; +			} + +			/* Don't allow autosuspend if the device will need +			 * a reset-resume and any of its interface drivers +			 * doesn't include support or needs remote wakeup. +			 */ +			if (udev->quirks & USB_QUIRK_RESET_RESUME) { +				struct usb_driver *driver; + +				driver = to_usb_driver(intf->dev.driver); +				if (!driver->reset_resume || +						intf->needs_remote_wakeup) +					return -EOPNOTSUPP; +			} +		} +	} + +	/* If everything is okay but the device hasn't been idle for long +	 * enough, queue a delayed autosuspend request. +	 */ +	j = ACCESS_ONCE(jiffies); +	suspend_time = udev->last_busy + udev->autosuspend_delay; +	if (time_before(j, suspend_time)) { +		pm_schedule_suspend(&udev->dev, jiffies_to_msecs( +				round_jiffies_up_relative(suspend_time - j))); +		return -EAGAIN; +	} +	return 0; +} + +static int usb_runtime_suspend(struct device *dev) +{ +	int	status = 0; -void usb_autosuspend_work(struct work_struct *work) -{} +	/* A USB device can be suspended if it passes the various autosuspend +	 * checks.  Runtime suspend for a USB device means suspending all the +	 * interfaces and then the device itself. +	 */ +	if (is_usb_device(dev)) { +		struct usb_device	*udev = to_usb_device(dev); + +		if (autosuspend_check(udev) != 0) +			return -EAGAIN; + +		status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND); + +		/* If an interface fails the suspend, adjust the last_busy +		 * time so that we don't get another suspend attempt right +		 * away. +		 */ +		if (status) { +			udev->last_busy = jiffies + +					(udev->autosuspend_delay == 0 ? +						HZ/2 : 0); +		} + +		/* Prevent the parent from suspending immediately after */ +		else if (udev->parent) { +			udev->parent->last_busy = jiffies; +		} +	} + +	/* Runtime suspend for a USB interface doesn't mean anything. */ +	return status; +} + +static int usb_runtime_resume(struct device *dev) +{ +	/* Runtime resume for a USB device means resuming both the device +	 * and all its interfaces. +	 */ +	if (is_usb_device(dev)) { +		struct usb_device	*udev = to_usb_device(dev); +		int			status; + +		status = usb_resume_both(udev, PMSG_AUTO_RESUME); +		udev->last_busy = jiffies; +		return status; +	} + +	/* Runtime resume for a USB interface doesn't mean anything. */ +	return 0; +} + +static int usb_runtime_idle(struct device *dev) +{ +	/* An idle USB device can be suspended if it passes the various +	 * autosuspend checks.  An idle interface can be suspended at +	 * any time. +	 */ +	if (is_usb_device(dev)) { +		struct usb_device	*udev = to_usb_device(dev); + +		if (autosuspend_check(udev) != 0) +			return 0; +	} + +	pm_runtime_suspend(dev); +	return 0; +} + +static struct dev_pm_ops usb_bus_pm_ops = { +	.runtime_suspend =	usb_runtime_suspend, +	.runtime_resume =	usb_runtime_resume, +	.runtime_idle =		usb_runtime_idle, +}; + +#else -void usb_autoresume_work(struct work_struct *work) -{} +#define usb_bus_pm_ops	(*(struct dev_pm_ops *) NULL)  #endif /* CONFIG_USB_SUSPEND */ @@ -1891,4 +1781,5 @@ struct bus_type usb_bus_type = {  	.name =		"usb",  	.match =	usb_device_match,  	.uevent =	usb_uevent, +	.pm =		&usb_bus_pm_ops,  }; diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index fc4290b6691..b07ba051118 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -39,6 +39,7 @@  #include <linux/platform_device.h>  #include <linux/workqueue.h>  #include <linux/mutex.h> +#include <linux/pm_runtime.h>  #include <linux/usb.h> @@ -1858,6 +1859,10 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)  	return status;  } +#endif	/* CONFIG_PM */ + +#ifdef	CONFIG_USB_SUSPEND +  /* Workqueue routine for root-hub remote wakeup */  static void hcd_resume_work(struct work_struct *work)  { @@ -1884,12 +1889,12 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd)  	spin_lock_irqsave (&hcd_root_hub_lock, flags);  	if (hcd->rh_registered) -		queue_work(ksuspend_usb_wq, &hcd->wakeup_work); +		queue_work(pm_wq, &hcd->wakeup_work);  	spin_unlock_irqrestore (&hcd_root_hub_lock, flags);  }  EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub); -#endif +#endif	/* CONFIG_USB_SUSPEND */  /*-------------------------------------------------------------------------*/ @@ -2034,7 +2039,7 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,  	init_timer(&hcd->rh_timer);  	hcd->rh_timer.function = rh_timer_func;  	hcd->rh_timer.data = (unsigned long) hcd; -#ifdef CONFIG_PM +#ifdef CONFIG_USB_SUSPEND  	INIT_WORK(&hcd->wakeup_work, hcd_resume_work);  #endif  	mutex_init(&hcd->bandwidth_mutex); @@ -2234,7 +2239,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)  	hcd->rh_registered = 0;  	spin_unlock_irq (&hcd_root_hub_lock); -#ifdef CONFIG_PM +#ifdef CONFIG_USB_SUSPEND  	cancel_work_sync(&hcd->wakeup_work);  #endif diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 70a7e490f81..8953ded6954 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -80,7 +80,7 @@ struct usb_hcd {  	struct timer_list	rh_timer;	/* drives root-hub polling */  	struct urb		*status_urb;	/* the current status urb */ -#ifdef CONFIG_PM +#ifdef CONFIG_USB_SUSPEND  	struct work_struct	wakeup_work;	/* for remote wakeup */  #endif @@ -464,16 +464,20 @@ extern int usb_find_interface_driver(struct usb_device *dev,  #define usb_endpoint_out(ep_dir)	(!((ep_dir) & USB_DIR_IN))  #ifdef CONFIG_PM -extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd);  extern void usb_root_hub_lost_power(struct usb_device *rhdev);  extern int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg);  extern int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg); +#endif /* CONFIG_PM */ + +#ifdef CONFIG_USB_SUSPEND +extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd);  #else  static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)  {  	return;  } -#endif /* CONFIG_PM */ +#endif /* CONFIG_USB_SUSPEND */ +  /*   * USB device fs stuff diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 746f26f222a..0e0a190bbd0 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -22,6 +22,7 @@  #include <linux/kthread.h>  #include <linux/mutex.h>  #include <linux/freezer.h> +#include <linux/pm_runtime.h>  #include <asm/uaccess.h>  #include <asm/byteorder.h> @@ -71,7 +72,6 @@ struct usb_hub {  	unsigned		mA_per_port;	/* current for each child */ -	unsigned		init_done:1;  	unsigned		limited_power:1;  	unsigned		quiescing:1;  	unsigned		disconnected:1; @@ -820,7 +820,6 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)  	}   init3:  	hub->quiescing = 0; -	hub->init_done = 1;  	status = usb_submit_urb(hub->urb, GFP_NOIO);  	if (status < 0) @@ -861,11 +860,6 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)  	int i;  	cancel_delayed_work_sync(&hub->init_work); -	if (!hub->init_done) { -		hub->init_done = 1; -		usb_autopm_put_interface_no_suspend( -				to_usb_interface(hub->intfdev)); -	}  	/* khubd and related activity won't re-trigger */  	hub->quiescing = 1; @@ -1405,10 +1399,8 @@ static void recursively_mark_NOTATTACHED(struct usb_device *udev)  		if (udev->children[i])  			recursively_mark_NOTATTACHED(udev->children[i]);  	} -	if (udev->state == USB_STATE_SUSPENDED) { -		udev->discon_suspended = 1; +	if (udev->state == USB_STATE_SUSPENDED)  		udev->active_duration -= jiffies; -	}  	udev->state = USB_STATE_NOTATTACHED;  } @@ -1532,31 +1524,6 @@ static void update_address(struct usb_device *udev, int devnum)  		udev->devnum = devnum;  } -#ifdef	CONFIG_USB_SUSPEND - -static void usb_stop_pm(struct usb_device *udev) -{ -	/* Synchronize with the ksuspend thread to prevent any more -	 * autosuspend requests from being submitted, and decrement -	 * the parent's count of unsuspended children. -	 */ -	usb_pm_lock(udev); -	if (udev->parent && !udev->discon_suspended) -		usb_autosuspend_device(udev->parent); -	usb_pm_unlock(udev); - -	/* Stop any autosuspend or autoresume requests already submitted */ -	cancel_delayed_work_sync(&udev->autosuspend); -	cancel_work_sync(&udev->autoresume); -} - -#else - -static inline void usb_stop_pm(struct usb_device *udev) -{ } - -#endif -  /**   * usb_disconnect - disconnect a device (usbcore-internal)   * @pdev: pointer to device being disconnected @@ -1625,8 +1592,6 @@ void usb_disconnect(struct usb_device **pdev)  	*pdev = NULL;  	spin_unlock_irq(&device_state_lock); -	usb_stop_pm(udev); -  	put_device(&udev->dev);  } @@ -1803,9 +1768,6 @@ int usb_new_device(struct usb_device *udev)  	int err;  	if (udev->parent) { -		/* Increment the parent's count of unsuspended children */ -		usb_autoresume_device(udev->parent); -  		/* Initialize non-root-hub device wakeup to disabled;  		 * device (un)configuration controls wakeup capable  		 * sysfs power/wakeup controls wakeup enabled/disabled @@ -1814,6 +1776,10 @@ int usb_new_device(struct usb_device *udev)  		device_set_wakeup_enable(&udev->dev, 1);  	} +	/* Tell the runtime-PM framework the device is active */ +	pm_runtime_set_active(&udev->dev); +	pm_runtime_enable(&udev->dev); +  	usb_detect_quirks(udev);  	err = usb_enumerate_device(udev);	/* Read descriptors */  	if (err < 0) @@ -1844,7 +1810,8 @@ int usb_new_device(struct usb_device *udev)  fail:  	usb_set_device_state(udev, USB_STATE_NOTATTACHED); -	usb_stop_pm(udev); +	pm_runtime_disable(&udev->dev); +	pm_runtime_set_suspended(&udev->dev);  	return err;  } @@ -2408,8 +2375,11 @@ int usb_remote_wakeup(struct usb_device *udev)  	if (udev->state == USB_STATE_SUSPENDED) {  		dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-"); -		usb_mark_last_busy(udev); -		status = usb_external_resume_device(udev, PMSG_REMOTE_RESUME); +		status = usb_autoresume_device(udev); +		if (status == 0) { +			/* Let the drivers do their thing, then... */ +			usb_autosuspend_device(udev); +		}  	}  	return status;  } @@ -2446,11 +2416,6 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)  	return status;  } -int usb_remote_wakeup(struct usb_device *udev) -{ -	return 0; -} -  #endif  static int hub_suspend(struct usb_interface *intf, pm_message_t msg) @@ -3268,7 +3233,7 @@ static void hub_events(void)  		 * disconnected while waiting for the lock to succeed. */  		usb_lock_device(hdev);  		if (unlikely(hub->disconnected)) -			goto loop2; +			goto loop_disconnected;  		/* If the hub has died, clean up after it */  		if (hdev->state == USB_STATE_NOTATTACHED) { @@ -3428,7 +3393,7 @@ static void hub_events(void)  		 * kick_khubd() and allow autosuspend.  		 */  		usb_autopm_put_interface(intf); - loop2: + loop_disconnected:  		usb_unlock_device(hdev);  		kref_put(&hub->kref, hub_release); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index df73574a9cc..73de41bb254 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1843,7 +1843,6 @@ free_interfaces:  		intf->dev.dma_mask = dev->dev.dma_mask;  		INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);  		device_initialize(&intf->dev); -		mark_quiesced(intf);  		dev_set_name(&intf->dev, "%d-%s:%d.%d",  			dev->bus->busnum, dev->devpath,  			configuration, alt->desc.bInterfaceNumber); diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 0daff0d968b..32966ccdff6 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -49,9 +49,6 @@ const char *usbcore_name = "usbcore";  static int nousb;	/* Disable USB when built into kernel image */ -/* Workqueue for autosuspend and for remote wakeup of root hubs */ -struct workqueue_struct *ksuspend_usb_wq; -  #ifdef	CONFIG_USB_SUSPEND  static int usb_autosuspend_delay = 2;		/* Default delay value,  						 * in seconds */ @@ -264,23 +261,6 @@ static int usb_dev_uevent(struct device *dev, struct kobj_uevent_env *env)  #ifdef	CONFIG_PM -static int ksuspend_usb_init(void) -{ -	/* This workqueue is supposed to be both freezable and -	 * singlethreaded.  Its job doesn't justify running on more -	 * than one CPU. -	 */ -	ksuspend_usb_wq = create_freezeable_workqueue("ksuspend_usbd"); -	if (!ksuspend_usb_wq) -		return -ENOMEM; -	return 0; -} - -static void ksuspend_usb_cleanup(void) -{ -	destroy_workqueue(ksuspend_usb_wq); -} -  /* USB device Power-Management thunks.   * There's no need to distinguish here between quiescing a USB device   * and powering it down; the generic_suspend() routine takes care of @@ -296,7 +276,7 @@ static int usb_dev_prepare(struct device *dev)  static void usb_dev_complete(struct device *dev)  {  	/* Currently used only for rebinding interfaces */ -	usb_resume(dev, PMSG_RESUME);	/* Message event is meaningless */ +	usb_resume(dev, PMSG_ON);	/* FIXME: change to PMSG_COMPLETE */  }  static int usb_dev_suspend(struct device *dev) @@ -342,9 +322,7 @@ static const struct dev_pm_ops usb_device_pm_ops = {  #else -#define ksuspend_usb_init()	0 -#define ksuspend_usb_cleanup()	do {} while (0) -#define usb_device_pm_ops	(*(struct dev_pm_ops *)0) +#define usb_device_pm_ops	(*(struct dev_pm_ops *) NULL)  #endif	/* CONFIG_PM */ @@ -472,9 +450,6 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,  	INIT_LIST_HEAD(&dev->filelist);  #ifdef	CONFIG_PM -	mutex_init(&dev->pm_mutex); -	INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work); -	INIT_WORK(&dev->autoresume, usb_autoresume_work);  	dev->autosuspend_delay = usb_autosuspend_delay * HZ;  	dev->connect_time = jiffies;  	dev->active_duration = -jiffies; @@ -1117,9 +1092,6 @@ static int __init usb_init(void)  	if (retval)  		goto out; -	retval = ksuspend_usb_init(); -	if (retval) -		goto out;  	retval = bus_register(&usb_bus_type);  	if (retval)  		goto bus_register_failed; @@ -1159,7 +1131,7 @@ major_init_failed:  bus_notifier_failed:  	bus_unregister(&usb_bus_type);  bus_register_failed: -	ksuspend_usb_cleanup(); +	usb_debugfs_cleanup();  out:  	return retval;  } @@ -1181,7 +1153,6 @@ static void __exit usb_exit(void)  	usb_hub_cleanup();  	bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);  	bus_unregister(&usb_bus_type); -	ksuspend_usb_cleanup();  	usb_debugfs_cleanup();  } diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 2b74a7f99c4..cd882203ad3 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -55,25 +55,8 @@ extern void usb_major_cleanup(void);  extern int usb_suspend(struct device *dev, pm_message_t msg);  extern int usb_resume(struct device *dev, pm_message_t msg); -extern void usb_autosuspend_work(struct work_struct *work); -extern void usb_autoresume_work(struct work_struct *work);  extern int usb_port_suspend(struct usb_device *dev, pm_message_t msg);  extern int usb_port_resume(struct usb_device *dev, pm_message_t msg); -extern int usb_external_suspend_device(struct usb_device *udev, -		pm_message_t msg); -extern int usb_external_resume_device(struct usb_device *udev, -		pm_message_t msg); -extern int usb_remote_wakeup(struct usb_device *dev); - -static inline void usb_pm_lock(struct usb_device *udev) -{ -	mutex_lock_nested(&udev->pm_mutex, udev->level); -} - -static inline void usb_pm_unlock(struct usb_device *udev) -{ -	mutex_unlock(&udev->pm_mutex); -}  #else @@ -87,14 +70,6 @@ static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg)  	return 0;  } -static inline int usb_remote_wakeup(struct usb_device *udev) -{ -	return 0; -} - -static inline void usb_pm_lock(struct usb_device *udev) {} -static inline void usb_pm_unlock(struct usb_device *udev) {} -  #endif  #ifdef CONFIG_USB_SUSPEND @@ -102,6 +77,7 @@ static inline void usb_pm_unlock(struct usb_device *udev) {}  extern void usb_autosuspend_device(struct usb_device *udev);  extern void usb_try_autosuspend_device(struct usb_device *udev);  extern int usb_autoresume_device(struct usb_device *udev); +extern int usb_remote_wakeup(struct usb_device *dev);  #else @@ -112,9 +88,13 @@ static inline int usb_autoresume_device(struct usb_device *udev)  	return 0;  } +static inline int usb_remote_wakeup(struct usb_device *udev) +{ +	return 0; +} +  #endif -extern struct workqueue_struct *ksuspend_usb_wq;  extern struct bus_type usb_bus_type;  extern struct device_type usb_device_type;  extern struct device_type usb_if_device_type; @@ -144,23 +124,6 @@ static inline int is_usb_device_driver(struct device_driver *drv)  			for_devices;  } -/* Interfaces and their "power state" are owned by usbcore */ - -static inline void mark_active(struct usb_interface *f) -{ -	f->is_active = 1; -} - -static inline void mark_quiesced(struct usb_interface *f) -{ -	f->is_active = 0; -} - -static inline int is_active(const struct usb_interface *f) -{ -	return f->is_active; -} -  /* for labeling diagnostics */  extern const char *usbcore_name;  |