USB: xHCI: handle_tx_event() refactor: finish_td
authorAndiry Xu <andiry.xu@amd.com>
Thu, 22 Jul 2010 22:22:55 +0000 (15:22 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 10 Aug 2010 21:35:41 +0000 (14:35 -0700)
This patch moves the td universal processing part in handle_tx_event()
into a separate function finish_td().

if finish_td() returns 1, it indicates the urb can be given back.

Signed-off-by: Andiry Xu <andiry.xu@amd.com>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

drivers/usb/host/xhci-ring.c

index bfc99a9..691a108 100644 (file)
@@ -1258,6 +1258,104 @@ int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code)
 }
 
 /*
+ * Finish the td processing, remove the td from td list;
+ * Return 1 if the urb can be given back.
+ */
+static int finish_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, bool skip)
+{
+       struct xhci_virt_device *xdev;
+       struct xhci_ring *ep_ring;
+       unsigned int slot_id;
+       int ep_index;
+       struct urb *urb = NULL;
+       struct xhci_ep_ctx *ep_ctx;
+       int ret = 0;
+       u32 trb_comp_code;
+
+       slot_id = TRB_TO_SLOT_ID(event->flags);
+       xdev = xhci->devs[slot_id];
+       ep_index = TRB_TO_EP_ID(event->flags) - 1;
+       ep_ring = xhci_dma_to_transfer_ring(ep, event->buffer);
+       ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
+       trb_comp_code = GET_COMP_CODE(event->transfer_len);
+
+       if (skip)
+               goto td_cleanup;
+
+       if (trb_comp_code == COMP_STOP_INVAL ||
+                       trb_comp_code == COMP_STOP) {
+               /* The Endpoint Stop Command completion will take care of any
+                * stopped TDs.  A stopped TD may be restarted, so don't update
+                * the ring dequeue pointer or take this TD off any lists yet.
+                */
+               ep->stopped_td = td;
+               ep->stopped_trb = event_trb;
+               return 0;
+       } else {
+               if (trb_comp_code == COMP_STALL) {
+                       /* The transfer is completed from the driver's
+                        * perspective, but we need to issue a set dequeue
+                        * command for this stalled endpoint to move the dequeue
+                        * pointer past the TD.  We can't do that here because
+                        * the halt condition must be cleared first.  Let the
+                        * USB class driver clear the stall later.
+                        */
+                       ep->stopped_td = td;
+                       ep->stopped_trb = event_trb;
+                       ep->stopped_stream = ep_ring->stream_id;
+               } else if (xhci_requires_manual_halt_cleanup(xhci,
+                                       ep_ctx, trb_comp_code)) {
+                       /* Other types of errors halt the endpoint, but the
+                        * class driver doesn't call usb_reset_endpoint() unless
+                        * the error is -EPIPE.  Clear the halted status in the
+                        * xHCI hardware manually.
+                        */
+                       xhci_cleanup_halted_endpoint(xhci,
+                                       slot_id, ep_index, ep_ring->stream_id,
+                                       td, event_trb);
+               } else {
+                       /* Update ring dequeue pointer */
+                       while (ep_ring->dequeue != td->last_trb)
+                               inc_deq(xhci, ep_ring, false);
+                       inc_deq(xhci, ep_ring, false);
+               }
+
+td_cleanup:
+               /* Clean up the endpoint's TD list */
+               urb = td->urb;
+
+               /* Do one last check of the actual transfer length.
+                * If the host controller said we transferred more data than
+                * the buffer length, urb->actual_length will be a very big
+                * number (since it's unsigned).  Play it safe and say we didn't
+                * transfer anything.
+                */
+               if (urb->actual_length > urb->transfer_buffer_length) {
+                       xhci_warn(xhci, "URB transfer length is wrong, "
+                                       "xHC issue? req. len = %u, "
+                                       "act. len = %u\n",
+                                       urb->transfer_buffer_length,
+                                       urb->actual_length);
+                       urb->actual_length = 0;
+                       if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
+                               *status = -EREMOTEIO;
+                       else
+                               *status = 0;
+               }
+               list_del(&td->td_list);
+               /* Was this TD slated to be cancelled but completed anyway? */
+               if (!list_empty(&td->cancelled_td_list))
+                       list_del(&td->cancelled_td_list);
+
+               ret = 1;
+       }
+
+       return ret;
+}
+
+/*
  * 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.
@@ -1278,6 +1376,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
        int status = -EINPROGRESS;
        struct xhci_ep_ctx *ep_ctx;
        u32 trb_comp_code;
+       int ret = 0;
 
        xhci_dbg(xhci, "In %s\n", __func__);
        slot_id = TRB_TO_SLOT_ID(event->flags);
@@ -1308,7 +1407,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                xhci_dbg(xhci, "Event TRB with TRB type ID %u\n",
                                (unsigned int) (event->flags & TRB_TYPE_BITMASK)>>10);
                xhci_print_trb_offsets(xhci, (union xhci_trb *) event);
-               urb = NULL;
                goto cleanup;
        }
        xhci_dbg(xhci, "%s - getting list entry\n", __func__);
@@ -1379,7 +1477,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                        break;
                }
                xhci_warn(xhci, "ERROR Unknown event condition, HC probably busted\n");
-               urb = NULL;
                goto cleanup;
        }
        /* Now update the urb's actual_length and give back to the core */
