It helps if you Cc testers on your patches.  Adding Jérôme, please test.

Sarah Sharp

On Thu, Jan 23, 2014 at 01:42:28PM +0000, David Laight wrote:
> Transfer requests for usb disks can contain a large number of 4k fragments.
> Assume that it doesn't matter if there are LINK TRB in fragment lists
> that are 1k aligned.
> 
> This should stop errors when transfer requests for usb disks contain
> more fragments that will fit in a ring segment.
> 
> Signed-off-by: David Laight <david.lai...@aculab.com>
> ---
> Note that this patch just allows large numbers of aligned fragments for
> bulk scatter-gather transfers.
> It doesn't remove the need for the patch that changes the way the ownership
> of the the first TRB is set in order to avoid the controller seeing 'dangling'
> LINK TRBs.
> However it does reduce the likelyhood of dangling LINK TRBs, so might seem to
> make the other patch unnecessary.
> 
> I've only compile tested it - but it should be fine.
> 
>  drivers/usb/host/xhci-ring.c | 49 
> ++++++++++++++++++++++++++++++++++----------
>  1 file changed, 38 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
> index a0b248c..7a4efd2 100644
> --- a/drivers/usb/host/xhci-ring.c
> +++ b/drivers/usb/host/xhci-ring.c
> @@ -2932,7 +2932,8 @@ static void queue_trb(struct xhci_hcd *xhci, struct 
> xhci_ring *ring,
>   * FIXME allocate segments if the ring is full.
>   */
>  static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
> -             u32 ep_state, unsigned int num_trbs, gfp_t mem_flags)
> +             u32 ep_state, unsigned int num_trbs, gfp_t mem_flags,
> +             bool aligned_xfer)
>  {
>       unsigned int num_trbs_needed;
>  
> @@ -2980,6 +2981,9 @@ static int prepare_ring(struct xhci_hcd *xhci, struct 
> xhci_ring *ep_ring,
>                        * Simplest solution is to fill the trb before the
>                        * LINK with nop commands.
>                        */
> +                     if (aligned_xfer)
> +                             /* Caller says buffer is aligned */
> +                             break;
>                       if (num_trbs == 1 || num_trbs <= usable || usable == 0)
>                               break;
>  
> @@ -3073,7 +3077,8 @@ static int prepare_transfer(struct xhci_hcd *xhci,
>               unsigned int num_trbs,
>               struct urb *urb,
>               unsigned int td_index,
> -             gfp_t mem_flags)
> +             gfp_t mem_flags,
> +             bool aligned_xfer)
>  {
>       int ret;
>       struct urb_priv *urb_priv;
> @@ -3090,7 +3095,7 @@ static int prepare_transfer(struct xhci_hcd *xhci,
>  
>       ret = prepare_ring(xhci, ep_ring,
>                          le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK,
> -                        num_trbs, mem_flags);
> +                        num_trbs, mem_flags, aligned_xfer);
>       if (ret)
>               return ret;
>  
> @@ -3117,7 +3122,8 @@ static int prepare_transfer(struct xhci_hcd *xhci,
>       return 0;
>  }
>  
> -static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb 
> *urb)
> +static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb 
> *urb,
> +     bool *aligned_xfer)
>  {
>       int num_sgs, num_trbs, running_total, temp, i;
>       struct scatterlist *sg;
> @@ -3125,11 +3131,30 @@ static unsigned int count_sg_trbs_needed(struct 
> xhci_hcd *xhci, struct urb *urb)
>       sg = NULL;
>       num_sgs = urb->num_mapped_sgs;
>       temp = urb->transfer_buffer_length;
> +     *aligned_xfer = true;
>  
>       num_trbs = 0;
>       for_each_sg(urb->sg, sg, num_sgs, i) {
>               unsigned int len = sg_dma_len(sg);
>  
> +             /*
> +              * The 1.0 spec says LINK TRB are only allowed at data offsets
> +              * that are multiples of the transfer burst size.
> +              * While the burst size might be 16k the effect is probably
> +              * that the transfer is split. In particular a non-full-length
> +              * data block might be sent - terminating a bulk transfer.
> +              *
> +              * prepare_ring() ensures that the data TRB don't cross a LINK,
> +              * but for usb disks we see large numbers of fragments of 4k
> +              * and that exceeds the size of each ring segment.
> +              *
> +              * If all the fragments start and end on 1k boundaries tell
> +              * prepare_ring() not to worry about LINK TRB.
> +              */
> +             if ((sg_dma_address(sg) | sg_dma_len(sg)) & 1023)
> +                     /* Fragment not 1k aligned */
> +                     *aligned_xfer = false;
> +
>               /* Scatter gather list entries may cross 64KB boundaries */
>               running_total = TRB_MAX_BUFF_SIZE -
>                       (sg_dma_address(sg) & (TRB_MAX_BUFF_SIZE - 1));
> @@ -3284,6 +3309,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, 
> gfp_t mem_flags,
>       bool first_trb;
>       u64 addr;
>       bool more_trbs_coming;
> +     bool aligned_xfer;
>  
>       struct xhci_generic_trb *start_trb;
>       int start_cycle;
> @@ -3292,14 +3318,14 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, 
> gfp_t mem_flags,
>       if (!ep_ring)
>               return -EINVAL;
>  
> -     num_trbs = count_sg_trbs_needed(xhci, urb);
> +     num_trbs = count_sg_trbs_needed(xhci, urb, &aligned_xfer);
>       num_sgs = urb->num_mapped_sgs;
>       total_packet_count = DIV_ROUND_UP(urb->transfer_buffer_length,
>                       usb_endpoint_maxp(&urb->ep->desc));
>  
>       trb_buff_len = prepare_transfer(xhci, xhci->devs[slot_id],
>                       ep_index, urb->stream_id,
> -                     num_trbs, urb, 0, mem_flags);
> +                     num_trbs, urb, 0, mem_flags, aligned_xfer);
>       if (trb_buff_len < 0)
>               return trb_buff_len;
>  
> @@ -3470,7 +3496,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t 
> mem_flags,
>  
>       ret = prepare_transfer(xhci, xhci->devs[slot_id],
>                       ep_index, urb->stream_id,
> -                     num_trbs, urb, 0, mem_flags);
> +                     num_trbs, urb, 0, mem_flags, false);
>       if (ret < 0)
>               return ret;
>  
> @@ -3600,7 +3626,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t 
> mem_flags,
>               num_trbs++;
>       ret = prepare_transfer(xhci, xhci->devs[slot_id],
>                       ep_index, urb->stream_id,
> -                     num_trbs, urb, 0, mem_flags);
> +                     num_trbs, urb, 0, mem_flags, false);
>       if (ret < 0)
>               return ret;
>  
> @@ -3810,7 +3836,8 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, 
> gfp_t mem_flags,
>               trbs_per_td = count_isoc_trbs_needed(xhci, urb, i);
>  
>               ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index,
> -                             urb->stream_id, trbs_per_td, urb, i, mem_flags);
> +                             urb->stream_id, trbs_per_td, urb, i, mem_flags,
> +                             false);
>               if (ret < 0) {
>                       if (i == 0)
>                               return ret;
> @@ -3969,7 +3996,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, 
> gfp_t mem_flags,
>        * Do not insert any td of the urb to the ring if the check failed.
>        */
>       ret = prepare_ring(xhci, ep_ring, le32_to_cpu(ep_ctx->ep_info) & 
> EP_STATE_MASK,
> -                        num_trbs, mem_flags);
> +                        num_trbs, mem_flags, false);
>       if (ret)
>               return ret;
>  
> @@ -4026,7 +4053,7 @@ static int queue_command(struct xhci_hcd *xhci, u32 
> field1, u32 field2,
>               reserved_trbs++;
>  
>       ret = prepare_ring(xhci, xhci->cmd_ring, EP_STATE_RUNNING,
> -                     reserved_trbs, GFP_ATOMIC);
> +                     reserved_trbs, GFP_ATOMIC, false);
>       if (ret < 0) {
>               xhci_err(xhci, "ERR: No room for command on command ring\n");
>               if (command_must_succeed)
> -- 
> 1.8.1.2
> 
> 
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to