process_ctrl_td() is too complex and difficult to read. We can clean it
up a lot and maintain same functionality as before. Note that while
cleaning up, one comment was introduced to explain the special case - it
wasn't clear before from code.

Much of the changes are related to removal of duplicated work done in
both process_ctrl_td() and finish_td(). By removing the duplicated code,
we could remove a few local variables and shuffle things around so the
implementation is more straight forward.

Signed-off-by: Felipe Balbi <felipe.ba...@linux.intel.com>
---
 drivers/usb/host/xhci-ring.c | 103 ++++++++++++++-----------------------------
 1 file changed, 32 insertions(+), 71 deletions(-)

diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 7acfecc6639a..607bd2d2ab11 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1930,99 +1930,60 @@ static int process_ctrl_td(struct xhci_hcd *xhci, 
struct xhci_td *td,
        union xhci_trb *ep_trb, struct xhci_transfer_event *event,
        struct xhci_virt_ep *ep, int *status)
 {
-       struct xhci_virt_device *xdev;
-       struct xhci_ring *ep_ring;
-       struct device *dev;
-       unsigned int slot_id;
-       int ep_index;
-       struct xhci_ep_ctx *ep_ctx;
        u32 trb_comp_code;
-       u32 remaining, requested;
+       u32 remaining;
+       u32 requested;
        u32 trb_type;
 
        trb_type = TRB_FIELD_TO_TYPE(le32_to_cpu(ep_trb->generic.field[3]));
-       slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
-       xdev = xhci->devs[slot_id];
-       ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1;
-       ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer));
-       ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
        trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
        requested = td->urb->transfer_buffer_length;
        remaining = EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
-       dev = xhci_to_hcd(xhci)->self.controller;
+
+       td->urb->actual_length = requested - remaining;
 
        switch (trb_comp_code) {
        case COMP_SUCCESS:
-               dev_WARN_ONCE(dev, trb_type != TRB_STATUS,
-                               "ep%d%s: unexpected success! TRB Type %d\n",
-                               usb_endpoint_num(&td->urb->ep->desc),
-                               usb_endpoint_dir_in(&td->urb->ep->desc) ?
-                               "in" : "out", trb_type);
-               *status = 0;
-               break;
        case COMP_SHORT_PACKET:
                *status = 0;
                break;
        case COMP_STOPPED_SHORT_PACKET:
-               if (trb_type == TRB_DATA ||
-                       trb_type == TRB_NORMAL)
-                       td->urb->actual_length = remaining;
-               else
+               if (trb_type == TRB_SETUP ||
+                               trb_type == TRB_STATUS)
                        xhci_warn(xhci, "WARN: Stopped Short Packet on ctrl 
setup or status TRB\n");
-               goto finish_td;
+               *status = -ESHUTDOWN;
+
+               /*
+                * NOTICE: according to section 6.4.2 Table 91 of xHCI rev 1.1
+                * Specification, if completion code is Stopped - Short Packet,
+                * Transfer Length field (referred to as 'remaining' here)
+                * contain the value of EDTLA (see section 4.11.5.2 for
+                * details), which means that remaining contains actual_length,
+                * not the amount of bytes remaining to be transferred as usual.
+                */
+               td->urb->actual_length = remaining;
+               break;
        case COMP_STOPPED:
-               switch (trb_type) {
-               case TRB_SETUP:
+               if (trb_type == TRB_SETUP)
                        td->urb->actual_length = 0;
-                       goto finish_td;
-               case TRB_DATA:
-               case TRB_NORMAL:
-                       td->urb->actual_length = requested - remaining;
-                       goto finish_td;
-               default:
-                       xhci_warn(xhci, "WARN: unexpected TRB Type %d\n", 
trb_type);
-                       goto finish_td;
-               }
+               *status = -ESHUTDOWN;
+               break;
        case COMP_STOPPED_LENGTH_INVALID:
-               goto finish_td;
-       default:
-               if (!xhci_requires_manual_halt_cleanup(xhci,
-                                                      ep_ctx, trb_comp_code))
-                       break;
-               xhci_dbg(xhci, "TRB error %u, halted endpoint index = %u\n",
-                        trb_comp_code, ep_index);
-               /* else fall through */
+               td->urb->actual_length = 0;
+               *status = -EINVAL;
+               break;
        case COMP_STALL_ERROR:
-               /* Did we transfer part of the data (middle) phase? */
-               if (trb_type == TRB_DATA ||
-                       trb_type == TRB_NORMAL)
-                       td->urb->actual_length = requested - remaining;
-               else if (!td->urb_length_set)
-                       td->urb->actual_length = 0;
-               goto finish_td;
-       }
+               *status = -EINVAL;
 
-       /* stopped at setup stage, no data transferred */
-       if (trb_type == TRB_SETUP)
-               goto finish_td;
-
-       /*
-        * if on data stage then update the actual_length of the URB and flag it
-        * as set, so it won't be overwritten in the event for the last TRB.
-        */
-       if (trb_type == TRB_DATA ||
-               trb_type == TRB_NORMAL) {
-               td->urb_length_set = true;
-               td->urb->actual_length = requested - remaining;
-               xhci_dbg(xhci, "Waiting for status stage event\n");
-               return 0;
+               if (trb_type != TRB_DATA &&
+                               trb_type != TRB_NORMAL)
+                       td->urb->actual_length = 0;
+               break;
+       default:
+               /* nothing, further processed by finish_td() */
+               break;
        }
 
-       /* at status stage */
-       if (!td->urb_length_set)
-               td->urb->actual_length = requested;
-
-finish_td:
        return finish_td(xhci, td, ep_trb, event, ep, status, false);
 }
 
-- 
2.10.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to