[U-Boot] [PATCH] usb: xhci: Limit transfer length in a single TD

Jaehoon Chung jh80.chung at samsung.com
Fri Nov 18 08:24:47 CET 2016


Hi,

Added Marek as USB maintainer.

On 11/17/2016 01:21 PM, Dongwoo Lee wrote:
> The transfer request exceeding 4032KB (the maximum number of TRBs per
> TD * the maximum size of transfer buffer on TRB) fails on xhci host
> with timed out error or babble error state. This failure occurs when
> accessing large files on USB mass-storage. Currently with xhci as well
> as ehci host, the driver requests maximum 30MB (65536 blks * 512 byte)
> to storage at once. However, xhci cannot handle this request because
> of the reason mentioned above, even though ehci can handle this. Thus,
> transfer request larger than this size should be splitted in order to
> limit the length of data in a single TD.
> 
> Even though the single request is splitted into multiple requests,
> the transfer speed has affected insignificantly in comparison with
> ehci host: 22.6 MB/s on ehci and 22.3 MB/s on xhci for 100MB tranfer.

I don't have USB knowledge..So i wonder that this is correct way.
Have other guys ever seen the similar issue?

> 
> Reported-by: Jaehoon Chung <jh80.chung at samsung.com>
> Signed-off-by: Dongwoo Lee <dwoo08.lee at samsung.com>
> ---
>  drivers/usb/host/xhci.c | 30 +++++++++++++++++++++++++++++-
>  1 file changed, 29 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
> index 3201177..594026e 100644
> --- a/drivers/usb/host/xhci.c
> +++ b/drivers/usb/host/xhci.c
> @@ -907,12 +907,40 @@ static int _xhci_submit_int_msg(struct usb_device *udev, unsigned long pipe,
>  static int _xhci_submit_bulk_msg(struct usb_device *udev, unsigned long pipe,
>  				 void *buffer, int length)
>  {
> +	int ret;
> +	int xfer_max_per_td, xfer_length, buf_pos;
> +
>  	if (usb_pipetype(pipe) != PIPE_BULK) {
>  		printf("non-bulk pipe (type=%lu)", usb_pipetype(pipe));
>  		return -EINVAL;
>  	}
>  
> -	return xhci_bulk_tx(udev, pipe, length, buffer);
> +	/*
> +	 * When transfering data exceeding the maximum number of TRBs per
> +	 * TD (default 64) is requested, the transfer fails with babble
> +	 * error or time out.
> +	 *
> +	 * Thus, huge data transfer should be splitted into multiple TDs.
> +	 */
> +	xfer_max_per_td = TRB_MAX_BUFF_SIZE * (TRBS_PER_SEGMENT - 1);

xfer_ma_per_td is constant? Then why don't define "XFER_MAX_PER_TD"?
Then can remove xfer_max_per_td  variable.

> +
> +	buf_pos = 0;

can be assigned to 0 when buf_pos is defined?

Best Regards,
Jaehoon Chung

> +	do {
> +		if (length > xfer_max_per_td)
> +			xfer_length = xfer_max_per_td;
> +		else
> +			xfer_length = length;
> +
> +		ret = xhci_bulk_tx(udev, pipe, xfer_length, buffer + buf_pos);
> +		if (ret < 0)
> +			return ret;
> +
> +		buf_pos += xfer_length;
> +		length -= xfer_length;
> +
> +	} while (length > 0);
> +
> +	return ret;
>  }
>  
>  /**
> 



More information about the U-Boot mailing list