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>
This commit is contained in:
Mathias Nyman 2021-01-29 15:00:35 +02:00 committed by Greg Kroah-Hartman
parent e1a298390e
commit a6ccd1fd4b
2 changed files with 30 additions and 27 deletions

View 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 &&

View 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;