xhci: store TD status in the td struct instead of passing it along
authorMathias Nyman <mathias.nyman@linux.intel.com>
Fri, 29 Jan 2021 13:00:35 +0000 (15:00 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 29 Jan 2021 13:16:51 +0000 (14:16 +0100)
In cases where the TD can't be given back in current handler we want
to be able to store it until its time to return the TD.

Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20210129130044.206855-19-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.h

index 47597af..26b2d1e 100644 (file)
@@ -750,7 +750,7 @@ static void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci,
 }
 
 static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td,
-               struct xhci_ring *ep_ring, int *status)
+                          struct xhci_ring *ep_ring, int status)
 {
        struct urb *urb = NULL;
 
@@ -769,7 +769,7 @@ static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td,
                xhci_warn(xhci, "URB req %u and actual %u transfer length mismatch\n",
                          urb->transfer_buffer_length, urb->actual_length);
                urb->actual_length = 0;
-               *status = 0;
+               status = 0;
        }
        /* TD might be removed from td_list if we are giving back a cancelled URB */
        if (!list_empty(&td->td_list))
@@ -783,15 +783,15 @@ static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td,
        if (last_td_in_urb(td)) {
                if ((urb->actual_length != urb->transfer_buffer_length &&
                     (urb->transfer_flags & URB_SHORT_NOT_OK)) ||
-                   (*status != 0 && !usb_endpoint_xfer_isoc(&urb->ep->desc)))
+                   (status != 0 && !usb_endpoint_xfer_isoc(&urb->ep->desc)))
                        xhci_dbg(xhci, "Giveback URB %p, len = %d, expected = %d, status = %d\n",
                                 urb, urb->actual_length,
-                                urb->transfer_buffer_length, *status);
+                                urb->transfer_buffer_length, status);
 
                /* set isoc urb status to 0 just as EHCI, UHCI, and OHCI */
                if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
-                       *status = 0;
-               xhci_giveback_urb_in_irq(xhci, td, *status);
+                       status = 0;
+               xhci_giveback_urb_in_irq(xhci, td, status);
        }
 
        return 0;
@@ -2036,8 +2036,7 @@ int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code)
 }
 
 static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,
-       struct xhci_transfer_event *event,
-       struct xhci_virt_ep *ep, int *status)
+       struct xhci_transfer_event *event, struct xhci_virt_ep *ep)
 {
        struct xhci_ep_ctx *ep_ctx;
        struct xhci_ring *ep_ring;
@@ -2081,7 +2080,7 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,
                inc_deq(xhci, ep_ring);
        }
 
-       return xhci_td_cleanup(xhci, td, ep_ring, status);
+       return xhci_td_cleanup(xhci, td, ep_ring, td->status);
 }
 
 /* sum trb lengths from ring dequeue up to stop_trb, _excluding_ stop_trb */
@@ -2104,7 +2103,7 @@ static int sum_trb_lengths(struct xhci_hcd *xhci, struct xhci_ring *ring,
  */
 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_ep *ep)
 {
        struct xhci_ep_ctx *ep_ctx;
        u32 trb_comp_code;
@@ -2122,13 +2121,13 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
                if (trb_type != TRB_STATUS) {
                        xhci_warn(xhci, "WARN: Success on ctrl %s TRB without IOC set?\n",
                                  (trb_type == TRB_DATA) ? "data" : "setup");
-                       *status = -ESHUTDOWN;
+                       td->status = -ESHUTDOWN;
                        break;
                }
-               *status = 0;
+               td->status = 0;
                break;
        case COMP_SHORT_PACKET:
-               *status = 0;
+               td->status = 0;
                break;
        case COMP_STOPPED_SHORT_PACKET:
                if (trb_type == TRB_DATA || trb_type == TRB_NORMAL)
@@ -2192,7 +2191,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
                td->urb->actual_length = requested;
 
 finish_td:
-       return finish_td(xhci, td, event, ep, status);
+       return finish_td(xhci, td, event, ep);
 }
 
 /*
@@ -2200,7 +2199,7 @@ finish_td:
  */
 static int process_isoc_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_ep *ep)
 {
        struct urb_priv *urb_priv;
        int idx;
@@ -2277,11 +2276,11 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
 
        td->urb->actual_length += frame->actual_length;
 
-       return finish_td(xhci, td, event, ep, status);
+       return finish_td(xhci, td, event, ep);
 }
 
 static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
