Re: [PATCH 01/10 v8] xHCI: handle_tx_event() refactor: finish_td

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

 



On Tue, Jul 20, 2010 at 04:49:11PM +0800, Andiry Xu wrote:
> >From 08d56cd6a34dff12bc753c6b5022a277ec03ee0b Mon Sep 17 00:00:00 2001
> From: Andiry Xu <andiry.xu@xxxxxxx>
> Date: Thu, 15 Jul 2010 13:33:27 +0800
> Subject: [PATCH 01/10] xHCI: handle_tx_event() refactor: finish_td
> 
> This patch moves the td universal processing part in handle_tx_event()
> into a separate function finish_td().
> 
> if finish_td() returns 1, it indicates the urb can be given back.
> 
> Signed-off-by: Andiry Xu <andiry.xu@xxxxxxx>

The patchset (with the updated patch #8) passes my testing.  Thanks
Andiry!

Signed-off-by: Sarah Sharp <sarah.a.sharp@xxxxxxxxxxxxxxx>

> ---
>  drivers/usb/host/xhci-ring.c |  185 +++++++++++++++++++++++++-----------------
>  1 files changed, 112 insertions(+), 73 deletions(-)
> 
> diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
> index bfc99a9..691a108 100644
> --- a/drivers/usb/host/xhci-ring.c
> +++ b/drivers/usb/host/xhci-ring.c
> @@ -1258,6 +1258,104 @@ int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code)
>  }
>  
>  /*
> + * Finish the td processing, remove the td from td list;
> + * Return 1 if the urb can be given back.
> + */
> +static int finish_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, bool skip)
> +{
> +	struct xhci_virt_device *xdev;
> +	struct xhci_ring *ep_ring;
> +	unsigned int slot_id;
> +	int ep_index;
> +	struct urb *urb = NULL;
> +	struct xhci_ep_ctx *ep_ctx;
> +	int ret = 0;
> +	u32 trb_comp_code;
> +
> +	slot_id = TRB_TO_SLOT_ID(event->flags);
> +	xdev = xhci->devs[slot_id];
> +	ep_index = TRB_TO_EP_ID(event->flags) - 1;
> +	ep_ring = xhci_dma_to_transfer_ring(ep, event->buffer);
> +	ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
> +	trb_comp_code = GET_COMP_CODE(event->transfer_len);
> +
> +	if (skip)
> +		goto td_cleanup;
> +
> +	if (trb_comp_code == COMP_STOP_INVAL ||
> +			trb_comp_code == COMP_STOP) {
> +		/* The Endpoint Stop Command completion will take care of any
> +		 * stopped TDs.  A stopped TD may be restarted, so don't update
> +		 * the ring dequeue pointer or take this TD off any lists yet.
> +		 */
> +		ep->stopped_td = td;
> +		ep->stopped_trb = event_trb;
> +		return 0;
> +	} else {
> +		if (trb_comp_code == COMP_STALL) {
> +			/* The transfer is completed from the driver's
> +			 * perspective, but we need to issue a set dequeue
> +			 * command for this stalled endpoint to move the dequeue
> +			 * pointer past the TD.  We can't do that here because
> +			 * the halt condition must be cleared first.  Let the
> +			 * USB class driver clear the stall later.
> +			 */
> +			ep->stopped_td = td;
> +			ep->stopped_trb = event_trb;
> +			ep->stopped_stream = ep_ring->stream_id;
> +		} else if (xhci_requires_manual_halt_cleanup(xhci,
> +					ep_ctx, trb_comp_code)) {
> +			/* Other types of errors halt the endpoint, but the
> +			 * class driver doesn't call usb_reset_endpoint() unless
> +			 * the error is -EPIPE.  Clear the halted status in the
> +			 * xHCI hardware manually.
> +			 */
> +			xhci_cleanup_halted_endpoint(xhci,
> +					slot_id, ep_index, ep_ring->stream_id,
> +					td, event_trb);
> +		} else {
> +			/* Update ring dequeue pointer */
> +			while (ep_ring->dequeue != td->last_trb)
> +				inc_deq(xhci, ep_ring, false);
> +			inc_deq(xhci, ep_ring, false);
> +		}
> +
> +td_cleanup:
> +		/* Clean up the endpoint's TD list */
> +		urb = td->urb;
> +
> +		/* Do one last check of the actual transfer length.
> +		 * If the host controller said we transferred more data than
> +		 * the buffer length, urb->actual_length will be a very big
> +		 * number (since it's unsigned).  Play it safe and say we didn't
> +		 * transfer anything.
> +		 */
> +		if (urb->actual_length > urb->transfer_buffer_length) {
> +			xhci_warn(xhci, "URB transfer length is wrong, "
> +					"xHC issue? req. len = %u, "
> +					"act. len = %u\n",
> +					urb->transfer_buffer_length,
> +					urb->actual_length);
> +			urb->actual_length = 0;
> +			if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
> +				*status = -EREMOTEIO;
> +			else
> +				*status = 0;
> +		}
> +		list_del(&td->td_list);
> +		/* Was this TD slated to be cancelled but completed anyway? */
> +		if (!list_empty(&td->cancelled_td_list))
> +			list_del(&td->cancelled_td_list);
> +
> +		ret = 1;
> +	}
> +
> +	return ret;
> +}
> +
> +/*
>   * If this function returns an error condition, it means it got a Transfer
>   * event with a corrupted Slot ID, Endpoint ID, or TRB DMA address.
>   * At this point, the host controller is probably hosed and should be reset.
> @@ -1278,6 +1376,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
>  	int status = -EINPROGRESS;
>  	struct xhci_ep_ctx *ep_ctx;
>  	u32 trb_comp_code;
> +	int ret = 0;
>  
>  	xhci_dbg(xhci, "In %s\n", __func__);
>  	slot_id = TRB_TO_SLOT_ID(event->flags);
> @@ -1308,7 +1407,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
>  		xhci_dbg(xhci, "Event TRB with TRB type ID %u\n",
>  				(unsigned int) (event->flags & TRB_TYPE_BITMASK)>>10);
>  		xhci_print_trb_offsets(xhci, (union xhci_trb *) event);
> -		urb = NULL;
>  		goto cleanup;
>  	}
>  	xhci_dbg(xhci, "%s - getting list entry\n", __func__);
> @@ -1379,7 +1477,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
>  			break;
>  		}
>  		xhci_warn(xhci, "ERROR Unknown event condition, HC probably busted\n");
> -		urb = NULL;
>  		goto cleanup;
>  	}
>  	/* Now update the urb's actual_length and give back to the core */
> @@ -1427,7 +1524,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,
>  
>  			xhci_cleanup_halted_endpoint(xhci,
>  					slot_id, ep_index, 0, td, event_trb);
> -			goto td_cleanup;
> +
> +			ret = finish_td(xhci, td, event_trb, event, ep,
> +					 &status, true);
> +			goto cleanup;
>  		}
>  		/*
>  		 * Did we transfer any data, despite the errors that might have
> @@ -1456,7 +1556,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
>  						td->urb->transfer_buffer_length -
>  						TRB_LEN(event->transfer_len);
>  					xhci_dbg(xhci, "Waiting for status stage event\n");
> -					urb = NULL;
>  					goto cleanup;
>  				}
>  			}
> @@ -1558,68 +1657,16 @@ static int handle_tx_event(struct xhci_hcd *xhci,
>  					TRB_LEN(event->transfer_len);
>  		}
>  	}
> -	if (trb_comp_code == COMP_STOP_INVAL ||
> -			trb_comp_code == COMP_STOP) {
> -		/* The Endpoint Stop Command completion will take care of any
> -		 * stopped TDs.  A stopped TD may be restarted, so don't update
> -		 * the ring dequeue pointer or take this TD off any lists yet.
> -		 */
> -		ep->stopped_td = td;
> -		ep->stopped_trb = event_trb;
> -	} else {
> -		if (trb_comp_code == COMP_STALL) {
> -			/* The transfer is completed from the driver's
> -			 * perspective, but we need to issue a set dequeue
> -			 * command for this stalled endpoint to move the dequeue
> -			 * pointer past the TD.  We can't do that here because
> -			 * the halt condition must be cleared first.  Let the
> -			 * USB class driver clear the stall later.
> -			 */
> -			ep->stopped_td = td;
> -			ep->stopped_trb = event_trb;
> -			ep->stopped_stream = ep_ring->stream_id;
> -		} else if (xhci_requires_manual_halt_cleanup(xhci,
> -					ep_ctx, trb_comp_code)) {
> -			/* Other types of errors halt the endpoint, but the
> -			 * class driver doesn't call usb_reset_endpoint() unless
> -			 * the error is -EPIPE.  Clear the halted status in the
> -			 * xHCI hardware manually.
> -			 */
> -			xhci_cleanup_halted_endpoint(xhci,
> -					slot_id, ep_index, ep_ring->stream_id, td, event_trb);
> -		} else {
> -			/* Update ring dequeue pointer */
> -			while (ep_ring->dequeue != td->last_trb)
> -				inc_deq(xhci, ep_ring, false);
> -			inc_deq(xhci, ep_ring, false);
> -		}
>  
> -td_cleanup:
> -		/* Clean up the endpoint's TD list */
> -		urb = td->urb;
> -		/* Do one last check of the actual transfer length.
> -		 * If the host controller said we transferred more data than
> -		 * the buffer length, urb->actual_length will be a very big
> -		 * number (since it's unsigned).  Play it safe and say we didn't
> -		 * transfer anything.
> -		 */
> -		if (urb->actual_length > urb->transfer_buffer_length) {
> -			xhci_warn(xhci, "URB transfer length is wrong, "
> -					"xHC issue? req. len = %u, "
> -					"act. len = %u\n",
> -					urb->transfer_buffer_length,
> -					urb->actual_length);
> -			urb->actual_length = 0;
> -			if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
> -				status = -EREMOTEIO;
> -			else
> -				status = 0;
> -		}
> -		list_del(&td->td_list);
> -		/* Was this TD slated to be cancelled but completed anyway? */
> -		if (!list_empty(&td->cancelled_td_list))
> -			list_del(&td->cancelled_td_list);
> +	ret =  finish_td(xhci, td, event_trb, event, ep, &status, false);
>  
> +cleanup:
> +	inc_deq(xhci, xhci->event_ring, true);
> +	xhci_set_hc_event_deq(xhci);
> +
> +	/* FIXME for multi-TD URBs (who have buffers bigger than 64MB) */
> +	if (ret) {
> +		urb = td->urb;
>  		/* Leave the TD around for the reset endpoint function to use
>  		 * (but only if it's not a control endpoint, since we already
>  		 * queued the Set TR dequeue pointer command for stalled
> @@ -1627,17 +1674,9 @@ td_cleanup:
>  		 */
>  		if (usb_endpoint_xfer_control(&urb->ep->desc) ||
>  			(trb_comp_code != COMP_STALL &&
> -				trb_comp_code != COMP_BABBLE)) {
> +				trb_comp_code != COMP_BABBLE))
>  			kfree(td);
> -		}
> -		urb->hcpriv = NULL;
> -	}
> -cleanup:
> -	inc_deq(xhci, xhci->event_ring, true);
> -	xhci_set_hc_event_deq(xhci);
>  
> -	/* FIXME for multi-TD URBs (who have buffers bigger than 64MB) */
> -	if (urb) {
>  		usb_hcd_unlink_urb_from_ep(xhci_to_hcd(xhci), urb);
>  		xhci_dbg(xhci, "Giveback URB %p, len = %d, status = %d\n",
>  				urb, urb->actual_length, status);
> -- 
> 1.7.0.4
> 
> 
> 
--
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