Re: [PATCH] [RFC] USB: hub.c: Add the retry count module parameter for usbcore

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

 



On Thu, Jul 30, 2020 at 07:42:26PM +0900, Yasushi Asano wrote:
> From: Yasushi Asano <yasano@xxxxxxxxxxxxxx>
> 
> Dear Alan
> Dear Greg
> 
> I would like to have a consultation with you. The customer's product
> board needs to get a USB certification and compliance, but it can not
> pass the test using the current USB hub driver. According to the USB
> compliance plan[1], the“6.7.22 Device No Response” test requires the
> detection of device enumeration failure within 30 seconds. The
> kernel(USB hub driver) must notify userspace of the enumeration failure
> within 30 seconds.

Odd, we have passed the USB certification tests in the past, what
changed recently to cause this?

> In the current hub driver, the place to detect device enumeration
> failure is [2]. I have modified the hub driver to issue a uevent here,
> but the procedure of device enumeration (new_scheme+old_scheme) takes
> too long to execute, it couldn't reach [2] within 30 seconds after
> starting the test.  According to the result of PETtool [3], the state of
> "Device No response" is that usb_control_msg(USB_REQ_GET_DESCRIPTOR) [4]
> in hub_port_initn times out. That means r == -ETIMEDOUT.  because of the
> default setting of initial_descriptor_timeout is 5000 msec[5],
> usb_control_msg() took 5000msec until -ETIMEDOUT.
> 
> I will try to describe the flow of device enumeration processing
> below[6].  If my understanding is correct, the enumeration failure [2]
> will be reached after performing all the loops of [7][8][9]+[7][10].  In
> the new scheme, 12 times check will be performed ([7]/2*[8]*[9] => 2*2*3
> => 12).  In the old scheme , 4 times check will be performed ([7]/2*[10]
> => 2*2 => 4).  In total, it checks 16 times, and it took 5000msec to
> ETIMEDOUT every time. Therefore, It takes about 80 seconds(16*5000msec)
> to reach [2]. This does not pass the "Device No response" test.
> 
> If I set the module parameter old_schene_first=Y and use_both_schemes=N,
> it can be reached [2] within 30 seconds. However, the new_scheme will no
> longer be performed. I think we can't choose this, as
> previously-detected devices may become undetectable.  new_scheme is
> taking too long and I think 12 times checks are redundant. So, I
> confirmed the USB specification.
> 
> This is the only description of the read of the device descriptor[12].
> I couldn't find the description related retry count or timing here and
> anywhere in this specification.  And I couldn't find the description
> related timing in the “No silent failures" requirements in other
> documents[13] also.
> 
> Because I'm not sure where this number of loop count is decided, I'm not
> sure how should it be modified the driver to pass the USB compliance
> test. Is it possible for me to receive a proposal for a solution?  As my
> thought, the number of loops may be redundant, so I think if the user
> can change it arbitrarily, the problem will be solved. Currently, the
> timeout value can be adjusted with a module parameter, but the loop
> count cannot. Is there any problem if it is changed like this patch?
> The original handling of the driver is unchanged by this modification. I
> think the user will be able to adjust the time to enumeration failure
> freely. Is this patch acceptable? I would appreciate it much if I could
> receive the feedback from you.
> 
> ----------------------------------------------------------------------------------------------------------------------------------------
> [1] https://www.usb.org/sites/default/files/otgeh_compliance_plan_1_2.pdf
> 6.7.22 A-UUT “Device No Response” for connection timeout
> 6.7.22.2 Test Procedure for A-UUT which does not support sessions
>    - 5. If operator clicks OK before 30s elapses since VBUS went on, then UUT passes test.
>    - 6. If 30s elapses first, then UUT fails test.
> ----------------------------------------------------------------------------------------------------------------------------------------
> [2] hub_port_connect()
> 
>         if (hub->hdev->parent ||
>                         !hcd->driver->port_handed_over ||
>                         !(hcd->driver->port_handed_over)(hcd, port1)) {
>                 if (status != -ENOTCONN && status != -ENODEV)
>                         dev_err(&port_dev->dev,
>                                         "unable to enumerate USB device\n");
>         }
> ----------------------------------------------------------------------------------------------------------------------------------------
> [3] http://www.mqp.com/usbcomp.htm
> ----------------------------------------------------------------------------------------------------------------------------------------
> [4] hub_port_init()
> 
>   r = usb_control_msg(udev, usb_rcvaddr0pipe(),
>           USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
>           USB_DT_DEVICE << 8, 0,
>           buf, GET_DESCRIPTOR_BUFSIZE,
>           initial_descriptor_timeout);
> ----------------------------------------------------------------------------------------------------------------------------------------
> [5]
> static int initial_descriptor_timeout = USB_CTRL_GET_TIMEOUT;
> include/linux/usb.h:#define USB_CTRL_GET_TIMEOUT        5000
> ----------------------------------------------------------------------------------------------------------------------------------------
> [6] The flow of device enumeration processing
> drivers/usb/core/hub.c
> 
> hub_port_connect(){
>        for (x = 0; x < SET_CONFIG_TRIES; x++) {                  ...[7] SET_CONFIG_TRIES is 4 as default setting
>                hub_port_init(){
>                        if( x < 2 ) {
>                              ------ new scheme ------
>                              for ( y= 0; y < 2; ++y ) {          ...[8] 2==GET_DESCRIPTOR_TRIES
>                                     for ( z = 0; z < 3; ++z ) {  ...[9]
>                                            usb_control_msg()     ...[3] ETIMEDOUT(-110) is detected. Timieout value=5000msec.
>                                     }
>                              }
>                        }
>                        else {
>                              ------ old scheme ------
>                              for ( y= 0; y < 2; ++y ) {          ...[10] 2==SET_ADDRESS_TRIES
>                                     hub_set_address()            ...[11] ETIMEDOUT(-110) is detected. Timieout value=5000msec.
>                              }
>                        }
>                }
>        }
>        unable to enumerate USB device.                           ...[2]
> }
> ----------------------------------------------------------------------------------------------------------------------------------------
> [12] https://www.usb.org/document-library/usb-20-specification
> Universal Serial Bus Specification (usb_20.pdf)
> 9.1.2 Bus Enumeration
> 6. Before the USB device receives a unique address, its Default Control Pipe is still accessible via the default address.
>    The host reads the device descriptor to determine what actual maximum data payload size this USB device's default pipe can use.
> ----------------------------------------------------------------------------------------------------------------------------------------
> [13] https://www.usb.org/document-library/usb-20-specification
> On-The-Go and Embedded Host Supplement to the USB Revision 2.0 Specification (USB_OTG_and_EH_2-0-version 1_1a.pdf)
> 3.5 No Silent Failures
> ----------------------------------------------------------------------------------------------------------------------------------------
> 
> Signed-off-by: Yasushi Asano <yasano@xxxxxxxxxxxxxx>
> ---
>  drivers/usb/core/hub.c | 17 +++++++++++++++--
>  1 file changed, 15 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
> index 052d5ac..01c2b2d 100644
> --- a/drivers/usb/core/hub.c
> +++ b/drivers/usb/core/hub.c
> @@ -99,6 +99,18 @@ MODULE_PARM_DESC(use_both_schemes,
>  		"try the other device initialization scheme if the "
>  		"first one fails");
>  
> +static int get_descriptor_tries = 2;
> +module_param(get_descriptor_tries, int, S_IRUGO | S_IWUSR);
> +MODULE_PARM_DESC(get_descriptor_tries,
> +		"The number of a 64-byte GET_DESCRIPTOR request tries "
> +		"(default 2)");
> +
> +static int get_descriptor_operations = 3;
> +module_param(get_descriptor_operations, int, S_IRUGO | S_IWUSR);
> +MODULE_PARM_DESC(get_descriptor_operations,
> +		"The number of a 64-byte GET_DESCRIPTOR operation "
> +		"(default 3)");
> +
>  /* Mutual exclusion for EHCI CF initialization.  This interferes with
>   * port reset on some companion controllers.
>   */
> @@ -2707,7 +2719,8 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
>  
>  #define PORT_RESET_TRIES	5
>  #define SET_ADDRESS_TRIES	2
> -#define GET_DESCRIPTOR_TRIES	2
> +#define GET_DESCRIPTOR_TRIES	get_descriptor_tries
> +#define GET_DESCRIPTOR_OPERATIONS	get_descriptor_operations

No need for these defines now that you have a variable being used,
right?

>  #define SET_CONFIG_TRIES	(2 * (use_both_schemes + 1))
>  #define USE_NEW_SCHEME(i, scheme)	((i) / 2 == (int)(scheme))
>  
> @@ -4684,7 +4697,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
>  			 * 255 is for WUSB devices, we actually need to use
>  			 * 512 (WUSB1.0[4.8.1]).
>  			 */
> -			for (operations = 0; operations < 3; ++operations) {
> +			for (operations = 0; operations < GET_DESCRIPTOR_OPERATIONS; ++operations) {

module parameters are not ok, they work for all devices/hubs in the
system, and no one knows how to change them or not.

Any other way we can "just always do it correctly" here?

thanks,

greg k-h



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

  Powered by Linux