diff options
Diffstat (limited to 'drivers/usb/core/hub.c')
| -rw-r--r-- | drivers/usb/core/hub.c | 33 | 
1 files changed, 20 insertions, 13 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index dcd78c15f8c..93035d862c6 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2307,14 +2307,10 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)  	}  	/* see 7.1.7.6 */ -	/* Clear PORT_POWER if it's a USB3.0 device connected to USB 3.0 -	 * external hub. -	 * FIXME: this is a temporary workaround to make the system able -	 * to suspend/resume. -	 */ -	if ((hub->hdev->parent != NULL) && hub_is_superspeed(hub->hdev)) -		status = clear_port_feature(hub->hdev, port1, -						USB_PORT_FEAT_POWER); +	if (hub_is_superspeed(hub->hdev)) +		status = set_port_feature(hub->hdev, +				port1 | (USB_SS_PORT_LS_U3 << 3), +				USB_PORT_FEAT_LINK_STATE);  	else  		status = set_port_feature(hub->hdev, port1,  						USB_PORT_FEAT_SUSPEND); @@ -2469,8 +2465,13 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)  	set_bit(port1, hub->busy_bits);  	/* see 7.1.7.7; affects power usage, but not budgeting */ -	status = clear_port_feature(hub->hdev, -			port1, USB_PORT_FEAT_SUSPEND); +	if (hub_is_superspeed(hub->hdev)) +		status = set_port_feature(hub->hdev, +				port1 | (USB_SS_PORT_LS_U0 << 3), +				USB_PORT_FEAT_LINK_STATE); +	else +		status = clear_port_feature(hub->hdev, +				port1, USB_PORT_FEAT_SUSPEND);  	if (status) {  		dev_dbg(hub->intfdev, "can't resume port %d, status %d\n",  				port1, status); @@ -2492,9 +2493,15 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)   SuspendCleared:  	if (status == 0) { -		if (portchange & USB_PORT_STAT_C_SUSPEND) -			clear_port_feature(hub->hdev, port1, -					USB_PORT_FEAT_C_SUSPEND); +		if (hub_is_superspeed(hub->hdev)) { +			if (portchange & USB_PORT_STAT_C_LINK_STATE) +				clear_port_feature(hub->hdev, port1, +					USB_PORT_FEAT_C_PORT_LINK_STATE); +		} else { +			if (portchange & USB_PORT_STAT_C_SUSPEND) +				clear_port_feature(hub->hdev, port1, +						USB_PORT_FEAT_C_SUSPEND); +		}  	}  	clear_bit(port1, hub->busy_bits);  |