@@ -1427,7 +1524,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,
 
                        xhci_cleanup_halted_endpoint(xhci,
                                        slot_id, ep_index, 0, td, event_trb);
-                       goto td_cleanup;
+
+                       ret = finish_td(xhci, td, event_trb, event, ep,
+                                        &status, true);
+                       goto cleanup;
                }
                /*
                 * Did we transfer any data, despite the errors that might have
@@ -1456,7 +1556,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                                                td->urb->transfer_buffer_length -
                                                TRB_LEN(event->transfer_len);
                                        xhci_dbg(xhci, "Waiting for status stage event\n");
-                                       urb = NULL;
                                        goto cleanup;
                                }
                        }
@@ -1558,68 +1657,16 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                                        TRB_LEN(event->transfer_len);
                }
        }
-       if (trb_comp_code == COMP_STOP_INVAL ||
-                       trb_comp_code == COMP_STOP) {
-               /* The Endpoint Stop Command completion will take care of any
-                * stopped TDs.  A stopped TD may be restarted, so don't update
-                * the ring dequeue pointer or take this TD off any lists yet.
-                */
-               ep->stopped_td = td;
-               ep->stopped_trb = event_trb;
-       } else {
-               if (trb_comp_code == COMP_STALL) {
-                       /* The transfer is completed from the driver's
-                        * perspective, but we need to issue a set dequeue
-                        * command for this stalled endpoint to move the dequeue
-                        * pointer past the TD.  We can't do that here because
-                        * the halt condition must be cleared first.  Let the
-                        * USB class driver clear the stall later.
-                        */
-                       ep->stopped_td = td;
-                       ep->stopped_trb = event_trb;
-                       ep->stopped_stream = ep_ring->stream_id;
-               } else if (xhci_requires_manual_halt_cleanup(xhci,
-                                       ep_ctx, trb_comp_code)) {
-                       /* Other types of errors halt the endpoint, but the
-                        * class driver doesn't call usb_reset_endpoint() unless
-                        * the error is -EPIPE.  Clear the halted status in the
-                        * xHCI hardware manually.
-                        */
-                       xhci_cleanup_halted_endpoint(xhci,
-                                       slot_id, ep_index, ep_ring->stream_id, td, event_trb);
-               } else {
-                       /* Update ring dequeue pointer */
-                       while (ep_ring->dequeue != td->last_trb)
-                               inc_deq(xhci, ep_ring, false);
-                       inc_deq(xhci, ep_ring, false);
-               }
 
-td_cleanup:
-               /* Clean up the endpoint's TD list */
-               urb = td->urb;
-               /* Do one last check of the actual transfer length.
-                * If the host controller said we transferred more data than
-                * the buffer length, urb->actual_length will be a very big
-                * number (since it's unsigned).  Play it safe and say we didn't
-                * transfer anything.
-                */
-               if (urb->actual_length > urb->transfer_buffer_length) {
-                       xhci_warn(xhci, "URB transfer length is wrong, "
-                                       "xHC issue? req. len = %u, "
-                                       "act. len = %u\n",
-                                       urb->transfer_buffer_length,
-                                       urb->actual_length);
-                       urb->actual_length = 0;
-                       if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
-                               status = -EREMOTEIO;
-                       else
-                               status = 0;
-               }
-               list_del(&td->td_list);
-               /* Was this TD slated to be cancelled but completed anyway? */
-               if (!list_empty(&td->cancelled_td_list))
-                       list_del(&td->cancelled_td_list);
+       ret =  finish_td(xhci, td, event_trb, event, ep, &status, false);
 
+cleanup:
+       inc_deq(xhci, xhci->event_ring, true);
+       xhci_set_hc_event_deq(xhci);
+
+       /* FIXME for multi-TD URBs (who have buffers bigger than 64MB) */
+       if (ret) {
+               urb = td->urb;
                /* Leave the TD around for the reset endpoint function to use
                 * (but only if it's not a control endpoint, since we already
                 * queued the Set TR dequeue pointer command for stalled
@@ -1627,17 +1674,9 @@ td_cleanup:
                 */
                if (usb_endpoint_xfer_control(&urb->ep->desc) ||
                        (trb_comp_code != COMP_STALL &&
-                               trb_comp_code != COMP_BABBLE)) {
+                               trb_comp_code != COMP_BABBLE))
                        kfree(td);
-               }
-               urb->hcpriv = NULL;
-       }
-cleanup:
-       inc_deq(xhci, xhci->event_ring, true);
-       xhci_set_hc_event_deq(xhci);
 
-       /* FIXME for multi-TD URBs (who have buffers bigger than 64MB) */
-       if (urb) {
                usb_hcd_unlink_urb_from_ep(xhci_to_hcd(xhci), urb);
                xhci_dbg(xhci, "Giveback URB %p, len = %d, status = %d\n",
                                urb, urb->actual_length, status);