|
@@ -2587,13 +2587,20 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
|
|
/* Is a USB 3.0 port in the Inactive or Compliance Mode state?
|
|
/* Is a USB 3.0 port in the Inactive or Compliance Mode state?
|
|
* Port worm reset is required to recover
|
|
* Port worm reset is required to recover
|
|
*/
|
|
*/
|
|
-static bool hub_port_warm_reset_required(struct usb_hub *hub, u16 portstatus)
|
|
|
|
|
|
+static bool hub_port_warm_reset_required(struct usb_hub *hub, int port1,
|
|
|
|
+ u16 portstatus)
|
|
{
|
|
{
|
|
- return hub_is_superspeed(hub->hdev) &&
|
|
|
|
- (((portstatus & USB_PORT_STAT_LINK_STATE) ==
|
|
|
|
- USB_SS_PORT_LS_SS_INACTIVE) ||
|
|
|
|
- ((portstatus & USB_PORT_STAT_LINK_STATE) ==
|
|
|
|
- USB_SS_PORT_LS_COMP_MOD)) ;
|
|
|
|
|
|
+ u16 link_state;
|
|
|
|
+
|
|
|
|
+ if (!hub_is_superspeed(hub->hdev))
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ if (test_bit(port1, hub->warm_reset_bits))
|
|
|
|
+ return true;
|
|
|
|
+
|
|
|
|
+ link_state = portstatus & USB_PORT_STAT_LINK_STATE;
|
|
|
|
+ return link_state == USB_SS_PORT_LS_SS_INACTIVE
|
|
|
|
+ || link_state == USB_SS_PORT_LS_COMP_MOD;
|
|
}
|
|
}
|
|
|
|
|
|
static int hub_port_wait_reset(struct usb_hub *hub, int port1,
|
|
static int hub_port_wait_reset(struct usb_hub *hub, int port1,
|
|
@@ -2630,7 +2637,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
|
|
if ((portstatus & USB_PORT_STAT_RESET))
|
|
if ((portstatus & USB_PORT_STAT_RESET))
|
|
return -EBUSY;
|
|
return -EBUSY;
|
|
|
|
|
|
- if (hub_port_warm_reset_required(hub, portstatus))
|
|
|
|
|
|
+ if (hub_port_warm_reset_required(hub, port1, portstatus))
|
|
return -ENOTCONN;
|
|
return -ENOTCONN;
|
|
|
|
|
|
/* Device went away? */
|
|
/* Device went away? */
|
|
@@ -2730,9 +2737,10 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
|
|
if (status < 0)
|
|
if (status < 0)
|
|
goto done;
|
|
goto done;
|
|
|
|
|
|
- if (hub_port_warm_reset_required(hub, portstatus))
|
|
|
|
|
|
+ if (hub_port_warm_reset_required(hub, port1, portstatus))
|
|
warm = true;
|
|
warm = true;
|
|
}
|
|
}
|
|
|
|
+ clear_bit(port1, hub->warm_reset_bits);
|
|
|
|
|
|
/* Reset the port */
|
|
/* Reset the port */
|
|
for (i = 0; i < PORT_RESET_TRIES; i++) {
|
|
for (i = 0; i < PORT_RESET_TRIES; i++) {
|
|
@@ -2769,7 +2777,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
|
|
&portstatus, &portchange) < 0)
|
|
&portstatus, &portchange) < 0)
|
|
goto done;
|
|
goto done;
|
|
|
|
|
|
- if (!hub_port_warm_reset_required(hub, portstatus))
|
|
|
|
|
|
+ if (!hub_port_warm_reset_required(hub, port1,
|
|
|
|
+ portstatus))
|
|
goto done;
|
|
goto done;
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -2856,8 +2865,13 @@ static int check_port_resume_type(struct usb_device *udev,
|
|
{
|
|
{
|
|
struct usb_port *port_dev = hub->ports[port1 - 1];
|
|
struct usb_port *port_dev = hub->ports[port1 - 1];
|
|
|
|
|
|
|
|
+ /* Is a warm reset needed to recover the connection? */
|
|
|
|
+ if (status == 0 && udev->reset_resume
|
|
|
|
+ && hub_port_warm_reset_required(hub, port1, portstatus)) {
|
|
|
|
+ /* pass */;
|
|
|
|
+ }
|
|
/* Is the device still present? */
|
|
/* Is the device still present? */
|
|
- if (status || port_is_suspended(hub, portstatus) ||
|
|
|
|
|
|
+ else if (status || port_is_suspended(hub, portstatus) ||
|
|
!port_is_power_on(hub, portstatus) ||
|
|
!port_is_power_on(hub, portstatus) ||
|
|
!(portstatus & USB_PORT_STAT_CONNECTION)) {
|
|
!(portstatus & USB_PORT_STAT_CONNECTION)) {
|
|
if (status >= 0)
|
|
if (status >= 0)
|
|
@@ -4872,7 +4886,7 @@ static void port_event(struct usb_hub *hub, int port1)
|
|
* Warm reset a USB3 protocol port if it's in
|
|
* Warm reset a USB3 protocol port if it's in
|
|
* SS.Inactive state.
|
|
* SS.Inactive state.
|
|
*/
|
|
*/
|
|
- if (hub_port_warm_reset_required(hub, portstatus)) {
|
|
|
|
|
|
+ if (hub_port_warm_reset_required(hub, port1, portstatus)) {
|
|
dev_dbg(&port_dev->dev, "do warm reset\n");
|
|
dev_dbg(&port_dev->dev, "do warm reset\n");
|
|
if (!udev || !(portstatus & USB_PORT_STAT_CONNECTION)
|
|
if (!udev || !(portstatus & USB_PORT_STAT_CONNECTION)
|
|
|| udev->state == USB_STATE_NOTATTACHED) {
|
|
|| udev->state == USB_STATE_NOTATTACHED) {
|