Re: [RFC 6/9] xHCI 1.0: Soft Retry mechanism

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

 



Hi Andiry and Alex,

I've noticed (although I don't have time to confirm again) that the
NEC/Rensas host controller seems to return these transaction errors
whenever there is a link TRB in the middle of the control transfer TD.
Have you also noticed this?  If so, we should probably let Rensas know,
as it might indicate a hardware bug.  Or it could mean we're doing
something odd in the xHCI driver.

Sarah Sharp

On Thu, May 05, 2011 at 06:14:07PM +0800, Andiry Xu wrote:
> From: Alex He <alex.he@xxxxxxx>
> 
> xHCI 1.0 spec 4.6.8.1 describes Soft Retry mechanism.
> A Soft Retry may effectively be used to recover from a USB Transaction Error
> that was due to a temporary error condition. Oftern the delay introduced
> between software detecting the error and attempting a Soft Retry is enough
> to let the temporary condition clear and allow a successful transfer.
> 
> Signed-off-by: Alex He <alex.he@xxxxxxx>
> Signed-off-by: Andiry Xu <andiry.xu@xxxxxxx>
> ---
>  drivers/usb/host/xhci-ring.c |   70 ++++++++++++++++++++++++++++++++++++++++++
>  drivers/usb/host/xhci.h      |    6 +++
>  2 files changed, 76 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
> index e07162d..d0b8c85 100644
> --- a/drivers/usb/host/xhci-ring.c
> +++ b/drivers/usb/host/xhci-ring.c
> @@ -1645,6 +1645,18 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
>  		if (!xhci_requires_manual_halt_cleanup(xhci,
>  					ep_ctx, trb_comp_code))
>  			break;
> +		if (trb_comp_code == COMP_TX_ERR &&
> +				xhci->hci_version == 0x100) {
> +			if (ep->soft_retries++ < SOFT_RETRY) {
> +				xhci_soft_retry_ep(xhci, slot_id, ep_index,
> +						ep_ring->stream_id, td,
> +						event_trb);
> +				return 0;
> +			} else {
> +				ep->soft_retries = 0;
> +			}
> +		}
> +
>  		xhci_dbg(xhci, "TRB error code %u, "
>  				"halted endpoint index = %u\n",
>  				trb_comp_code, ep_index);
> @@ -1818,10 +1830,21 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
>  	union xhci_trb *event_trb, struct xhci_transfer_event *event,
>  	struct xhci_virt_ep *ep, int *status)
>  {
> +	struct xhci_virt_device *xdev;
> +	unsigned int slot_id;
> +	struct xhci_slot_ctx *slot_ctx;
> +	int ep_index;
>  	struct xhci_ring *ep_ring;
>  	union xhci_trb *cur_trb;
>  	struct xhci_segment *cur_seg;
>  	u32 trb_comp_code;
> +	u32 tt_hub_slot_id;
> +
> +	ep_index = TRB_TO_EP_ID(event->flags) - 1;
> +	slot_id = TRB_TO_SLOT_ID(event->flags);
> +	xdev = xhci->devs[slot_id];
> +	slot_ctx = xhci_get_slot_ctx(xhci, xdev->out_ctx);
> +	tt_hub_slot_id = slot_ctx->tt_info && 0xff;
>  
>  	ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer));
>  	trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
> @@ -1852,6 +1875,25 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
>  		else
>  			*status = 0;
>  		break;
> +	case COMP_TX_ERR:
> +		if (xhci->hci_version == 0x100) {
> +			if (usb_endpoint_xfer_bulk(&td->urb->ep->desc) &&
> +					(ep->soft_retries++ < SOFT_RETRY)) {
> +				xhci_soft_retry_ep(xhci, slot_id, ep_index,
> +					ep_ring->stream_id, td, event_trb);
> +				return 0;
> +
> +			}
> +			if (usb_endpoint_xfer_int(&td->urb->ep->desc) &&
> +					tt_hub_slot_id == 0 &&
> +					(ep->soft_retries++ < SOFT_RETRY)) {
> +				xhci_soft_retry_ep(xhci, slot_id, ep_index,
> +					ep_ring->stream_id, td, event_trb);
> +				return 0;
> +			}
> +			ep->soft_retries = 0;
> +		}
> +		break;
>  	default:
>  		/* Others already handled above */
>  		break;
> @@ -3565,3 +3607,31 @@ int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id,
>  	return queue_command(xhci, 0, 0, 0, trb_slot_id | trb_ep_index | type,
>  			false);
>  }
> +
> +/*
> + * A Soft Retry may effectively be used to recver from a USB Transaction Error
> + * that was due to a temporary error codition. Details in the Chapter 4.6.8.1
> + * NOTE:
> + * 1. can't be called for isoc ep
> + * 2. can't be called for interrupt ep behind a TT
> + */
> +void xhci_soft_retry_ep(struct xhci_hcd *xhci, int slot_id,
> +		unsigned int ep_index, unsigned int stream_id,
> +		struct xhci_td *td, union xhci_trb *event_trb)
> +{
> +	u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id);
> +	u32 trb_ep_index = EP_ID_FOR_TRB(ep_index);
> +	u32 type = TRB_TYPE(TRB_RESET_EP);
> +	u32 tsp_flag = 1 << 9;
> +	struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index];
> +
> +	ep->ep_state |= EP_HALTED;
> +	ep->stopped_td = td;
> +	ep->stopped_trb	= event_trb;
> +	ep->stopped_stream = stream_id;
> +
> +	queue_command(xhci, 0, 0, 0,
> +			trb_slot_id | trb_ep_index | type | tsp_flag, false);
> +
> +	xhci_ring_cmd_db(xhci);
> +}
> diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
> index 33a49d5..dd45929 100644
> --- a/drivers/usb/host/xhci.h
> +++ b/drivers/usb/host/xhci.h
> @@ -767,6 +767,9 @@ struct xhci_virt_ep {
>  	 * process the missed tds on the endpoint ring.
>  	 */
>  	bool			skip;
> +	/* Soft Retries to prevent an infinite loop */
> +	unsigned int		soft_retries;
> +#define SOFT_RETRY	2
>  };
>  
>  struct xhci_virt_device {
> @@ -1540,6 +1543,9 @@ void xhci_queue_config_ep_quirk(struct xhci_hcd *xhci,
>  		unsigned int slot_id, unsigned int ep_index,
>  		struct xhci_dequeue_state *deq_state);
>  void xhci_stop_endpoint_command_watchdog(unsigned long arg);
> +void xhci_soft_retry_ep(struct xhci_hcd *xhci, int slot_id,
> +		unsigned int ep_index, unsigned int stream_id,
> +		struct xhci_td *td, union xhci_trb *event_trb);
>  void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
>  		unsigned int ep_index, unsigned int stream_id);
>  
> -- 
> 1.7.1
> 
> 
> 
--
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