----- Original Message -----
> From: gre...@linuxfoundation.org
> To: "sarah a sharp" <sarah.a.sh...@linux.intel.com>, "bhavik kothari" 
> <bhavik.koth...@sibridgetech.com>, "chintan
> mehta" <chintan.me...@sibridgetech.com>, "shimmering h" 
> <shimmerin...@gmail.com>
> Cc: stable@vger.kernel.org
> Sent: Wednesday, January 9, 2013 4:47:08 AM
> Subject: FAILED: patch "[PATCH] xHCI: Fix TD Size calculation on 1.0 hosts." 
> failed to apply to 3.0-stable tree
> 
> 
> The patch below does not apply to the 3.0-stable tree.
> If someone wants it applied there, or to any other stable or longterm
> tree, then please email the backport, including the original git
> commit
> id to <stable@vger.kernel.org>.
I'll working on this.
> 
> thanks,
> 
> greg k-h
> 
> ------------------ original commit in Linus's tree ------------------
> 
> From 4525c0a10dff7ad3669763c28016c7daffc3900e Mon Sep 17 00:00:00
> 2001
> From: Sarah Sharp <sarah.a.sh...@linux.intel.com>
> Date: Thu, 25 Oct 2012 15:56:40 -0700
> Subject: [PATCH] xHCI: Fix TD Size calculation on 1.0 hosts.
> 
> The xHCI 1.0 specification made a change to the TD Size field in
> TRBs.
> The value is now the number of packets that remain to be sent in the
> TD,
> not including this TRB.  The TD Size value for the last TRB in a TD
> must
> always be zero.
> 
> The xHCI function xhci_v1_0_td_remainder() attempts to calculate
> this,
> but it gets it wrong.  First, it erroneously reuses the old
> xhci_td_remainder function, which will right shift the value by 10.
>  The
> xHCI 1.0 spec as of June 2011 says nothing about right shifting by
> 10.
> Second, it does not set the TD size for the last TRB in a TD to zero.
> 
> Third, it uses roundup instead of DIV_ROUND_UP.  The total packet
> count
> is supposed to be the total number of bytes in this TD, divided by
> the
> max packet size, rounded up.  DIV_ROUND_UP is the right function to
> use
> in that case.
> 
> With the old code, a TD on an endpoint with max packet size 1024
> would
> be set up like so:
> TRB 1, TRB length = 600 bytes, TD size = 0
> TRB 1, TRB length = 200 bytes, TD size = 0
> TRB 1, TRB length = 100 bytes, TD size = 0
> 
> With the new code, the TD would be set up like this:
> TRB 1, TRB length = 600 bytes, TD size = 1
> TRB 1, TRB length = 200 bytes, TD size = 1
> TRB 1, TRB length = 100 bytes, TD size = 0
> 
> This commit should be backported to kernels as old as 3.0, that
> contain
> the commit 4da6e6f247a2601ab9f1e63424e4d944ed4124f3 "xhci 1.0: Update
> TD
> size field format."
> 
> Signed-off-by: Sarah Sharp <sarah.a.sh...@linux.intel.com>
> Reported-by: Chintan Mehta <chintan.me...@sibridgetech.com>
> Reported-by: Shimmer Huang <shimmerin...@gmail.com>
> Tested-by: Bhavik Kothari <bhavik.koth...@sibridgetech.com>
> Tested-by: Shimmer Huang <shimmerin...@gmail.com>
> Cc: stable@vger.kernel.org
> 
> diff --git a/drivers/usb/host/xhci-ring.c
> b/drivers/usb/host/xhci-ring.c
> index 77f1ace..cbb44b7 100644
> --- a/drivers/usb/host/xhci-ring.c
> +++ b/drivers/usb/host/xhci-ring.c
> @@ -3071,11 +3071,11 @@ static u32 xhci_td_remainder(unsigned int
> remainder)
>  }
>  
>  /*
> - * For xHCI 1.0 host controllers, TD size is the number of packets
> remaining in
> - * the TD (*not* including this TRB).
> + * For xHCI 1.0 host controllers, TD size is the number of max
> packet sized
> + * packets remaining in the TD (*not* including this TRB).
>   *
>   * Total TD packet count = total_packet_count =
> - *     roundup(TD size in bytes / wMaxPacketSize)
> + *     DIV_ROUND_UP(TD size in bytes / wMaxPacketSize)
>   *
>   * Packets transferred up to and including this TRB =
>   packets_transferred =
>   *     rounddown(total bytes transferred including this TRB /
>   wMaxPacketSize)
> @@ -3083,15 +3083,16 @@ static u32 xhci_td_remainder(unsigned int
> remainder)
>   * TD size = total_packet_count - packets_transferred
>   *
>   * It must fit in bits 21:17, so it can't be bigger than 31.
> + * The last TRB in a TD must have the TD size set to zero.
>   */
> -
>  static u32 xhci_v1_0_td_remainder(int running_total, int
>  trb_buff_len,
> -             unsigned int total_packet_count, struct urb *urb)
> +             unsigned int total_packet_count, struct urb *urb,
> +             unsigned int num_trbs_left)
>  {
>       int packets_transferred;
>  
>       /* One TRB with a zero-length data packet. */
> -     if (running_total == 0 && trb_buff_len == 0)
> +     if (num_trbs_left == 0 || (running_total == 0 && trb_buff_len ==
> 0))
>               return 0;
>  
>       /* All the TRB queueing functions don't count the current TRB in
> @@ -3100,7 +3101,9 @@ static u32 xhci_v1_0_td_remainder(int
> running_total, int trb_buff_len,
>       packets_transferred = (running_total + trb_buff_len) /
>               usb_endpoint_maxp(&urb->ep->desc);
>  
> -     return xhci_td_remainder(total_packet_count - packets_transferred);
> +     if ((total_packet_count - packets_transferred) > 31)
> +             return 31 << 17;
> +     return (total_packet_count - packets_transferred) << 17;
>  }
>  
>  static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
> @@ -3127,7 +3130,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd
> *xhci, gfp_t mem_flags,
>  
>       num_trbs = count_sg_trbs_needed(xhci, urb);
>       num_sgs = urb->num_mapped_sgs;
> -     total_packet_count = roundup(urb->transfer_buffer_length,
> +     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],
> @@ -3210,7 +3213,8 @@ static int queue_bulk_sg_tx(struct xhci_hcd
> *xhci, gfp_t mem_flags,
>                                       running_total);
>               } else {
>                       remainder = xhci_v1_0_td_remainder(running_total,
> -                                     trb_buff_len, total_packet_count, urb);
> +                                     trb_buff_len, total_packet_count, urb,
> +                                     num_trbs - 1);
>               }
>               length_field = TRB_LEN(trb_buff_len) |
>                       remainder |
> @@ -3318,7 +3322,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci,
> gfp_t mem_flags,
>       start_cycle = ep_ring->cycle_state;
>  
>       running_total = 0;
> -     total_packet_count = roundup(urb->transfer_buffer_length,
> +     total_packet_count = DIV_ROUND_UP(urb->transfer_buffer_length,
>                       usb_endpoint_maxp(&urb->ep->desc));
>       /* How much data is in the first TRB? */
>       addr = (u64) urb->transfer_dma;
> @@ -3364,7 +3368,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci,
> gfp_t mem_flags,
>                                       running_total);
>               } else {
>                       remainder = xhci_v1_0_td_remainder(running_total,
> -                                     trb_buff_len, total_packet_count, urb);
> +                                     trb_buff_len, total_packet_count, urb,
> +                                     num_trbs - 1);
>               }
>               length_field = TRB_LEN(trb_buff_len) |
>                       remainder |
> @@ -3627,7 +3632,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd
> *xhci, gfp_t mem_flags,
>               addr = start_addr + urb->iso_frame_desc[i].offset;
>               td_len = urb->iso_frame_desc[i].length;
>               td_remain_len = td_len;
> -             total_packet_count = roundup(td_len,
> +             total_packet_count = DIV_ROUND_UP(td_len,
>                               usb_endpoint_maxp(&urb->ep->desc));
>               /* A zero-length transfer still involves at least one packet. */
>               if (total_packet_count == 0)
> @@ -3706,7 +3711,8 @@ static int xhci_queue_isoc_tx(struct xhci_hcd
> *xhci, gfp_t mem_flags,
>                       } else {
>                               remainder = xhci_v1_0_td_remainder(
>                                               running_total, trb_buff_len,
> -                                             total_packet_count, urb);
> +                                             total_packet_count, urb,
> +                                             (trbs_per_td - j - 1));
>                       }
>                       length_field = TRB_LEN(trb_buff_len) |
>                               remainder |
> 
> --
> To unsubscribe from this list: send the line "unsubscribe stable" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
--
To unsubscribe from this list: send the line "unsubscribe stable" 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