-                       struct xhci_virt_ep *ep, int *status)
+                       struct xhci_virt_ep *ep, int status)
 {
        struct urb_priv *urb_priv;
        struct usb_iso_packet_descriptor *frame;
@@ -2311,7 +2310,7 @@ static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
  */
 static int process_bulk_intr_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_ep *ep)
 {
        struct xhci_slot_ctx *slot_ctx;
        struct xhci_ring *ep_ring;
@@ -2335,13 +2334,13 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
                                 td->urb->ep->desc.bEndpointAddress,
                                 requested, remaining);
                }
-               *status = 0;
+               td->status = 0;
                break;
        case COMP_SHORT_PACKET:
                xhci_dbg(xhci, "ep %#x - asked for %d bytes, %d bytes untransferred\n",
                         td->urb->ep->desc.bEndpointAddress,
                         requested, remaining);
-               *status = 0;
+               td->status = 0;
                break;
        case COMP_STOPPED_SHORT_PACKET:
                td->urb->actual_length = remaining;
@@ -2355,7 +2354,8 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
                if ((ep_ring->err_count++ > MAX_SOFT_RETRY) ||
                    le32_to_cpu(slot_ctx->tt_info) & TT_SLOT)
                        break;
-               *status = 0;
+
+               td->status = 0;
                xhci_cleanup_halted_endpoint(xhci, ep, ep_ring->stream_id, td,
                                             EP_SOFT_RESET);
                return 0;
@@ -2376,7 +2376,7 @@ finish_td:
                          remaining);
                td->urb->actual_length = 0;
        }
-       return finish_td(xhci, td, event, ep, status);
+       return finish_td(xhci, td, event, ep);
 }
 
 /*
@@ -2677,7 +2677,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                                return -ESHUTDOWN;
                        }
 
-                       skip_isoc_td(xhci, td, ep, &status);
+                       skip_isoc_td(xhci, td, ep, status);
                        goto cleanup;
                }
                if (trb_comp_code == COMP_SHORT_PACKET)
@@ -2705,6 +2705,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                 * endpoint. Otherwise, the endpoint remains stalled
                 * indefinitely.
                 */
+
                if (trb_is_noop(ep_trb)) {
                        if (trb_comp_code == COMP_STALL_ERROR ||
                            xhci_requires_manual_halt_cleanup(xhci, ep_ctx,
@@ -2715,14 +2716,15 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                        goto cleanup;
                }
 
+               td->status = status;
+
                /* update the urb's actual_length and give back to the core */
                if (usb_endpoint_xfer_control(&td->urb->ep->desc))
-                       process_ctrl_td(xhci, td, ep_trb, event, ep, &status);
+                       process_ctrl_td(xhci, td, ep_trb, event, ep);
                else if (usb_endpoint_xfer_isoc(&td->urb->ep->desc))
-                       process_isoc_td(xhci, td, ep_trb, event, ep, &status);
+                       process_isoc_td(xhci, td, ep_trb, event, ep);
                else
-                       process_bulk_intr_td(xhci, td, ep_trb, event, ep,
-                                            &status);
+                       process_bulk_intr_td(xhci, td, ep_trb, event, ep);
 cleanup:
                handling_skipped_tds = ep->skip &&
                        trb_comp_code != COMP_MISSED_SERVICE_ERROR &&
index 87af914..fe0bf77 100644 (file)
@@ -1542,6 +1542,7 @@ struct xhci_segment {
 struct xhci_td {
        struct list_head        td_list;
        struct list_head        cancelled_td_list;
+       int                     status;
        struct urb              *urb;
        struct xhci_segment     *start_seg;
        union xhci_trb          *first_trb;