Re: [PATCH 5/5] xHCI: assign devices to different interrupters

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

 



On Fri, Jun 10, 2011 at 04:51:43PM +0800, Andiry Xu wrote:
> This patch assign devices to different interrupters based on its slot_id.
> However, it's not mandatory that a device should use the same interrupter.
> A device can assign its control transfer to one interrupter and bulk/intr/
> isoc transfer to another interrupter. The interrupter usage policy is
> flexible.
>
> The policy in this patch may be replaced by better approach in the future.

I would like to get a more flexible policy, or at least the APIs to
allow drivers or the USB core flexibility in directing URB traffic to
different interrupters before this gets merged.  I'm most concerned
about allowing drivers or the USB core to change interrupt moderation
rate the rings should use.  Either that, or the xHCI driver needs to
choose the moderation interval based on the endpoint type and polling
rate.  I think we need that, because I have doubts that these patches
alone will improve performance.  I don't really want to add this much
optional code without some indication that it will help performance.

What about adding a field to the struct urb to allow the driver
to set the interrupter field?  We might have to add some USB core API to
allow the driver to figure out how many interrupters are available.  If
the driver doesn't set the field, we can just use the per-device
basis.

I think we'd have to restrict the driver to only using one interrupter
per endpoint, unless streams are enabled.  Otherwise I think it breaks
the xhci_td list handling assumption that events are handed back in the
order they are placed on the ring, because we could have a race
condition between two CPUs that receive interrupts for the same
endpoint.  You could set an initial interrupter used in the xhci_virt_ep
structure, and then double check it whenever a new URB is queued for
that endpoint.

Then if each URB could have a different interrupter, the UAS driver could
direct different stream transfers to different interrupters.

