提交 19e3c2e3 编写于 作者: M Mathias Nyman 提交者: sanglipeng

xhci: store TD status in the td struct instead of passing it along

stable inclusion
from stable-v5.10.164
commit cad965cedbc41236bea5f2642ea76e02ec033ff8
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I7T7G4

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=cad965cedbc41236bea5f2642ea76e02ec033ff8

--------------------------------

[ Upstream commit a6ccd1fd ]

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: NMathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20210129130044.206855-19-mathias.nyman@linux.intel.comSigned-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Stable-dep-of: a1575120 ("xhci: Prevent infinite loop in transaction errors recovery for streams")
Signed-off-by: NSasha Levin <sashal@kernel.org>
Signed-off-by: Nsanglipeng <sanglipeng1@jd.com>
上级 a90131b0
...@@ -774,7 +774,7 @@ static void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci, ...@@ -774,7 +774,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, 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; struct urb *urb = NULL;
...@@ -793,7 +793,7 @@ static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td, ...@@ -793,7 +793,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", xhci_warn(xhci, "URB req %u and actual %u transfer length mismatch\n",
urb->transfer_buffer_length, urb->actual_length); urb->transfer_buffer_length, urb->actual_length);
urb->actual_length = 0; urb->actual_length = 0;
*status = 0; status = 0;
} }
list_del_init(&td->td_list); list_del_init(&td->td_list);
/* Was this TD slated to be cancelled but completed anyway? */ /* Was this TD slated to be cancelled but completed anyway? */
...@@ -805,15 +805,15 @@ static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td, ...@@ -805,15 +805,15 @@ static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td,
if (last_td_in_urb(td)) { if (last_td_in_urb(td)) {
if ((urb->actual_length != urb->transfer_buffer_length && if ((urb->actual_length != urb->transfer_buffer_length &&
(urb->transfer_flags & URB_SHORT_NOT_OK)) || (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", xhci_dbg(xhci, "Giveback URB %p, len = %d, expected = %d, status = %d\n",
urb, urb->actual_length, 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 */ /* set isoc urb status to 0 just as EHCI, UHCI, and OHCI */
if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
*status = 0; status = 0;
xhci_giveback_urb_in_irq(xhci, td, *status); xhci_giveback_urb_in_irq(xhci, td, status);
} }
return 0; return 0;
...@@ -2064,8 +2064,7 @@ int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code) ...@@ -2064,8 +2064,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, static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,
struct xhci_transfer_event *event, struct xhci_transfer_event *event, struct xhci_virt_ep *ep)
struct xhci_virt_ep *ep, int *status)
{ {
struct xhci_ep_ctx *ep_ctx; struct xhci_ep_ctx *ep_ctx;
struct xhci_ring *ep_ring; struct xhci_ring *ep_ring;
...@@ -2108,7 +2107,7 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, ...@@ -2108,7 +2107,7 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,
inc_deq(xhci, ep_ring); 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 */ /* sum trb lengths from ring dequeue up to stop_trb, _excluding_ stop_trb */
...@@ -2131,7 +2130,7 @@ static int sum_trb_lengths(struct xhci_hcd *xhci, struct xhci_ring *ring, ...@@ -2131,7 +2130,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, static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
union xhci_trb *ep_trb, struct xhci_transfer_event *event, 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; struct xhci_ep_ctx *ep_ctx;
u32 trb_comp_code; u32 trb_comp_code;
...@@ -2149,13 +2148,13 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, ...@@ -2149,13 +2148,13 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
if (trb_type != TRB_STATUS) { if (trb_type != TRB_STATUS) {
xhci_warn(xhci, "WARN: Success on ctrl %s TRB without IOC set?\n", xhci_warn(xhci, "WARN: Success on ctrl %s TRB without IOC set?\n",
(trb_type == TRB_DATA) ? "data" : "setup"); (trb_type == TRB_DATA) ? "data" : "setup");
*status = -ESHUTDOWN; td->status = -ESHUTDOWN;
break; break;
} }
*status = 0; td->status = 0;
break; break;
case COMP_SHORT_PACKET: case COMP_SHORT_PACKET:
*status = 0; td->status = 0;
break; break;
case COMP_STOPPED_SHORT_PACKET: case COMP_STOPPED_SHORT_PACKET:
if (trb_type == TRB_DATA || trb_type == TRB_NORMAL) if (trb_type == TRB_DATA || trb_type == TRB_NORMAL)
...@@ -2219,7 +2218,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, ...@@ -2219,7 +2218,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
td->urb->actual_length = requested; td->urb->actual_length = requested;
finish_td: finish_td:
return finish_td(xhci, td, event, ep, status); return finish_td(xhci, td, event, ep);
} }
/* /*
...@@ -2227,7 +2226,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, ...@@ -2227,7 +2226,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
*/ */
static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
union xhci_trb *ep_trb, struct xhci_transfer_event *event, 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; struct urb_priv *urb_priv;
int idx; int idx;
...@@ -2304,11 +2303,11 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, ...@@ -2304,11 +2303,11 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
td->urb->actual_length += frame->actual_length; 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, 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 urb_priv *urb_priv;
struct usb_iso_packet_descriptor *frame; struct usb_iso_packet_descriptor *frame;
...@@ -2337,7 +2336,7 @@ static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, ...@@ -2337,7 +2336,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, static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
union xhci_trb *ep_trb, struct xhci_transfer_event *event, 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_slot_ctx *slot_ctx;
struct xhci_ring *ep_ring; struct xhci_ring *ep_ring;
...@@ -2361,13 +2360,13 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, ...@@ -2361,13 +2360,13 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
td->urb->ep->desc.bEndpointAddress, td->urb->ep->desc.bEndpointAddress,
requested, remaining); requested, remaining);
} }
*status = 0; td->status = 0;
break; break;
case COMP_SHORT_PACKET: case COMP_SHORT_PACKET:
xhci_dbg(xhci, "ep %#x - asked for %d bytes, %d bytes untransferred\n", xhci_dbg(xhci, "ep %#x - asked for %d bytes, %d bytes untransferred\n",
td->urb->ep->desc.bEndpointAddress, td->urb->ep->desc.bEndpointAddress,
requested, remaining); requested, remaining);
*status = 0; td->status = 0;
break; break;
case COMP_STOPPED_SHORT_PACKET: case COMP_STOPPED_SHORT_PACKET:
td->urb->actual_length = remaining; td->urb->actual_length = remaining;
...@@ -2382,7 +2381,8 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, ...@@ -2382,7 +2381,8 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
(ep_ring->err_count++ > MAX_SOFT_RETRY) || (ep_ring->err_count++ > MAX_SOFT_RETRY) ||
le32_to_cpu(slot_ctx->tt_info) & TT_SLOT) le32_to_cpu(slot_ctx->tt_info) & TT_SLOT)
break; break;
*status = 0;
td->status = 0;
xhci_cleanup_halted_endpoint(xhci, ep, ep_ring->stream_id, td, xhci_cleanup_halted_endpoint(xhci, ep, ep_ring->stream_id, td,
EP_SOFT_RESET); EP_SOFT_RESET);
return 0; return 0;
...@@ -2403,7 +2403,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, ...@@ -2403,7 +2403,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
remaining); remaining);
td->urb->actual_length = 0; td->urb->actual_length = 0;
} }
return finish_td(xhci, td, event, ep, status); return finish_td(xhci, td, event, ep);
} }
/* /*
...@@ -2705,7 +2705,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, ...@@ -2705,7 +2705,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
return -ESHUTDOWN; return -ESHUTDOWN;
} }
skip_isoc_td(xhci, td, ep, &status); skip_isoc_td(xhci, td, ep, status);
goto cleanup; goto cleanup;
} }
if (trb_comp_code == COMP_SHORT_PACKET) if (trb_comp_code == COMP_SHORT_PACKET)
...@@ -2733,6 +2733,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, ...@@ -2733,6 +2733,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
* endpoint. Otherwise, the endpoint remains stalled * endpoint. Otherwise, the endpoint remains stalled
* indefinitely. * indefinitely.
*/ */
if (trb_is_noop(ep_trb)) { if (trb_is_noop(ep_trb)) {
if (trb_comp_code == COMP_STALL_ERROR || if (trb_comp_code == COMP_STALL_ERROR ||
xhci_requires_manual_halt_cleanup(xhci, ep_ctx, xhci_requires_manual_halt_cleanup(xhci, ep_ctx,
...@@ -2743,14 +2744,15 @@ static int handle_tx_event(struct xhci_hcd *xhci, ...@@ -2743,14 +2744,15 @@ static int handle_tx_event(struct xhci_hcd *xhci,
goto cleanup; goto cleanup;
} }
td->status = status;
/* update the urb's actual_length and give back to the core */ /* update the urb's actual_length and give back to the core */
if (usb_endpoint_xfer_control(&td->urb->ep->desc)) 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)) 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 else
process_bulk_intr_td(xhci, td, ep_trb, event, ep, process_bulk_intr_td(xhci, td, ep_trb, event, ep);
&status);
cleanup: cleanup:
handling_skipped_tds = ep->skip && handling_skipped_tds = ep->skip &&
trb_comp_code != COMP_MISSED_SERVICE_ERROR && trb_comp_code != COMP_MISSED_SERVICE_ERROR &&
......
...@@ -1544,6 +1544,7 @@ struct xhci_segment { ...@@ -1544,6 +1544,7 @@ struct xhci_segment {
struct xhci_td { struct xhci_td {
struct list_head td_list; struct list_head td_list;
struct list_head cancelled_td_list; struct list_head cancelled_td_list;
int status;
struct urb *urb; struct urb *urb;
struct xhci_segment *start_seg; struct xhci_segment *start_seg;
union xhci_trb *first_trb; union xhci_trb *first_trb;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册