]> git.itanic.dy.fi Git - linux-stable/commitdiff
xhci: Prevent infinite loop in transaction errors recovery for streams
authorMathias Nyman <mathias.nyman@linux.intel.com>
Wed, 30 Nov 2022 09:19:43 +0000 (11:19 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 31 Dec 2022 12:26:52 +0000 (13:26 +0100)
commit a1575120972ecd7baa6af6a69e4e7ea9213bde7c upstream.

Make sure to also limit the amount of soft reset retries for transaction
errors on streams in cases where the transaction error event doesn't point
to any specific TRB.

In these cases we don't know the TRB or stream ring, but we do know which
endpoint had the error.

To keep error counting simple and functional, move the current err_count
from ring structure to endpoint structure.

Cc: stable@vger.kernel.org
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20221130091944.2171610-6-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 ad81e9a508b14b1bfd231e79db06a20d06699b25..343709af4c16fadcb5503edb82ce0c3c71183e61 100644 (file)
@@ -2458,7 +2458,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
 
        switch (trb_comp_code) {
        case COMP_SUCCESS:
-               ep_ring->err_count = 0;
+               ep->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");
@@ -2484,7 +2484,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
                break;
        case COMP_USB_TRANSACTION_ERROR:
                if (xhci->quirks & XHCI_NO_SOFT_RETRY ||
-                   (ep_ring->err_count++ > MAX_SOFT_RETRY) ||
+                   (ep->err_count++ > MAX_SOFT_RETRY) ||
                    le32_to_cpu(slot_ctx->tt_info) & TT_SLOT)
                        break;
 
@@ -2565,8 +2565,14 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                case COMP_USB_TRANSACTION_ERROR:
                case COMP_INVALID_STREAM_TYPE_ERROR:
                case COMP_INVALID_STREAM_ID_ERROR:
-                       xhci_handle_halted_endpoint(xhci, ep, 0, NULL,
-                                                   EP_SOFT_RESET);
+                       xhci_dbg(xhci, "Stream transaction error ep %u no id\n",
+                                ep_index);
+                       if (ep->err_count++ > MAX_SOFT_RETRY)
+                               xhci_handle_halted_endpoint(xhci, ep, 0, NULL,
+                                                           EP_HARD_RESET);
+                       else
+                               xhci_handle_halted_endpoint(xhci, ep, 0, NULL,
+                                                           EP_SOFT_RESET);
                        goto cleanup;
                case COMP_RING_UNDERRUN:
                case COMP_RING_OVERRUN:
index a6daf37ff4bf7422f5960ade19c7b926fb38a618..38941554ec55c1aab20da933fef442dfd8cfe48b 100644 (file)
@@ -933,6 +933,7 @@ struct xhci_virt_ep {
         * have to restore the device state to the previous state
         */
        struct xhci_ring                *new_ring;
+       unsigned int                    err_count;
        unsigned int                    ep_state;
 #define SET_DEQ_PENDING                (1 << 0)
 #define EP_HALTED              (1 << 1)        /* For stall handling */
@@ -1627,7 +1628,6 @@ 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;