Commit 04dd950d authored by Sarah Sharp's avatar Sarah Sharp Committed by Greg Kroah-Hartman

USB: xhci: Set transfer descriptor size field correctly.

The transfer descriptor (TD) is a series of transfer request buffers
(TRBs) that describe the buffer pointer, length, and other
characteristics.  The xHCI controllers want to know an estimate of how
long the TD is, for caching reasons.  In each TRB, there is a "TD size"
field that provides a rough estimate of the remaining buffers to be
transmitted, including the buffer pointed to by that TRB.

The TD size is 5 bits long, and contains the remaining size in bytes,
right shifted by 10 bits.  So a remaining TD size less than 1024 would get
a zero in the TD size field, and a remaining size greater than 32767 would
get 31 in the field.

This patches fixes a bug in the TD_REMAINDER macro that is triggered when
the URB has a scatter gather list with a size bigger than 32767 bytes.
Not all host controllers pay attention to the TD size field, so the bug
will not appear on all USB 3.0 hosts.
Signed-off-by: default avatarSarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent f176a5d8
...@@ -1699,6 +1699,21 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags, ...@@ -1699,6 +1699,21 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
return xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index); return xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index);
} }
/*
* The TD size is the number of bytes remaining in the TD (including this TRB),
* right shifted by 10.
* It must fit in bits 21:17, so it can't be bigger than 31.
*/
static u32 xhci_td_remainder(unsigned int remainder)
{
u32 max = (1 << (21 - 17 + 1)) - 1;
if ((remainder >> 10) >= max)
return max << 17;
else
return (remainder >> 10) << 17;
}
static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
struct urb *urb, int slot_id, unsigned int ep_index) struct urb *urb, int slot_id, unsigned int ep_index)
{ {
...@@ -1756,6 +1771,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, ...@@ -1756,6 +1771,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
do { do {
u32 field = 0; u32 field = 0;
u32 length_field = 0; u32 length_field = 0;
u32 remainder = 0;
/* Don't change the cycle bit of the first TRB until later */ /* Don't change the cycle bit of the first TRB until later */
if (first_trb) if (first_trb)
...@@ -1785,8 +1801,10 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, ...@@ -1785,8 +1801,10 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
(unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1), (unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1),
(unsigned int) addr + trb_buff_len); (unsigned int) addr + trb_buff_len);
} }
remainder = xhci_td_remainder(urb->transfer_buffer_length -
running_total) ;
length_field = TRB_LEN(trb_buff_len) | length_field = TRB_LEN(trb_buff_len) |
TD_REMAINDER(urb->transfer_buffer_length - running_total) | remainder |
TRB_INTR_TARGET(0); TRB_INTR_TARGET(0);
queue_trb(xhci, ep_ring, false, queue_trb(xhci, ep_ring, false,
lower_32_bits(addr), lower_32_bits(addr),
...@@ -1899,6 +1917,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, ...@@ -1899,6 +1917,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
/* Queue the first TRB, even if it's zero-length */ /* Queue the first TRB, even if it's zero-length */
do { do {
u32 remainder = 0;
field = 0; field = 0;
/* Don't change the cycle bit of the first TRB until later */ /* Don't change the cycle bit of the first TRB until later */
...@@ -1917,8 +1936,10 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, ...@@ -1917,8 +1936,10 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
td->last_trb = ep_ring->enqueue; td->last_trb = ep_ring->enqueue;
field |= TRB_IOC; field |= TRB_IOC;
} }
remainder = xhci_td_remainder(urb->transfer_buffer_length -
running_total);
length_field = TRB_LEN(trb_buff_len) | length_field = TRB_LEN(trb_buff_len) |
TD_REMAINDER(urb->transfer_buffer_length - running_total) | remainder |
TRB_INTR_TARGET(0); TRB_INTR_TARGET(0);
queue_trb(xhci, ep_ring, false, queue_trb(xhci, ep_ring, false,
lower_32_bits(addr), lower_32_bits(addr),
...@@ -2006,7 +2027,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, ...@@ -2006,7 +2027,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
/* If there's data, queue data TRBs */ /* If there's data, queue data TRBs */
field = 0; field = 0;
length_field = TRB_LEN(urb->transfer_buffer_length) | length_field = TRB_LEN(urb->transfer_buffer_length) |
TD_REMAINDER(urb->transfer_buffer_length) | xhci_td_remainder(urb->transfer_buffer_length) |
TRB_INTR_TARGET(0); TRB_INTR_TARGET(0);
if (urb->transfer_buffer_length > 0) { if (urb->transfer_buffer_length > 0) {
if (setup->bRequestType & USB_DIR_IN) if (setup->bRequestType & USB_DIR_IN)
......
...@@ -828,9 +828,6 @@ struct xhci_event_cmd { ...@@ -828,9 +828,6 @@ struct xhci_event_cmd {
/* Normal TRB fields */ /* Normal TRB fields */
/* transfer_len bitmasks - bits 0:16 */ /* transfer_len bitmasks - bits 0:16 */
#define TRB_LEN(p) ((p) & 0x1ffff) #define TRB_LEN(p) ((p) & 0x1ffff)
/* TD size - number of bytes remaining in the TD (including this TRB):
* bits 17 - 21. Shift the number of bytes by 10. */
#define TD_REMAINDER(p) ((((p) >> 10) & 0x1f) << 17)
/* Interrupter Target - which MSI-X vector to target the completion event at */ /* Interrupter Target - which MSI-X vector to target the completion event at */
#define TRB_INTR_TARGET(p) (((p) & 0x3ff) << 22) #define TRB_INTR_TARGET(p) (((p) & 0x3ff) << 22)
#define GET_INTR_TARGET(p) (((p) >> 22) & 0x3ff) #define GET_INTR_TARGET(p) (((p) >> 22) & 0x3ff)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment