On Wed, Nov 13, 2013 at 12:28:09PM -0000, David Laight wrote:
> If URB_ZERO_PACKET is set on a transfer that is an integral number
> of maximum length packets (1k for USB3 bulk) then an additional
> zero length fragment must be sent.
>
> Merge together the functions that setup single buffer and scatter-gather
> transfers (they aren't that different) simplifying the logic as well.
>
> In particular we note that the number of TRB passed to prepare_ring()
> need only be an upper limit on the number required. However we do try
> to only request 1 TRB when we know one is sufficient.
>
> Signed-off-by: David Laight <[email protected]>
> ---
> Change for v2:
> - Ensure we check there is space for 1 TRB for zero length transfer requests.
> (The extra TRB is added in the same path that checks URB_ZERO_PACKET).
>
> I hope I've edited the patch correctly.
> I've NFI how to get git to generate modified patches.
git commit --amend
I'll look over this patch in a couple days. ISTR that someone else
submitted a zero-length packet fix patch, so I need to coordinate the
two.
Sarah Sharp
>
> drivers/usb/host/xhci-ring.c | 390
> +++++++++++--------------------------------
> drivers/usb/host/xhci.h | 1 +
> 2 files changed, 102 insertions(+), 290 deletions(-)
>
> diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
> index ace586c..7211223 100644
> --- a/drivers/usb/host/xhci-ring.c
> +++ b/drivers/usb/host/xhci-ring.c
> @@ -3082,55 +3082,6 @@ static int prepare_transfer(struct xhci_hcd *xhci,
> return 0;
> }
>
> -static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb
> *urb)
> -{
> - int num_sgs, num_trbs, running_total, temp, i;
> - struct scatterlist *sg;
> -
> - sg = NULL;
> - num_sgs = urb->num_mapped_sgs;
> - temp = urb->transfer_buffer_length;
> -
> - num_trbs = 0;
> - for_each_sg(urb->sg, sg, num_sgs, i) {
> - unsigned int len = sg_dma_len(sg);
> -
> - /* Scatter gather list entries may cross 64KB boundaries */
> - running_total = TRB_MAX_BUFF_SIZE -
> - (sg_dma_address(sg) & (TRB_MAX_BUFF_SIZE - 1));
> - running_total &= TRB_MAX_BUFF_SIZE - 1;
> - if (running_total != 0)
> - num_trbs++;
> -
> - /* How many more 64KB chunks to transfer, how many more TRBs? */
> - while (running_total < sg_dma_len(sg) && running_total < temp) {
> - num_trbs++;
> - running_total += TRB_MAX_BUFF_SIZE;
> - }
> - len = min_t(int, len, temp);
> - temp -= len;
> - if (temp == 0)
> - break;
> - }
> - return num_trbs;
> -}
> -
> -static void check_trb_math(struct urb *urb, int num_trbs, int running_total)
> -{
> - if (num_trbs != 0)
> - dev_err(&urb->dev->dev, "%s - ep %#x - Miscalculated number of "
> - "TRBs, %d left\n", __func__,
> - urb->ep->desc.bEndpointAddress, num_trbs);
> - if (running_total != urb->transfer_buffer_length)
> - dev_err(&urb->dev->dev, "%s - ep %#x - Miscalculated tx length,
> "
> - "queued %#x (%d), asked for %#x (%d)\n",
> - __func__,
> - urb->ep->desc.bEndpointAddress,
> - running_total, running_total,
> - urb->transfer_buffer_length,
> - urb->transfer_buffer_length);
> -}
> -
> static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id,
> unsigned int ep_index, unsigned int stream_id,
> struct xhci_generic_trb *start_trb)
> @@ -3232,285 +3183,145 @@ static u32 xhci_v1_0_td_remainder(int
> running_total, int trb_buff_len,
> return (total_packet_count - packets_transferred) << 17;
> }
>
> -static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
> +int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
> struct urb *urb, int slot_id, unsigned int ep_index)
> {
> struct xhci_ring *ep_ring;
> unsigned int num_trbs;
> struct urb_priv *urb_priv;
> - struct xhci_td *td;
> + u32 trb_buff_len, this_sg_len;
> struct scatterlist *sg;
> - int num_sgs;
> - int trb_buff_len, this_sg_len, running_total;
> - unsigned int total_packet_count;
> - u32 trb_cycle_invert;
> + u32 trb_type_flags;
> + u32 max_packet, td_residue, len_left;
> + u32 td_size;
> u64 addr;
> - bool more_trbs_coming;
> -
> - struct xhci_generic_trb *start_trb;
> + int ret;
>
> ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
> - if (!ep_ring)
> + if (unlikely(!ep_ring))
> return -EINVAL;
>
> - num_trbs = count_sg_trbs_needed(xhci, urb);
> - num_sgs = urb->num_mapped_sgs;
> - 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],
> - ep_index, urb->stream_id,
> - num_trbs, urb, 0, mem_flags);
> - if (trb_buff_len < 0)
> - return trb_buff_len;
> -
> - urb_priv = urb->hcpriv;
> - td = &urb_priv->td[0];
> -
> - /*
> - * Don't give the first TRB to the hardware (by toggling the cycle bit)
> - * until we've finished creating all the other TRBs. The ring's cycle
> - * state may change as we enqueue the other TRBs, so save it too.
> - */
> - start_trb = &ep_ring->enqueue->generic;
> -
> - running_total = 0;
> - /*
> - * How much data is in the first TRB?
> - *
> - * There are three forces at work for TRB buffer pointers and lengths:
> - * 1. We don't want to walk off the end of this sg-list entry buffer.
> - * 2. The transfer length that the driver requested may be smaller than
> - * the amount of memory allocated for this scatter-gather list.
> - * 3. TRBs buffers can't cross 64KB boundaries.
> - */
> - sg = urb->sg;
> - addr = (u64) sg_dma_address(sg);
> - this_sg_len = sg_dma_len(sg);
> - trb_buff_len = TRB_MAX_BUFF_SIZE - (addr & (TRB_MAX_BUFF_SIZE - 1));
> - trb_buff_len = min_t(int, trb_buff_len, this_sg_len);
> - if (trb_buff_len > urb->transfer_buffer_length)
> - trb_buff_len = urb->transfer_buffer_length;
> -
> - trb_cycle_invert = TRB_CYCLE;
> - /* Queue the first TRB, even if it's zero-length */
> - do {
> - u32 field = 0;
> - u32 length_field = 0;
> - u32 remainder = 0;
> -
> - field |= ep_ring->cycle_state;
> - /* Don't change the cycle bit of the first TRB until later */
> - field ^= trb_cycle_invert;
> - trb_cycle_invert = 0;
> -
> - /* Chain all the TRBs together; clear the chain bit in the last
> - * TRB to indicate it's the last TRB in the chain.
> - */
> - if (num_trbs > 1) {
> - field |= TRB_CHAIN;
> - } else {
> - /* FIXME - add check for ZERO_PACKET flag before this */
> - td->last_trb = ep_ring->enqueue;
> - field |= TRB_IOC;
> - }
> -
> - /* Only set interrupt on short packet for IN endpoints */
> - if (usb_urb_dir_in(urb))
> - field |= TRB_ISP;
> -
> - if (TRB_MAX_BUFF_SIZE -
> - (addr & (TRB_MAX_BUFF_SIZE - 1)) <
> trb_buff_len) {
> - xhci_warn(xhci, "WARN: sg dma xfer crosses 64KB
> boundaries!\n");
> - xhci_dbg(xhci, "Next boundary at %#x, end dma = %#x\n",
> - (unsigned int) (addr +
> TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1),
> - (unsigned int) addr + trb_buff_len);
> - }
> -
> - /* Set the TRB length, TD size, and interrupter fields. */
> - if (xhci->hci_version < 0x100) {
> - remainder = xhci_td_remainder(
> - urb->transfer_buffer_length -
> - running_total);
> - } else {
> - remainder = xhci_v1_0_td_remainder(running_total,
> - trb_buff_len, total_packet_count, urb,
> - num_trbs - 1);
> - }
> - length_field = TRB_LEN(trb_buff_len) |
> - remainder |
> - TRB_INTR_TARGET(0);
> -
> - if (num_trbs > 1)
> - more_trbs_coming = true;
> - else
> - more_trbs_coming = false;
> - queue_trb(xhci, ep_ring, more_trbs_coming,
> - lower_32_bits(addr),
> - upper_32_bits(addr),
> - length_field,
> - field | TRB_TYPE(TRB_NORMAL));
> - --num_trbs;
> - running_total += trb_buff_len;
> -
> - /* Calculate length for next transfer --
> - * Are we done queueing all the TRBs for this sg entry?
> + if (urb->num_sgs == 0) {
> + sg = NULL;
> + addr = (u64)urb->transfer_dma;
> + this_sg_len = urb->transfer_buffer_length;
> + num_trbs = 0;
> + } else {
> + sg = urb->sg;
> + addr = (u64)sg_dma_address(sg);
> + this_sg_len = sg_dma_len(sg);
> + /*
> + * We only need an upper bound for the number of TRBs.
> + * Add in two extra TRB for each subsequent segment.
> */
> - this_sg_len -= trb_buff_len;
> - if (this_sg_len == 0) {
> - --num_sgs;
> - if (num_sgs == 0)
> - break;
> - sg = sg_next(sg);
> - addr = (u64) sg_dma_address(sg);
> - this_sg_len = sg_dma_len(sg);
> - } else {
> - addr += trb_buff_len;
> - }
> -
> - trb_buff_len = TRB_MAX_BUFF_SIZE -
> - (addr & (TRB_MAX_BUFF_SIZE - 1));
> - trb_buff_len = min_t(int, trb_buff_len, this_sg_len);
> - if (running_total + trb_buff_len > urb->transfer_buffer_length)
> - trb_buff_len =
> - urb->transfer_buffer_length - running_total;
> - } while (running_total < urb->transfer_buffer_length);
> -
> - check_trb_math(urb, num_trbs, running_total);
> - giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, start_trb);
> - return 0;
> -}
> -
> -/* This is very similar to what ehci-q.c qtd_fill() does */
> -int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
> - struct urb *urb, int slot_id, unsigned int ep_index)
> -{
> - struct xhci_ring *ep_ring;
> - struct urb_priv *urb_priv;
> - struct xhci_td *td;
> - int num_trbs;
> - struct xhci_generic_trb *start_trb;
> - u32 trb_cycle_invert;
> - bool more_trbs_coming;
> - u32 field, length_field;
> -
> - int running_total, trb_buff_len, ret;
> - unsigned int total_packet_count;
> - u64 addr;
> -
> - if (urb->num_sgs)
> - return queue_bulk_sg_tx(xhci, mem_flags, urb, slot_id,
> ep_index);
> + num_trbs = (urb->num_mapped_sgs - 1) * 2;
> + }
>
> - ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
> - if (!ep_ring)
> - return -EINVAL;
> + /* One TRB for each 64k 'page' that contains data */
> + num_trbs += DIV_ROUND_UP((addr & (TRB_MAX_BUFF_SIZE - 1)) +
> + urb->transfer_buffer_length, TRB_MAX_BUFF_SIZE);
>
> - num_trbs = 0;
> - /* How much data is (potentially) left before the 64KB boundary? */
> - running_total = TRB_MAX_BUFF_SIZE -
> - (urb->transfer_dma & (TRB_MAX_BUFF_SIZE - 1));
> - running_total &= TRB_MAX_BUFF_SIZE - 1;
> + max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&urb->ep->desc));
>
> - /* If there's some data on this 64KB chunk, or we have to send a
> - * zero-length transfer, we need at least one TRB
> + /*
> + * For v 1.0 we need to calculate the number of TD needed to
> + * complete the transfer.
> + * The code here is equivalent to 4.11.2.4.
> */
> - if (running_total != 0 || urb->transfer_buffer_length == 0)
> - num_trbs++;
> - /* How many more 64KB chunks to transfer, how many more TRBs? */
> - while (running_total < urb->transfer_buffer_length) {
> + td_residue = urb->transfer_buffer_length;
> + if (unlikely(urb->transfer_flags & URB_ZERO_PACKET)
> + || unlikely(urb->transfer_buffer_length == 0)) {
> + /* We need an extra zero length TD */
> num_trbs++;
> - running_total += TRB_MAX_BUFF_SIZE;
> + td_residue++;
> }
> - /* FIXME: this doesn't deal with URB_ZERO_PACKET - need one more */
> + td_residue = ALIGN(td_residue, max_packet) + max_packet - 1;
>
> ret = prepare_transfer(xhci, xhci->devs[slot_id],
> ep_index, urb->stream_id,
> num_trbs, urb, 0, mem_flags);
> - if (ret < 0)
> + if (unlikely(ret < 0))
> return ret;
>
> - urb_priv = urb->hcpriv;
> - td = &urb_priv->td[0];
> + trb_type_flags = TRB_CYCLE | TRB_CHAIN | TRB_TYPE(TRB_NORMAL);
>
> - /*
> - * Don't give the first TRB to the hardware (by toggling the cycle bit)
> - * until we've finished creating all the other TRBs. The ring's cycle
> - * state may change as we enqueue the other TRBs, so save it too.
> - */
> - start_trb = &ep_ring->enqueue->generic;
> -
> - running_total = 0;
> - 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;
> - trb_buff_len = TRB_MAX_BUFF_SIZE -
> - (urb->transfer_dma & (TRB_MAX_BUFF_SIZE - 1));
> - if (trb_buff_len > urb->transfer_buffer_length)
> - trb_buff_len = urb->transfer_buffer_length;
> -
> - trb_cycle_invert = TRB_CYCLE;
> + /* Set interrupt on short packet for IN endpoints */
> + if (usb_urb_dir_in(urb))
> + trb_type_flags |= TRB_ISP;
>
> /* Queue the first TRB, even if it's zero-length */
> - do {
> - u32 remainder = 0;
> - field = 0;
> + len_left = urb->transfer_buffer_length;
> + for (;;) {
> + /*
> + * How much data is in the TRB?
> + *
> + * 1. TRBs buffers can't cross 64KB boundaries.
> + * 2. We don't want to walk off the end of this sg-list buffer.
> + * 2. Don't exceed the driver-supplied transfer length.
> + * (May be smaller than the sg list.)
> + */
> + trb_buff_len = (~addr & (TRB_MAX_BUFF_SIZE - 1)) + 1;
> + trb_buff_len = min_t(u32, trb_buff_len, this_sg_len);
> + trb_buff_len = min_t(u32, trb_buff_len, len_left);
> + td_residue -= trb_buff_len;
>
> - field |= ep_ring->cycle_state;
> - /* Don't change the cycle bit of the first TRB until later */
> - field ^= trb_cycle_invert;
> - trb_cycle_invert = 0;
> + /* TRB_CYCLE is inverted in the first TRB */
> + trb_type_flags ^= ep_ring->cycle_state;
>
> - /* Chain all the TRBs together; clear the chain bit in the last
> + /*
> + * Chain all the TRBs together; clear the chain bit in the last
> * TRB to indicate it's the last TRB in the chain.
> + * The td_residue can only be 2 * max_packet - 1 if
> + * URB_ZERO_PACKET was set, this forces a zero length packet.
> + * For version 1.0 we could send the last fragment with
> + * td_size set to 1 - but that is just extra logic.
> */
> - if (num_trbs > 1) {
> - field |= TRB_CHAIN;
> + if (trb_buff_len == len_left && (trb_buff_len == 0 ||
> + td_residue < 2 * max_packet - 1)) {
> + /* The last buffer fragment */
> + urb_priv = urb->hcpriv;
> + urb_priv->td[0].last_trb = ep_ring->enqueue;
> + /* Set TRB_IOC and clear TRB_CHAIN */
> + trb_type_flags ^= TRB_IOC | TRB_CHAIN;
> + td_size = 0;
> } else {
> - /* FIXME - add check for ZERO_PACKET flag before this */
> - td->last_trb = ep_ring->enqueue;
> - field |= TRB_IOC;
> + if (xhci->hci_version < 0x100)
> + td_size = xhci_td_remainder(len_left);
> + else
> + td_size = TRB_TD_SIZE(td_residue / max_packet);
> }
>
> - /* Only set interrupt on short packet for IN endpoints */
> - if (usb_urb_dir_in(urb))
> - field |= TRB_ISP;
> + /* No need to specify 'more_trbs_coming', implied by CHAIN */
> + queue_trb(xhci, ep_ring, false,
> + lower_32_bits(addr),
> + upper_32_bits(addr),
> + TRB_LEN(trb_buff_len) | td_size |
> + TRB_INTR_TARGET(0),
> + trb_type_flags);
> +
> + if (!(trb_type_flags & TRB_CHAIN))
> + break;
> +
> + /* We want the current TRB_CYCLE in subsequent TRB */
> + trb_type_flags &= ~TRB_CYCLE;
>
> - /* Set the TRB length, TD size, and interrupter fields. */
> - if (xhci->hci_version < 0x100) {
> - remainder = xhci_td_remainder(
> - urb->transfer_buffer_length -
> - running_total);
> + /* Advance everything past this segment */
> + len_left -= trb_buff_len;
> + this_sg_len -= trb_buff_len;
> + if (this_sg_len == 0 && len_left != 0) {
> + sg = sg_next(sg);
> + addr = (u64)sg_dma_address(sg);
> + this_sg_len = sg_dma_len(sg);
> } else {
> - remainder = xhci_v1_0_td_remainder(running_total,
> - trb_buff_len, total_packet_count, urb,
> - num_trbs - 1);
> + /* Buffer was split on 64k boundary.
> + * Or we need to send a zero length packet. */
> + addr += trb_buff_len;
> }
> - length_field = TRB_LEN(trb_buff_len) |
> - remainder |
> - TRB_INTR_TARGET(0);
> + }
>
> - if (num_trbs > 1)
> - more_trbs_coming = true;
> - else
> - more_trbs_coming = false;
> - queue_trb(xhci, ep_ring, more_trbs_coming,
> - lower_32_bits(addr),
> - upper_32_bits(addr),
> - length_field,
> - field | TRB_TYPE(TRB_NORMAL));
> - --num_trbs;
> - running_total += trb_buff_len;
> -
> - /* Calculate length for next transfer */
> - addr += trb_buff_len;
> - trb_buff_len = urb->transfer_buffer_length - running_total;
> - if (trb_buff_len > TRB_MAX_BUFF_SIZE)
> - trb_buff_len = TRB_MAX_BUFF_SIZE;
> - } while (running_total < urb->transfer_buffer_length);
> -
> - check_trb_math(urb, num_trbs, running_total);
> - giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, start_trb);
> + urb_priv = urb->hcpriv;
> + giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
> + &urb_priv->td[0].first_trb->generic);
> return 0;
> }
>
> diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
> index 118f90b..bbdbfed 100644
> --- a/drivers/usb/host/xhci.h
> +++ b/drivers/usb/host/xhci.h
> @@ -1123,6 +1123,7 @@ struct xhci_event_cmd {
> /* Normal TRB fields */
> /* transfer_len bitmasks - bits 0:16 */
> #define TRB_LEN(p) ((p) & 0x1ffff)
> +#define TRB_TD_SIZE(p) (min_t(u32, (p), 31) << 17)
> /* Interrupter Target - which MSI-X vector to target the completion event at
> */
> #define TRB_INTR_TARGET(p) (((p) & 0x3ff) << 22)
> #define GET_INTR_TARGET(p) (((p) >> 22) & 0x3ff)
> --
> 1.8.1.2
>
>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html