mirror of
https://github.com/torvalds/linux.git
synced 2024-12-02 09:01:34 +00:00
xhci: Use soft retry to recover faster from transaction errors
Use soft retry to recover from a USB Transaction Errors that are caused by temporary error conditions. The USB device is not aware that the xHC has halted the endpoint, and will be waiting for another retry A Soft Retry perform additional retries and recover from an error which has caused the xHC to halt an endpoint. Soft retry has some limitations: Soft Retry attempts shall not be performed on Isoch endpoints Soft Retry attempts shall not be performed if the device is behind a TT in a HS Hub Software shall limit the number of unsuccessful Soft Retry attempts to prevent an infinite loop. For more details on Soft retry see xhci specs 4.6.8.1 Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
c94d41e9dd
commit
f8f80be501
@ -1155,6 +1155,10 @@ static void xhci_handle_cmd_reset_ep(struct xhci_hcd *xhci, int slot_id,
|
||||
/* Clear our internal halted state */
|
||||
xhci->devs[slot_id]->eps[ep_index].ep_state &= ~EP_HALTED;
|
||||
}
|
||||
|
||||
/* if this was a soft reset, then restart */
|
||||
if ((le32_to_cpu(trb->generic.field[3])) & TRB_TSP)
|
||||
ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
|
||||
}
|
||||
|
||||
static void xhci_handle_cmd_enable_slot(struct xhci_hcd *xhci, int slot_id,
|
||||
@ -2132,10 +2136,16 @@ 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_slot_ctx *slot_ctx;
|
||||
struct xhci_ring *ep_ring;
|
||||
u32 trb_comp_code;
|
||||
u32 remaining, requested, ep_trb_len;
|
||||
unsigned int slot_id;
|
||||
int ep_index;
|
||||
|
||||
slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
|
||||
slot_ctx = xhci_get_slot_ctx(xhci, xhci->devs[slot_id]->out_ctx);
|
||||
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));
|
||||
trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
|
||||
remaining = EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
|
||||
@ -2144,6 +2154,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
||||
|
||||
switch (trb_comp_code) {
|
||||
case COMP_SUCCESS:
|
||||
ep_ring->err_count = 0;
|
||||
/* handle success with untransferred data as short packet */
|
||||
if (ep_trb != td->last_trb || remaining) {
|
||||
xhci_warn(xhci, "WARN Successful completion on short TX\n");
|
||||
@ -2167,6 +2178,14 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
||||
ep_trb_len = 0;
|
||||
remaining = 0;
|
||||
break;
|
||||
case COMP_USB_TRANSACTION_ERROR:
|
||||
if ((ep_ring->err_count++ > MAX_SOFT_RETRY) ||
|
||||
le32_to_cpu(slot_ctx->tt_info) & TT_SLOT)
|
||||
break;
|
||||
*status = 0;
|
||||
xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index,
|
||||
ep_ring->stream_id, td, EP_SOFT_RESET);
|
||||
return 0;
|
||||
default:
|
||||
/* do nothing */
|
||||
break;
|
||||
|
@ -1496,6 +1496,7 @@ static inline const char *xhci_trb_type_string(u8 type)
|
||||
/* How much data is left before the 64KB boundary? */
|
||||
#define TRB_BUFF_LEN_UP_TO_BOUNDARY(addr) (TRB_MAX_BUFF_SIZE - \
|
||||
(addr & (TRB_MAX_BUFF_SIZE - 1)))
|
||||
#define MAX_SOFT_RETRY 3
|
||||
|
||||
struct xhci_segment {
|
||||
union xhci_trb *trbs;
|
||||
@ -1583,6 +1584,7 @@ struct xhci_ring {
|
||||
* if we own the TRB (if we are the consumer). See section 4.9.1.
|
||||
*/
|
||||
u32 cycle_state;
|
||||
unsigned int err_count;
|
||||
unsigned int stream_id;
|
||||
unsigned int num_segs;
|
||||
unsigned int num_trbs_free;
|
||||
|
Loading…
Reference in New Issue
Block a user