On Tue, Jul 20, 2010 at 04:49:17PM +0800, Andiry Xu wrote: > >From aa8672e3977e3ebfdcf435a0de9860eb86bb8b68 Mon Sep 17 00:00:00 2001 > From: Andiry Xu <andiry.xu@xxxxxxx> > Date: Thu, 15 Jul 2010 15:36:32 +0800 > Subject: [PATCH 03/10] xHCI: handle_tx_event() refactor: process_bulk_intr_td > > This patch moves the bulk and interrupt td processing part in > handle_tx_event() into a separate function process_bulk_intr_td(). > > Signed-off-by: Andiry Xu <andiry.xu@xxxxxxx> Signed-off-by: Sarah Sharp <sarah.a.sharp@xxxxxxxxxxxxxxx> > --- > drivers/usb/host/xhci-ring.c | 216 ++++++++++++++++++++++-------------------- > 1 files changed, 115 insertions(+), 101 deletions(-) > > diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c > index e28cfd1..83580cf 100644 > --- a/drivers/usb/host/xhci-ring.c > +++ b/drivers/usb/host/xhci-ring.c > @@ -1459,6 +1459,117 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, > } > > /* > + * Process bulk and interrupt tds, update urb status and actual_length. > + */ > +static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, > + union xhci_trb *event_trb, struct xhci_transfer_event *event, > + struct xhci_virt_ep *ep, int *status) > +{ > + struct xhci_ring *ep_ring; > + union xhci_trb *cur_trb; > + struct xhci_segment *cur_seg; > + u32 trb_comp_code; > + > + ep_ring = xhci_dma_to_transfer_ring(ep, event->buffer); > + trb_comp_code = GET_COMP_CODE(event->transfer_len); > + > + switch (trb_comp_code) { > + case COMP_SUCCESS: > + /* Double check that the HW transferred everything. */ > + if (event_trb != td->last_trb) { > + xhci_warn(xhci, "WARN Successful completion " > + "on short TX\n"); > + if (td->urb->transfer_flags & URB_SHORT_NOT_OK) > + *status = -EREMOTEIO; > + else > + *status = 0; > + } else { > + if (usb_endpoint_xfer_bulk(&td->urb->ep->desc)) > + xhci_dbg(xhci, "Successful bulk " > + "transfer!\n"); > + else > + xhci_dbg(xhci, "Successful interrupt " > + "transfer!\n"); > + *status = 0; > + } > + break; > + case COMP_SHORT_TX: > + if (td->urb->transfer_flags & URB_SHORT_NOT_OK) > + *status = -EREMOTEIO; > + else > + *status = 0; > + break; > + default: > + /* Others already handled above */ > + break; > + } > + dev_dbg(&td->urb->dev->dev, > + "ep %#x - asked for %d bytes, " > + "%d bytes untransferred\n", > + td->urb->ep->desc.bEndpointAddress, > + td->urb->transfer_buffer_length, > + TRB_LEN(event->transfer_len)); > + /* Fast path - was this the last TRB in the TD for this URB? */ > + if (event_trb == td->last_trb) { > + if (TRB_LEN(event->transfer_len) != 0) { > + td->urb->actual_length = > + td->urb->transfer_buffer_length - > + TRB_LEN(event->transfer_len); > + if (td->urb->transfer_buffer_length < > + td->urb->actual_length) { > + xhci_warn(xhci, "HC gave bad length " > + "of %d bytes left\n", > + TRB_LEN(event->transfer_len)); > + td->urb->actual_length = 0; > + if (td->urb->transfer_flags & URB_SHORT_NOT_OK) > + *status = -EREMOTEIO; > + else > + *status = 0; > + } > + /* Don't overwrite a previously set error code */ > + if (*status == -EINPROGRESS) { > + if (td->urb->transfer_flags & URB_SHORT_NOT_OK) > + *status = -EREMOTEIO; > + else > + *status = 0; > + } > + } else { > + td->urb->actual_length = > + td->urb->transfer_buffer_length; > + /* Ignore a short packet completion if the > + * untransferred length was zero. > + */ > + if (*status == -EREMOTEIO) > + *status = 0; > + } > + } else { > + /* Slow path - walk the list, starting from the dequeue > + * pointer, to get the actual length transferred. > + */ > + td->urb->actual_length = 0; > + for (cur_trb = ep_ring->dequeue, cur_seg = ep_ring->deq_seg; > + cur_trb != event_trb; > + next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) { > + if ((cur_trb->generic.field[3] & > + TRB_TYPE_BITMASK) != TRB_TYPE(TRB_TR_NOOP) && > + (cur_trb->generic.field[3] & > + TRB_TYPE_BITMASK) != TRB_TYPE(TRB_LINK)) > + td->urb->actual_length += > + TRB_LEN(cur_trb->generic.field[2]); > + } > + /* If the ring didn't stop on a Link or No-op TRB, add > + * in the actual bytes transferred from the Normal TRB > + */ > + if (trb_comp_code != COMP_STOP_INVAL) > + td->urb->actual_length += > + TRB_LEN(cur_trb->generic.field[2]) - > + TRB_LEN(event->transfer_len); > + } > + > + return finish_td(xhci, td, event_trb, event, ep, status, false); > +} > + > +/* > * If this function returns an error condition, it means it got a Transfer > * event with a corrupted Slot ID, Endpoint ID, or TRB DMA address. > * At this point, the host controller is probably hosed and should be reset. > @@ -1584,109 +1695,12 @@ static int handle_tx_event(struct xhci_hcd *xhci, > } > /* Now update the urb's actual_length and give back to the core */ > /* Was this a control transfer? */ > - if (usb_endpoint_xfer_control(&td->urb->ep->desc)) { > + if (usb_endpoint_xfer_control(&td->urb->ep->desc)) > ret = process_ctrl_td(xhci, td, event_trb, event, ep, > &status); > - goto cleanup; > - } else { > - switch (trb_comp_code) { > - case COMP_SUCCESS: > - /* Double check that the HW transferred everything. */ > - if (event_trb != td->last_trb) { > - xhci_warn(xhci, "WARN Successful completion " > - "on short TX\n"); > - if (td->urb->transfer_flags & URB_SHORT_NOT_OK) > - status = -EREMOTEIO; > - else > - status = 0; > - } else { > - if (usb_endpoint_xfer_bulk(&td->urb->ep->desc)) > - xhci_dbg(xhci, "Successful bulk " > - "transfer!\n"); > - else > - xhci_dbg(xhci, "Successful interrupt " > - "transfer!\n"); > - status = 0; > - } > - break; > - case COMP_SHORT_TX: > - if (td->urb->transfer_flags & URB_SHORT_NOT_OK) > - status = -EREMOTEIO; > - else > - status = 0; > - break; > - default: > - /* Others already handled above */ > - break; > - } > - dev_dbg(&td->urb->dev->dev, > - "ep %#x - asked for %d bytes, " > - "%d bytes untransferred\n", > - td->urb->ep->desc.bEndpointAddress, > - td->urb->transfer_buffer_length, > - TRB_LEN(event->transfer_len)); > - /* Fast path - was this the last TRB in the TD for this URB? */ > - if (event_trb == td->last_trb) { > - if (TRB_LEN(event->transfer_len) != 0) { > - td->urb->actual_length = > - td->urb->transfer_buffer_length - > - TRB_LEN(event->transfer_len); > - if (td->urb->transfer_buffer_length < > - td->urb->actual_length) { > - xhci_warn(xhci, "HC gave bad length " > - "of %d bytes left\n", > - TRB_LEN(event->transfer_len)); > - td->urb->actual_length = 0; > - if (td->urb->transfer_flags & > - URB_SHORT_NOT_OK) > - status = -EREMOTEIO; > - else > - status = 0; > - } > - /* Don't overwrite a previously set error code */ > - if (status == -EINPROGRESS) { > - if (td->urb->transfer_flags & URB_SHORT_NOT_OK) > - status = -EREMOTEIO; > - else > - status = 0; > - } > - } else { > - td->urb->actual_length = td->urb->transfer_buffer_length; > - /* Ignore a short packet completion if the > - * untransferred length was zero. > - */ > - if (status == -EREMOTEIO) > - status = 0; > - } > - } else { > - /* Slow path - walk the list, starting from the dequeue > - * pointer, to get the actual length transferred. > - */ > - union xhci_trb *cur_trb; > - struct xhci_segment *cur_seg; > - > - td->urb->actual_length = 0; > - for (cur_trb = ep_ring->dequeue, cur_seg = ep_ring->deq_seg; > - cur_trb != event_trb; > - next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) { > - if ((cur_trb->generic.field[3] & > - TRB_TYPE_BITMASK) != TRB_TYPE(TRB_TR_NOOP) && > - (cur_trb->generic.field[3] & > - TRB_TYPE_BITMASK) != TRB_TYPE(TRB_LINK)) > - td->urb->actual_length += > - TRB_LEN(cur_trb->generic.field[2]); > - } > - /* If the ring didn't stop on a Link or No-op TRB, add > - * in the actual bytes transferred from the Normal TRB > - */ > - if (trb_comp_code != COMP_STOP_INVAL) > - td->urb->actual_length += > - TRB_LEN(cur_trb->generic.field[2]) - > - TRB_LEN(event->transfer_len); > - } > - } > - > - ret = finish_td(xhci, td, event_trb, event, ep, &status, false); > + else > + ret = process_bulk_intr_td(xhci, td, event_trb, event, ep, > + &status); > > cleanup: > inc_deq(xhci, xhci->event_ring, true); > -- > 1.7.0.4 > > > > -- > 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