Re: [BUG] USB 3.0 device "lost for good" when in SS.inactive or Compliance Mode during hub_port_reset()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Thanks for the reply, Alan.

The USB device is initially in link state 0, and only after the "cold"
reset in link state SS.inactive. After the following warm reset, it is
in link state 0 again.

> ... but the code is in the wrong place.  The check needs to occur 
> before hub_port_finish_reset, not after.  It's a bug to call 
> hub_port_finish_reset before the retry loop is over; that call should 
> happen after the end of the loop.

Looking at the code, I'd say the hub_port_finish_reset() call is actually
in the _right_ place, because that's where we know that a reset was really
initiated (that step could have errored out) and the reset _try_ should be
finished before the next retry.

What is in the wrong place is coincidentally that code fragment at the
end of hub_port_finish_reset() which I had quoted last time:

>     if (udev)
>         usb_set_device_state(udev, *status
>             ? USB_STATE_NOTATTACHED
>             : USB_STATE_DEFAULT);

That part should be done after the retry loop, because the device state
should not be set based on the result of an "interim" reset result
(especially not when the setting may be irrevocable), but rather based
on the final reset result.

So I moved this code fragment from hub_port_finish_reset() to the end of
hub_port_reset() and made sure it only gets there when a reset attempt
was actually made. The following diff is based on kernel sources 3.19.8:

diff -c -r a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
*** a/drivers/usb/core/hub.c	2015-05-21 00:11:25.000000000 +0200
--- b/drivers/usb/core/hub.c	2015-05-21 00:19:38.471481393 +0200
***************
*** 2736,2745 ****
  			usb_clear_port_feature(hub->hdev, port1,
  					USB_PORT_FEAT_C_CONNECTION);
  		}
- 		if (udev)
- 			usb_set_device_state(udev, *status
- 					? USB_STATE_NOTATTACHED
- 					: USB_STATE_DEFAULT);
  		break;
  	}
  }
--- 2736,2741 ----
***************
*** 2770,2781 ****
  		status = hub_port_status(hub, port1,
  					&portstatus, &portchange);
  		if (status < 0)
! 			goto done;
  
  		if (hub_port_warm_reset_required(hub, port1, portstatus))
  			warm = true;
  	}
  	clear_bit(port1, hub->warm_reset_bits);
  
  	/* Reset the port */
  	for (i = 0; i < PORT_RESET_TRIES; i++) {
--- 2766,2778 ----
  		status = hub_port_status(hub, port1,
  					&portstatus, &portchange);
  		if (status < 0)
! 			return status;
  
  		if (hub_port_warm_reset_required(hub, port1, portstatus))
  			warm = true;
  	}
  	clear_bit(port1, hub->warm_reset_bits);
+ 	status = 0;
  
  	/* Reset the port */
  	for (i = 0; i < PORT_RESET_TRIES; i++) {
***************
*** 2836,2841 ****
--- 2833,2843 ----
  	dev_err(&port_dev->dev, "Cannot enable. Maybe the USB cable is bad?\n");
  
  done:
+ 	if (udev)
+ 		usb_set_device_state(udev, status
+ 				? USB_STATE_NOTATTACHED
+ 				: USB_STATE_DEFAULT);
+ 
  	if (!hub_is_superspeed(hub->hdev))
  		up_read(&ehci_cf_port_reset_rwsem);
  

That also alters the handling of some errors which before the patch caused
hub_port_finish_reset() never to be called and thus the USB device state
not to be altered, but I think it is actually more appropriate to set a
USB device to NOTATTACHED if the reset could not even be initiated, e.g.
because of ENODEV...

It will still leave the USB device state unchanged if it errors out at the
initial "double check" if a warm reset is needed, as the current code
does. It might be more appropriate to just skip the double check rather
than exiting, though...

What do you think, is that an appropriate fix?

Best Regards,
Robert Schlabbach
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux