aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2011-08-12 13:23:01 -0400
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2011-08-16 19:46:57 -0400
commit48df4a6fd8c40c0bbcbca2044f5f2bc75dcf6db1 (patch)
tree3c1ab23559595b3a2b7cc5955a623f9f3222ae59 /drivers
parent8a9af4fdf6d5eeb3200a088354d266a87e8260b0 (diff)
xhci: Handle zero-length isochronous packets.
For a long time, the xHCI driver has had this note: /* FIXME: Ignoring zero-length packets, can those happen? */ It turns out that, yes, there are drivers that need to queue zero-length transfers for isochronous OUT transfers. Without this patch, users will see kernel hang messages when a driver attempts to enqueue an isochronous URB with a zero length transfer (because count_isoc_trbs_needed will return zero for that TD, xhci_td->last_trb will never be set, and updating the dequeue pointer will cause an infinite loop). Matěj ran into this issue when using an NI Audio4DJ USB soundcard with the snd-usb-caiaq driver. See https://bugzilla.kernel.org/show_bug.cgi?id=40702 Fix count_isoc_trbs_needed() to return 1 for zero-length transfers (thanks Alan on the math help). Update the various TRB field calculations to deal with zero-length transfers. We're still transferring one packet with a zero-length data payload, so the total_packet_count should be 1. The Transfer Burst Count (TBC) and Transfer Last Burst Packet Count (TLBPC) fields should be set to zero. This patch should be backported to kernels as old as 2.6.36. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Tested-by: Matěj Laitl <matej@laitl.cz> Cc: Daniel Mack <zonque@gmail.com> Cc: Alan Stern <stern@rowland.harvard.edu> Cc: stable@kernel.org
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/host/xhci-ring.c21
1 files changed, 11 insertions, 10 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index b2d654b7477e..54139a2f06ce 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2684,6 +2684,10 @@ static u32 xhci_v1_0_td_remainder(int running_total, int trb_buff_len,
2684{ 2684{
2685 int packets_transferred; 2685 int packets_transferred;
2686 2686
2687 /* One TRB with a zero-length data packet. */
2688 if (running_total == 0 && trb_buff_len == 0)
2689 return 0;
2690
2687 /* All the TRB queueing functions don't count the current TRB in 2691 /* All the TRB queueing functions don't count the current TRB in
2688 * running_total. 2692 * running_total.
2689 */ 2693 */
@@ -3125,20 +3129,15 @@ static int count_isoc_trbs_needed(struct xhci_hcd *xhci,
3125 struct urb *urb, int i) 3129 struct urb *urb, int i)
3126{ 3130{
3127 int num_trbs = 0; 3131 int num_trbs = 0;
3128 u64 addr, td_len, running_total; 3132 u64 addr, td_len;
3129 3133
3130 addr = (u64) (urb->transfer_dma + urb->iso_frame_desc[i].offset); 3134 addr = (u64) (urb->transfer_dma + urb->iso_frame_desc[i].offset);
3131 td_len = urb->iso_frame_desc[i].length; 3135 td_len = urb->iso_frame_desc[i].length;
3132 3136
3133 running_total = TRB_MAX_BUFF_SIZE - (addr & (TRB_MAX_BUFF_SIZE - 1)); 3137 num_trbs = DIV_ROUND_UP(td_len + (addr & (TRB_MAX_BUFF_SIZE - 1)),
3134 running_total &= TRB_MAX_BUFF_SIZE - 1; 3138 TRB_MAX_BUFF_SIZE);
3135 if (running_total != 0) 3139 if (num_trbs == 0)
3136 num_trbs++;
3137
3138 while (running_total < td_len) {
3139 num_trbs++; 3140 num_trbs++;
3140 running_total += TRB_MAX_BUFF_SIZE;
3141 }
3142 3141
3143 return num_trbs; 3142 return num_trbs;
3144} 3143}
@@ -3250,9 +3249,11 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
3250 addr = start_addr + urb->iso_frame_desc[i].offset; 3249 addr = start_addr + urb->iso_frame_desc[i].offset;
3251 td_len = urb->iso_frame_desc[i].length; 3250 td_len = urb->iso_frame_desc[i].length;
3252 td_remain_len = td_len; 3251 td_remain_len = td_len;
3253 /* FIXME: Ignoring zero-length packets, can those happen? */
3254 total_packet_count = roundup(td_len, 3252 total_packet_count = roundup(td_len,
3255 le16_to_cpu(urb->ep->desc.wMaxPacketSize)); 3253 le16_to_cpu(urb->ep->desc.wMaxPacketSize));
3254 /* A zero-length transfer still involves at least one packet. */
3255 if (total_packet_count == 0)
3256 total_packet_count++;
3256 burst_count = xhci_get_burst_count(xhci, urb->dev, urb, 3257 burst_count = xhci_get_burst_count(xhci, urb->dev, urb,
3257 total_packet_count); 3258 total_packet_count);
3258 residue = xhci_get_last_burst_packet_count(xhci, 3259 residue = xhci_get_last_burst_packet_count(xhci,