Skip to content

Commit 4525c0a

Browse files
author
Sarah Sharp
committed
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 4da6e6f "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]> Cc: [email protected]
1 parent 392a07a commit 4525c0a

File tree

1 file changed

+19
-13
lines changed

1 file changed

+19
-13
lines changed

drivers/usb/host/xhci-ring.c

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3071,27 +3071,28 @@ static u32 xhci_td_remainder(unsigned int remainder)
30713071
}
30723072

30733073
/*
3074-
* For xHCI 1.0 host controllers, TD size is the number of packets remaining in
3075-
* the TD (*not* including this TRB).
3074+
* For xHCI 1.0 host controllers, TD size is the number of max packet sized
3075+
* packets remaining in the TD (*not* including this TRB).
30763076
*
30773077
* Total TD packet count = total_packet_count =
3078-
* roundup(TD size in bytes / wMaxPacketSize)
3078+
* DIV_ROUND_UP(TD size in bytes / wMaxPacketSize)
30793079
*
30803080
* Packets transferred up to and including this TRB = packets_transferred =
30813081
* rounddown(total bytes transferred including this TRB / wMaxPacketSize)
30823082
*
30833083
* TD size = total_packet_count - packets_transferred
30843084
*
30853085
* It must fit in bits 21:17, so it can't be bigger than 31.
3086+
* The last TRB in a TD must have the TD size set to zero.
30863087
*/
3087-
30883088
static u32 xhci_v1_0_td_remainder(int running_total, int trb_buff_len,
3089-
unsigned int total_packet_count, struct urb *urb)
3089+
unsigned int total_packet_count, struct urb *urb,
3090+
unsigned int num_trbs_left)
30903091
{
30913092
int packets_transferred;
30923093

30933094
/* One TRB with a zero-length data packet. */
3094-
if (running_total == 0 && trb_buff_len == 0)
3095+
if (num_trbs_left == 0 || (running_total == 0 && trb_buff_len == 0))
30953096
return 0;
30963097

30973098
/* 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,
31003101
packets_transferred = (running_total + trb_buff_len) /
31013102
usb_endpoint_maxp(&urb->ep->desc);
31023103

3103-
return xhci_td_remainder(total_packet_count - packets_transferred);
3104+
if ((total_packet_count - packets_transferred) > 31)
3105+
return 31 << 17;
3106+
return (total_packet_count - packets_transferred) << 17;
31043107
}
31053108

31063109
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,
31273130

31283131
num_trbs = count_sg_trbs_needed(xhci, urb);
31293132
num_sgs = urb->num_mapped_sgs;
3130-
total_packet_count = roundup(urb->transfer_buffer_length,
3133+
total_packet_count = DIV_ROUND_UP(urb->transfer_buffer_length,
31313134
usb_endpoint_maxp(&urb->ep->desc));
31323135

31333136
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,
32103213
running_total);
32113214
} else {
32123215
remainder = xhci_v1_0_td_remainder(running_total,
3213-
trb_buff_len, total_packet_count, urb);
3216+
trb_buff_len, total_packet_count, urb,
3217+
num_trbs - 1);
32143218
}
32153219
length_field = TRB_LEN(trb_buff_len) |
32163220
remainder |
@@ -3318,7 +3322,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
33183322
start_cycle = ep_ring->cycle_state;
33193323

33203324
running_total = 0;
3321-
total_packet_count = roundup(urb->transfer_buffer_length,
3325+
total_packet_count = DIV_ROUND_UP(urb->transfer_buffer_length,
33223326
usb_endpoint_maxp(&urb->ep->desc));
33233327
/* How much data is in the first TRB? */
33243328
addr = (u64) urb->transfer_dma;
@@ -3364,7 +3368,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
33643368
running_total);
33653369
} else {
33663370
remainder = xhci_v1_0_td_remainder(running_total,
3367-
trb_buff_len, total_packet_count, urb);
3371+
trb_buff_len, total_packet_count, urb,
3372+
num_trbs - 1);
33683373
}
33693374
length_field = TRB_LEN(trb_buff_len) |
33703375
remainder |
@@ -3627,7 +3632,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
36273632
addr = start_addr + urb->iso_frame_desc[i].offset;
36283633
td_len = urb->iso_frame_desc[i].length;
36293634
td_remain_len = td_len;
3630-
total_packet_count = roundup(td_len,
3635+
total_packet_count = DIV_ROUND_UP(td_len,
36313636
usb_endpoint_maxp(&urb->ep->desc));
36323637
/* A zero-length transfer still involves at least one packet. */
36333638
if (total_packet_count == 0)
@@ -3706,7 +3711,8 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
37063711
} else {
37073712
remainder = xhci_v1_0_td_remainder(
37083713
running_total, trb_buff_len,
3709-
total_packet_count, urb);
3714+
total_packet_count, urb,
3715+
(trbs_per_td - j - 1));
37103716
}
37113717
length_field = TRB_LEN(trb_buff_len) |
37123718
remainder |

0 commit comments

Comments
 (0)