diff options
author | Mathias Nyman | 2021-01-29 15:00:35 +0200 |
---|---|---|
committer | Greg Kroah-Hartman | 2021-01-29 14:16:51 +0100 |
commit | a6ccd1fd4bd4fca37eaa3d76bef940d6332919bc (patch) | |
tree | ab35c8eece2d90d7393cd34c2a593dcf0c0f2b17 | |
parent | e1a298390e987ddeb767cad18d913cb2782fda15 (diff) |
xhci: store TD status in the td struct instead of passing it along
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>
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 56 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 1 |
2 files changed, 30 insertions, 27 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 47597af50b5d..26b2d1e9b55a 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -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 && diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 87af91447985..fe0bf77e8cd8 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -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; |