This is a note to let you know that I've just added the patch titled

    xHCI: Fix TD Size calculation on 1.0 hosts.

to the 3.4-stable tree which can be found at:
    
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     xhci-fix-td-size-calculation-on-1.0-hosts.patch
and it can be found in the queue-3.4 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <[email protected]> know about it.


>From 4525c0a10dff7ad3669763c28016c7daffc3900e Mon Sep 17 00:00:00 2001
From: Sarah Sharp <[email protected]>
Date: Thu, 25 Oct 2012 15:56:40 -0700
Subject: xHCI: Fix TD Size calculation on 1.0 hosts.

From: Sarah Sharp <[email protected]>

commit 4525c0a10dff7ad3669763c28016c7daffc3900e upstream.

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 <[email protected]>
Reported-by: Chintan Mehta <[email protected]>
Reported-by: Shimmer Huang <[email protected]>
Tested-by: Bhavik Kothari <[email protected]>
Tested-by: Shimmer Huang <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

---
 drivers/usb/host/xhci-ring.c |   32 +++++++++++++++++++-------------
 1 file changed, 19 insertions(+), 13 deletions(-)

--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -3069,11 +3069,11 @@ static u32 xhci_td_remainder(unsigned in
 }
 
 /*
- * 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)
@@ -3081,15 +3081,16 @@ static u32 xhci_td_remainder(unsigned in
  * 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
@@ -3098,7 +3099,9 @@ static u32 xhci_v1_0_td_remainder(int ru
        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,
@@ -3125,7 +3128,7 @@ static int queue_bulk_sg_tx(struct xhci_
 
        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],
@@ -3208,7 +3211,8 @@ static int queue_bulk_sg_tx(struct xhci_
                                        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 |
@@ -3316,7 +3320,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *
        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;
@@ -3362,7 +3366,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *
                                        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 |
@@ -3625,7 +3630,7 @@ static int xhci_queue_isoc_tx(struct xhc
                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)
@@ -3704,7 +3709,8 @@ static int xhci_queue_isoc_tx(struct xhc
                        } 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 |


Patches currently in stable-queue which might be from 
[email protected] are

queue-3.4/xhci-fix-null-pointer-dereference-when-destroying-half-built-segment-rings.patch
queue-3.4/xhci-fix-conditional-check-in-bandwidth-calculation.patch
queue-3.4/xhci-fix-td-size-calculation-on-1.0-hosts.patch
queue-3.4/usb-host-xhci-stricter-conditional-for-z1-system-models-for-compliance-mode-patch.patch
queue-3.4/xhci-add-lynx-point-lp-to-list-of-intel-switchable-hosts.patch
--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to