On Tue, Nov 5, 2013 at 6:21 AM, David Laight <David.Laight@xxxxxxxxxx> wrote: > > Close inspection shows that xhci_queue_isoc_tx() can only fail if > prepare_transfer() gets an error from usb_hcd_link_urb_to_ep() for > the first TD. The call to prepare_ring() cannot fail because an initial > check is made to ensure the ring has enough space for all the TD. > > The check for 'num_tds' being negative is pointless here, and the > check of the 'running_total' is looking for a simple coding error, > both can be deleted. > > Isoc setup is the only code path that calls prepare_transfer() with > ts_index != 0 so there is no point calling prepare_ring() again. > > prepare_ring() is still called twice for the first TD. > However since prepare_tranfser() doesn't depend on the number of TD > the initial prepare_ring() can be replaced by prepare_transfer() > and the existing prepare_transfer() call only made for subsequent TD. > > This all means that xhci_queue_isoc_tx() can no longer fail. > Delete the (possibly dubious) 'cleanup' code and change the return > type to void. > > Signed-off-by: David Laight <david.laight@xxxxxxxxxx> > --- > This is compile tested only because I don't have an isoc device. > However it should be ok. > I've just ordered a cheap USB 'sound card' - presumably that > will let me test isochronous transfers. > > Note: This patch will only apply cleanly if my earlier patches are applied first. > --- > drivers/usb/host/xhci-ring.c | 90 +++++++++++++------------------------------- > drivers/usb/host/xhci.h | 1 - > 2 files changed, 27 insertions(+), 64 deletions(-) > > diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c > index d0ef8b8..5480215 100644 > --- a/drivers/usb/host/xhci-ring.c > +++ b/drivers/usb/host/xhci-ring.c > @@ -2991,7 +2991,7 @@ static int prepare_transfer(struct xhci_hcd *xhci, > struct urb_priv *urb_priv; > struct xhci_td *td; > struct xhci_ring *ep_ring; > - struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); > + struct xhci_ep_ctx *ep_ctx; > > ep_ring = xhci_stream_id_to_ring(xdev, ep_index, stream_id); > if (!ep_ring) { > @@ -3000,24 +3000,26 @@ static int prepare_transfer(struct xhci_hcd *xhci, > return -EINVAL; > } > > - ret = prepare_ring(xhci, ep_ring, > - le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK, > - num_trbs, mem_flags); > - if (ret) > - return ret; > - > - urb_priv = urb->hcpriv; > - td = &urb_priv->td[td_index]; > + if (td_index == 0) { > + ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); > > - INIT_LIST_HEAD(&td->td_list); > - INIT_LIST_HEAD(&td->cancelled_td_list); > + ret = prepare_ring(xhci, ep_ring, > + le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK, > + num_trbs, mem_flags); > + if (unlikely(ret)) > + return ret; > > - if (td_index == 0) { > ret = usb_hcd_link_urb_to_ep(bus_to_hcd(urb->dev->bus), urb); > if (unlikely(ret)) > return ret; > } > > + urb_priv = urb->hcpriv; > + td = &urb_priv->td[td_index]; > + > + INIT_LIST_HEAD(&td->td_list); > + INIT_LIST_HEAD(&td->cancelled_td_list); > + > td->urb = urb; > /* Add this TD to the tail of the endpoint ring's TD list */ > list_add_tail(&td->td_list, &ep_ring->td_list); > @@ -3647,7 +3649,7 @@ static unsigned int xhci_get_last_burst_packet_count(struct xhci_hcd *xhci, > } > > /* This is for isoc transfer */ > -static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, > +static void xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, > struct urb *urb, int slot_id, unsigned int ep_index) > { > struct xhci_ring *ep_ring; > @@ -3657,7 +3659,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, > struct xhci_generic_trb *start_trb; > bool first_trb; > u32 field, length_field; > - int running_total, trb_buff_len, td_len, td_remain_len, ret; > + int running_total, trb_buff_len, td_len, td_remain_len; > u64 start_addr, addr; > int i, j; > bool more_trbs_coming; > @@ -3665,10 +3667,6 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, > ep_ring = xhci->devs[slot_id]->eps[ep_index].ring; > > num_tds = urb->number_of_packets; > - if (num_tds < 1) { > - xhci_dbg(xhci, "Isoc URB with zero packets?\n"); > - return -EINVAL; > - } > > start_addr = (u64) urb->transfer_dma; > start_trb = &ep_ring->enqueue->generic; > @@ -3698,13 +3696,13 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, > > trbs_per_td = count_isoc_trbs_needed(xhci, urb, i); > > - ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, > - urb->stream_id, trbs_per_td, urb, i, mem_flags); > - if (ret < 0) { > - if (i == 0) > - return ret; > - goto cleanup; > - } > + /* prepare_transfer() was called earlier for the first TRB. > + * It cannot fail for later TRBs. > + */ > + if (i != 0) > + prepare_transfer(xhci, xhci->devs[slot_id], ep_index, > + urb->stream_id, trbs_per_td, urb, i, > + mem_flags); > > td = &urb_priv->td[i]; > for (j = 0; j < trbs_per_td; j++) { > @@ -3782,13 +3780,6 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, > addr += trb_buff_len; > td_remain_len -= trb_buff_len; > } > - > - /* Check TD length */ > - if (running_total != td_len) { > - xhci_err(xhci, "ISOC TD length unmatch\n"); > - ret = -EINVAL; > - goto cleanup; > - } > } > > if (xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs == 0) { > @@ -3798,31 +3789,6 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, > xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs++; > > giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, start_trb); > - return 0; > -cleanup: > - /* Clean up a partially enqueued isoc transfer. */ > - > - for (i--; i >= 0; i--) > - list_del_init(&urb_priv->td[i].td_list); > - > - /* Use the first TD as a temporary variable to turn the TDs we've queued > - * into No-ops with a software-owned cycle bit. That way the hardware > - * won't accidentally start executing bogus TDs when we partially > - * overwrite them. td->first_trb and td->start_seg are already set. > - */ > - urb_priv->td[0].last_trb = ep_ring->enqueue; > - /* Every TRB except the first & last will have its cycle bit flipped. */ > - td_to_noop(xhci, ep_ring, &urb_priv->td[0], true); > - > - /* Reset the ring enqueue back to the first TRB and its cycle bit. */ > - ep_ring->enqueue = urb_priv->td[0].first_trb; > - ep_ring->enq_seg = urb_priv->td[0].start_seg; > - /* The cycle bit in the first TRB won't be modified, get its inverse. */ > - ep_ring->cycle_state = (ep_ring->enqueue->generic.field[3] & > - TRB_CYCLE) ^ TRB_CYCLE; > - ep_ring->num_trbs_free = ep_ring->num_trbs_free_temp; > - usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb); > - return ret; > } This code is there for a reason. See commit 522989a27c7badb608155b1f1dea3487ed431f74 for details. Also, do you remove the return 0 sentence on purpose? Thanks, Andiry > > /* > @@ -3836,7 +3802,6 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, > struct urb *urb, int slot_id, unsigned int ep_index) > { > struct xhci_virt_device *xdev; > - struct xhci_ring *ep_ring; > struct xhci_ep_ctx *ep_ctx; > int start_frame; > int xhci_interval; > @@ -3845,7 +3810,6 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, > int ret; > > xdev = xhci->devs[slot_id]; > - ep_ring = xdev->eps[ep_index].ring; > ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); > > num_trbs = 0; > @@ -3856,8 +3820,8 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, > /* Check the ring to guarantee there is enough room for the whole urb. > * Do not insert any td of the urb to the ring if the check failed. > */ > - ret = prepare_ring(xhci, ep_ring, le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK, > - num_trbs, mem_flags); > + ret = prepare_transfer(xhci, xdev, ep_index, > + urb->stream_id, num_trbs, urb, 0, mem_flags); > if (ret) > return ret; > > @@ -3889,9 +3853,9 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, > urb->dev->speed == USB_SPEED_FULL) > urb->interval /= 8; > } > - ep_ring->num_trbs_free_temp = ep_ring->num_trbs_free; > > - return xhci_queue_isoc_tx(xhci, mem_flags, urb, slot_id, ep_index); > + xhci_queue_isoc_tx(xhci, mem_flags, urb, slot_id, ep_index); > + return 0; > } > > /**** Command Ring Operations ****/ > diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h > index a7d8fdd..118f90b 100644 > --- a/drivers/usb/host/xhci.h > +++ b/drivers/usb/host/xhci.h > @@ -1331,7 +1331,6 @@ struct xhci_ring { > unsigned int stream_id; > unsigned int num_segs; > unsigned int num_trbs_free; > - unsigned int num_trbs_free_temp; > enum xhci_ring_type type; > bool last_td_was_short; > }; > -- > 1.8.1.2 > > > > -- > To unsubscribe from this list: send the line "unsubscribe linux-usb" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html