mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	USB: use "global suspend" for system sleep on USB-2 buses
This patch (as1674) speeds up system sleep transitions by not suspending each individual device on a USB-1.1 or USB-2 bus. The devices will automatically go into suspend when their root hubs are suspended (i.e., stop sending out Start-Of-Frame packets) -- this is what the USB spec calls "global suspend". Since this is what we do already when CONFIG_USB_SUSPEND isn't enabled, it shouldn't cause any problems. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> CC: Peter Chen <peter.chen@freescale.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
		
							parent
							
								
									e9e88fb7bc
								
							
						
					
					
						commit
						0aa2832dd0
					
				
					 1 changed files with 21 additions and 6 deletions
				
			
		| 
						 | 
					@ -2886,9 +2886,11 @@ static int usb_disable_function_remotewakeup(struct usb_device *udev)
 | 
				
			||||||
 * Linux (2.6) currently has NO mechanisms to initiate that:  no khubd
 | 
					 * Linux (2.6) currently has NO mechanisms to initiate that:  no khubd
 | 
				
			||||||
 * timer, no SRP, no requests through sysfs.
 | 
					 * timer, no SRP, no requests through sysfs.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when
 | 
					 * If CONFIG_USB_SUSPEND isn't enabled, non-SuperSpeed devices really get
 | 
				
			||||||
 * the root hub for their bus goes into global suspend ... so we don't
 | 
					 * suspended only when their bus goes into global suspend (i.e., the root
 | 
				
			||||||
 * (falsely) update the device power state to say it suspended.
 | 
					 * hub is suspended).  Nevertheless, we change @udev->state to
 | 
				
			||||||
 | 
					 * USB_STATE_SUSPENDED as this is the device's "logical" state.  The actual
 | 
				
			||||||
 | 
					 * upstream port setting is stored in @udev->port_is_suspended.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Returns 0 on success, else negative errno.
 | 
					 * Returns 0 on success, else negative errno.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -2899,6 +2901,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
 | 
				
			||||||
	enum pm_qos_flags_status pm_qos_stat;
 | 
						enum pm_qos_flags_status pm_qos_stat;
 | 
				
			||||||
	int		port1 = udev->portnum;
 | 
						int		port1 = udev->portnum;
 | 
				
			||||||
	int		status;
 | 
						int		status;
 | 
				
			||||||
 | 
						bool		really_suspend = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* enable remote wakeup when appropriate; this lets the device
 | 
						/* enable remote wakeup when appropriate; this lets the device
 | 
				
			||||||
	 * wake up the upstream hub (including maybe the root hub).
 | 
						 * wake up the upstream hub (including maybe the root hub).
 | 
				
			||||||
| 
						 | 
					@ -2955,9 +2958,19 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
 | 
				
			||||||
	/* see 7.1.7.6 */
 | 
						/* see 7.1.7.6 */
 | 
				
			||||||
	if (hub_is_superspeed(hub->hdev))
 | 
						if (hub_is_superspeed(hub->hdev))
 | 
				
			||||||
		status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U3);
 | 
							status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U3);
 | 
				
			||||||
	else
 | 
						else if (PMSG_IS_AUTO(msg))
 | 
				
			||||||
		status = set_port_feature(hub->hdev, port1,
 | 
							status = set_port_feature(hub->hdev, port1,
 | 
				
			||||||
						USB_PORT_FEAT_SUSPEND);
 | 
											USB_PORT_FEAT_SUSPEND);
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * For system suspend, we do not need to enable the suspend feature
 | 
				
			||||||
 | 
						 * on individual USB-2 ports.  The devices will automatically go
 | 
				
			||||||
 | 
						 * into suspend a few ms after the root hub stops sending packets.
 | 
				
			||||||
 | 
						 * The USB 2.0 spec calls this "global suspend".
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						else {
 | 
				
			||||||
 | 
							really_suspend = false;
 | 
				
			||||||
 | 
							status = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (status) {
 | 
						if (status) {
 | 
				
			||||||
		dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n",
 | 
							dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n",
 | 
				
			||||||
				port1, status);
 | 
									port1, status);
 | 
				
			||||||
| 
						 | 
					@ -2993,8 +3006,10 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
 | 
				
			||||||
				(PMSG_IS_AUTO(msg) ? "auto-" : ""),
 | 
									(PMSG_IS_AUTO(msg) ? "auto-" : ""),
 | 
				
			||||||
				udev->do_remote_wakeup);
 | 
									udev->do_remote_wakeup);
 | 
				
			||||||
		usb_set_device_state(udev, USB_STATE_SUSPENDED);
 | 
							usb_set_device_state(udev, USB_STATE_SUSPENDED);
 | 
				
			||||||
		udev->port_is_suspended = 1;
 | 
							if (really_suspend) {
 | 
				
			||||||
		msleep(10);
 | 
								udev->port_is_suspended = 1;
 | 
				
			||||||
 | 
								msleep(10);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue