Re: [PATCH/RFC v2] xhci: Transfer ring link TRB activation change.

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

 



Hi John,

This patch looks fine and works for me.  Feel free to add my signed-off
by line and send to Greg KH.

Sarah Sharp

On Thu, May 06, 2010 at 11:11:06AM -0700, John Youn wrote:
> Change transfer ring behavior to not follow/activate link TRBs
> until active TRBs are queued after it.  This change affects
> the behavior when a TD ends just before a link TRB.
> 
> Signed-off-by: John Youn <johnyoun@xxxxxxxxxxxx>
> ---
> 
> Cleaned up the previous patch a little and fixed the link_quirk
> condition.  Don't have 0.95 hardware to test with though.
> 
>  drivers/usb/host/xhci-ring.c |   71 ++++++++++++++++++++++++++++++++++--------
>  1 files changed, 58 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
> index b648efa..74d0c2d 100644
> --- a/drivers/usb/host/xhci-ring.c
> +++ b/drivers/usb/host/xhci-ring.c
> @@ -112,6 +112,12 @@ static inline int last_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
>  		return (trb->link.control & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK);
>  }
>  
> +static inline int enqueue_is_link_trb(struct xhci_ring *ring)
> +{
> +	struct xhci_link_trb *link = &ring->enqueue->link;
> +	return ((link->control & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK));
> +}
> +
>  /* Updates trb to point to the next TRB in the ring, and updates seg if the next
>   * TRB is in a new segment.  This does not skip over link TRBs, and it does not
>   * effect the ring dequeue or enqueue pointers.
> @@ -193,20 +199,15 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer
>  	while (last_trb(xhci, ring, ring->enq_seg, next)) {
>  		if (!consumer) {
>  			if (ring != xhci->event_ring) {
> -				/* If we're not dealing with 0.95 hardware,
> -				 * carry over the chain bit of the previous TRB
> -				 * (which may mean the chain bit is cleared).
> -				 */
> -				if (!xhci_link_trb_quirk(xhci)) {
> -					next->link.control &= ~TRB_CHAIN;
> -					next->link.control |= chain;
> +				if (chain) {
> +					next->link.control |= TRB_CHAIN;
> +
> +					/* Give this link TRB to the hardware */
> +					wmb();
> +					next->link.control ^= TRB_CYCLE;
> +				} else {
> +					break;
>  				}
> -				/* Give this link TRB to the hardware */
> -				wmb();
> -				if (next->link.control & TRB_CYCLE)
> -					next->link.control &= (u32) ~TRB_CYCLE;
> -				else
> -					next->link.control |= (u32) TRB_CYCLE;
>  			}
>  			/* Toggle the cycle bit after the last ring segment. */
>  			if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {
> @@ -243,6 +244,13 @@ static int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring,
>  	union xhci_trb *enq = ring->enqueue;
>  	struct xhci_segment *enq_seg = ring->enq_seg;
>  
> +	/* If we are currently pointing to a link TRB, advance the
> +	 * enqueue pointer before checking for space */
> +	while (last_trb(xhci, ring, enq_seg, enq)) {
> +		enq_seg = enq_seg->next;
> +		enq = enq_seg->trbs;
> +	}
> +
>  	/* Check if ring is empty */
>  	if (enq == ring->dequeue)
>  		return 1;
> @@ -1703,6 +1711,43 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
>  		xhci_err(xhci, "ERROR no room on ep ring\n");
>  		return -ENOMEM;
>  	}
> +
> +	if (enqueue_is_link_trb(ep_ring)) {
> +		struct xhci_ring *ring = ep_ring;
> +		union xhci_trb *next;
> +		unsigned long long addr;
> +
> +		xhci_dbg(xhci, "prepare_ring: pointing to link trb\n");
> +		next = ring->enqueue;
> +
> +		while (last_trb(xhci, ring, ring->enq_seg, next)) {
> +
> +			/* If we're not dealing with 0.95 hardware,
> +			 * clear the chain bit.
> +			 */
> +			if (!xhci_link_trb_quirk(xhci))
> +				next->link.control &= ~TRB_CHAIN;
> +			else
> +				next->link.control |= TRB_CHAIN;
> +
> +			wmb();
> +			next->link.control ^= (u32) TRB_CYCLE;
> +
> +			/* Toggle the cycle bit after the last ring segment. */
> +			if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {
> +				ring->cycle_state = (ring->cycle_state ? 0 : 1);
> +				if (!in_interrupt()) {
> +					xhci_dbg(xhci, "queue_trb: Toggle cycle "
> +						"state for ring %p = %i\n",
> +						ring, (unsigned int)ring->cycle_state);
> +				}
> +			}
> +			ring->enq_seg = ring->enq_seg->next;
> +			ring->enqueue = ring->enq_seg->trbs;
> +			next = ring->enqueue;
> +		}
> +	}
> +
>  	return 0;
>  }
>  
> -- 
> 1.6.6.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
--
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