> Signed-off-by: Andiry Xu <andiry.xu@xxxxxxx>
> ---
>  drivers/usb/host/xhci-mem.c  |    3 +++
>  drivers/usb/host/xhci-ring.c |   22 ++++++++++++++--------
>  drivers/usb/host/xhci.h      |    2 ++
>  3 files changed, 19 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
> index f1f64a4..dd0f27d 100644
> --- a/drivers/usb/host/xhci-mem.c
> +++ b/drivers/usb/host/xhci-mem.c
> @@ -781,6 +781,9 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
>  	INIT_LIST_HEAD(&dev->cmd_list);
>  	dev->udev = udev;
>  
> +	/* Decide the interrupter target */
> +	dev->intr_target = slot_id % xhci->intr_num;
> +
>  	/* Point to output device context in dcbaa. */
>  	xhci->dcbaa->dev_context_ptrs[slot_id] = cpu_to_le64(dev->out_ctx->dma);
>  	xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n",
> diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
> index fc3c9d8..f3e49af 100644
> --- a/drivers/usb/host/xhci-ring.c
> +++ b/drivers/usb/host/xhci-ring.c
> @@ -2702,6 +2702,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
>  	bool first_trb;
>  	u64 addr;
>  	bool more_trbs_coming;
> +	int intr;
>  
>  	struct xhci_generic_trb *start_trb;
>  	int start_cycle;
> @@ -2724,6 +2725,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
>  	urb_priv = urb->hcpriv;
>  	td = urb_priv->td[0];
>  
> +	intr = xhci->devs[slot_id]->intr_target;
>  	/*
>  	 * Don't give the first TRB to the hardware (by toggling the cycle bit)
>  	 * until we've finished creating all the other TRBs.  The ring's cycle
> @@ -2806,7 +2808,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
>  		}
>  		length_field = TRB_LEN(trb_buff_len) |
>  			remainder |
> -			TRB_INTR_TARGET(0);
> +			TRB_INTR_TARGET(intr);
>  
>  		if (num_trbs > 1)
>  			more_trbs_coming = true;
> @@ -2862,10 +2864,10 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
>  	bool more_trbs_coming;
>  	int start_cycle;
>  	u32 field, length_field;
> -
>  	int running_total, trb_buff_len, ret;
>  	unsigned int total_packet_count;
>  	u64 addr;
> +	int intr;
>  
>  	if (urb->num_sgs)
>  		return queue_bulk_sg_tx(xhci, mem_flags, urb, slot_id, ep_index);
> @@ -2910,6 +2912,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
>  	urb_priv = urb->hcpriv;
>  	td = urb_priv->td[0];
>  
> +	intr = xhci->devs[slot_id]->intr_target;
>  	/*
>  	 * Don't give the first TRB to the hardware (by toggling the cycle bit)
>  	 * until we've finished creating all the other TRBs.  The ring's cycle
> @@ -2969,7 +2972,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
>  		}
>  		length_field = TRB_LEN(trb_buff_len) |
>  			remainder |
> -			TRB_INTR_TARGET(0);
> +			TRB_INTR_TARGET(intr);
>  
>  		if (num_trbs > 1)
>  			more_trbs_coming = true;
> @@ -3009,6 +3012,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
>  	u32 field, length_field;
>  	struct urb_priv *urb_priv;
>  	struct xhci_td *td;
> +	int intr;
>  
>  	ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
>  	if (!ep_ring)
> @@ -3042,6 +3046,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
>  	urb_priv = urb->hcpriv;
>  	td = urb_priv->td[0];
>  
> +	intr = xhci->devs[slot_id]->intr_target;
>  	/*
>  	 * Don't give the first TRB to the hardware (by toggling the cycle bit)
>  	 * until we've finished creating all the other TRBs.  The ring's cycle
> @@ -3071,7 +3076,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
>  	queue_trb(xhci, ep_ring, false, true,
>  		  setup->bRequestType | setup->bRequest << 8 | le16_to_cpu(setup->wValue) << 16,
>  		  le16_to_cpu(setup->wIndex) | le16_to_cpu(setup->wLength) << 16,
> -		  TRB_LEN(8) | TRB_INTR_TARGET(0),
> +		  TRB_LEN(8) | TRB_INTR_TARGET(intr),
>  		  /* Immediate data in pointer */
>  		  field);
>  
> @@ -3084,7 +3089,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
>  
>  	length_field = TRB_LEN(urb->transfer_buffer_length) |
>  		xhci_td_remainder(urb->transfer_buffer_length) |
> -		TRB_INTR_TARGET(0);
> +		TRB_INTR_TARGET(intr);
>  	if (urb->transfer_buffer_length > 0) {
>  		if (setup->bRequestType & USB_DIR_IN)
>  			field |= TRB_DIR_IN;
> @@ -3107,7 +3112,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
>  	queue_trb(xhci, ep_ring, false, false,
>  			0,
>  			0,
> -			TRB_INTR_TARGET(0),
> +			TRB_INTR_TARGET(intr),
>  			/* Event on completion */
>  			field | TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state);
>  
> @@ -3209,7 +3214,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
>  	u32 field, length_field;
>  	int running_total, trb_buff_len, td_len, td_remain_len, ret;
>  	u64 start_addr, addr;
> -	int i, j;
> +	int i, j, intr;
>  	bool more_trbs_coming;
>  
>  	ep_ring = xhci->devs[slot_id]->eps[ep_index].ring;
> @@ -3233,6 +3238,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
>  	start_trb = &ep_ring->enqueue->generic;
>  	start_cycle = ep_ring->cycle_state;
>  
> +	intr = xhci->devs[slot_id]->intr_target;
>  	/* Queue the first TRB, even if it's zero-length */
>  	for (i = 0; i < num_tds; i++) {
>  		unsigned int total_packet_count;
> @@ -3322,7 +3328,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
>  			}
>  			length_field = TRB_LEN(trb_buff_len) |
>  				remainder |
> -				TRB_INTR_TARGET(0);
> +				TRB_INTR_TARGET(intr);
>  
>  			queue_trb(xhci, ep_ring, false, more_trbs_coming,
>  				lower_32_bits(addr),
> diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
> index a18cf6b..84c0edb 100644
> --- a/drivers/usb/host/xhci.h
> +++ b/drivers/usb/host/xhci.h
> @@ -792,6 +792,8 @@ struct xhci_virt_device {
>  	int				num_rings_cached;
>  	/* Store xHC assigned device address */
>  	int				address;
> +	/* Store the interrupter target */
> +	int				intr_target;
>  #define	XHCI_MAX_RINGS_CACHED	31
>  	struct xhci_virt_ep		eps[31];
>  	struct completion		cmd_completion;
> -- 
> 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