From nobody Tue Dec 2 02:31:03 2025 Received: from mail-ed1-f45.google.com (mail-ed1-f45.google.com [209.85.208.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7F6E62FE07E for ; Wed, 19 Nov 2025 11:06:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763550369; cv=none; b=UZCzqedf8BkcZTuBscK9m9QSIAtRab75HBQprzlva3DfTKzj0MN6BbCD4McSloN36bJVFXxJxuIjwtj3YOdANrbH9wTD8ttDbxGzoMUnWtKzNNTAEVcJIS4FCOkc/O0qW2Uv+9KfKv4kDajAeEmkKC4Kwy0XVpzvKVlPGtF3naM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763550369; c=relaxed/simple; bh=+2d51D44sRDt8eBybkvWwVZvcXIsPb6EJ/QSrTukauM=; h=Date:From:To:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=C5Aa4jTn5dFxVtrzh/7YPe9V/ACKPAhlztBk9z70EdJqi7KrQIlJSZc4/NM3Wh32GVjn43lMvrKJEzb1Lzv7Qml/jkYgv2AjQNdhk1Ay7xzMdSr/gh7EjDz57g2Vjm4EQ9SLFZ5e9TE69K9zVD2F9wxbchq6uc1rtTnXCfpgAnQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=JwTfBbWa; arc=none smtp.client-ip=209.85.208.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="JwTfBbWa" Received: by mail-ed1-f45.google.com with SMTP id 4fb4d7f45d1cf-64312565c10so9825770a12.2 for ; Wed, 19 Nov 2025 03:06:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1763550364; x=1764155164; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:subject:cc:to:from:date:from:to:cc:subject:date :message-id:reply-to; bh=JjhqYSqklyXctCvXY19E4xXbS28k7b49erlVOkL0uaU=; b=JwTfBbWaJw1pvaovYWi9cZnu+Kb7Ed6nng7fOE1u66mDATB0H9+GwCQgeyC+TguWNd 6gRzqcPrPt5VJDspuuV3gZiirXAMRiKsK6aNZNEY52A0gDGyP7z4l/1pA3xzbD3AAQ/B z8jn0lVdXQbsgXnmAQPpztd1aGhM4XGChS8aa88ta0XITn09kdLGi//2S99FAvWUOxbK 8H5LhwpasiYit6IALb/qGrRwmgSV+mwryCXgZEIJEjoP9XnBjzBa1Z8uBiduwaJ9dKCw LRATbvO2LsihU2E4VgUXHi447MCfYdvf7OdtGiMm6CiQr2HHiDgxdUG/c7U4qBeaeK1C m/Xw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1763550364; x=1764155164; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:subject:cc:to:from:date:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=JjhqYSqklyXctCvXY19E4xXbS28k7b49erlVOkL0uaU=; b=hZo+481ELfg9/yxumy/YsbE4guEcZi7Fn2NrMd4LOGEdttZx9aWnJkQVIr78M7jbSO QfxySIkEfMAntih6HHHdlXOR9Q+oFffp4pvMKBOaQbE2blYN2GnbtsgYMh5EDWkABtSG U43nLdyS0GxaIkZKun435BTIHSCSMUGGJMtCiGiz6im2p89F+uWY6hKo+8BDTPzh/tVP TtWEtq0QkKw1Iuk0CMNHZrSqAUfUvVTFzfdQOlM5YjlY5bmCI/EclD1walIRohJ2vIUF 8Y45WDj5dUa/TVlQfVHjqEvFaXCeHNu2OBVxm/xjFgq9IVL9+Q7mf/xEbLhvhpGPl+im mWBA== X-Forwarded-Encrypted: i=1; AJvYcCUdl0wrlGKzT8uRzwPdDX4LIJxp8mxG/nLcrA3ZCUbuswYeB4oXgvQvB9bQSOZGbk8SlCbPP3q6mpCAv4E=@vger.kernel.org X-Gm-Message-State: AOJu0YxJUYoj8UJzn7HFQNjTlmfIhdGYWTmjpei347OJ8hiOkNZgFqyV KWGhI2Kg+Lxt/g+hl1LukfZtgy6axoDgcuW0F6uR8F1yLHc61vcz8CrJ X-Gm-Gg: ASbGncuT/eWYEBYIoLot49scAX/+JyiPFNJK6MmqdQ3P+uG3vU5HxO6hShIVmQMo9+x xqWE/TGqQz9Qqt2M1PoVHMDFgTBKnJ0gKmU9jCr/MnZgpuUuC/kM+ROErEFBisX7e2gzoOe3Jgh MVc030wqsqpP1r2taaPGZrKaA0Vjizve0un0C8JimZ4lUREaX5lQCIcgGrDFihMC1XoZh8FtX7c MreC/KMd2/eoRLFZKO0y3GmXgn8b0FOvYnOuOgqh5qzXg72Fli0I5jJnstvOT8Q6Bj8YP5PUn+t O8qcpqMfs+uS/gYSqUp4QY6rEZg6MnmF2AGMkSuilW8TUsoKpka1DKknYuqvDuiabj2yR+nQFd+ eom6G29BfO6sbqYQx0N1tnjtrUqGQg5ZNxzFvcR2R8zNcMU8bIimGhEzkIp0mJs+MKGGDm806BQ V4lkeYUC5TsgeHB0XwZ+kyC9o= X-Google-Smtp-Source: AGHT+IHTBHx15yNRGnMidAAcOO2NJhpnoMhv5pnLm2GpLTZ+cNsXO29k/8OCuAvMMM9Y/toDz1Chwg== X-Received: by 2002:a17:907:fdcb:b0:b73:8757:68ad with SMTP id a640c23a62f3a-b7387577ab2mr1700356166b.47.1763550364225; Wed, 19 Nov 2025 03:06:04 -0800 (PST) Received: from foxbook (bhd138.neoplus.adsl.tpnet.pl. [83.28.93.138]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-b73783ef841sm1215393966b.46.2025.11.19.03.06.03 (version=TLS1_2 cipher=AES128-SHA bits=128/128); Wed, 19 Nov 2025 03:06:03 -0800 (PST) Date: Wed, 19 Nov 2025 12:06:01 +0100 From: Michal Pecio To: Mathias Nyman , Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 5/5] usb: xhci: Handle short transfers as "done TDs" Message-ID: <20251119120601.77c46152.michal.pecio@gmail.com> In-Reply-To: <20251119120208.6a025eb0.michal.pecio@gmail.com> References: <20251119120208.6a025eb0.michal.pecio@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Short transfers (on any endpoint type) are similar to isochronous errors mid TD - the TD can be given back, but we need to keep track of xHC's progress through its TRBs and handle some more events. And here too there are buggy HCs which don't generate expected events. Reuse the "done TD" mechanism to also handle short transfers on all endpoints other than control, which have some special requirements. Done TD is more accurate than the previous code, because it matches events with TDs by TRB pointers, not by completion codes alone. Remove the SPURIOUS_SUCCESS quirk, as we can now detect missing end TRB events automatically and reliably. Ensure that no xhci_dbg() shows on every short transfer, which can be 8000 times per second. The patch was tested on isochronous and bulk endpoints at FS/HS/SS with several host controllers from various vendors. Behavior after Short Packet mid TD varies: 1. NEC uPD720200 and Etron EJ168 ignore IOC on the last TRB. 2. Renesas uPD720202 and AMD Carrizo APU generate Success with residual equal to last TRB size. 3. Fresco Logic FL1100 generates Short Packet, residual as above. 4. Various ASMedia HCs and AMD Promontory generate Short Packet again with repeated residual, even if the last TRB is shorter. 5. VIA VL805 generates Success with zero residual. No case of a Success with non-zero residual was observed, but commit 1530bbc6272d ("xhci: Add new short TX quirk for Fresco Logic host.") says that some Fresco Logic hardware (FL1000?) does that. Signed-off-by: Michal Pecio --- drivers/usb/host/xhci-mtk.c | 5 ---- drivers/usb/host/xhci-pci.c | 5 ---- drivers/usb/host/xhci-ring.c | 51 +++++++++--------------------------- drivers/usb/host/xhci.c | 7 ----- drivers/usb/host/xhci.h | 3 +-- 5 files changed, 13 insertions(+), 58 deletions(-) diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index 208558cf822d..d85f84e39291 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -454,11 +454,6 @@ static void xhci_mtk_quirks(struct device *dev, struct= xhci_hcd *xhci) struct xhci_hcd_mtk *mtk =3D hcd_to_mtk(hcd); =20 xhci->quirks |=3D XHCI_MTK_HOST; - /* - * MTK host controller gives a spurious successful event after a - * short transfer. Ignore it. - */ - xhci->quirks |=3D XHCI_SPURIOUS_SUCCESS; if (mtk->lpm_support) xhci->quirks |=3D XHCI_LPM_SUPPORT; if (mtk->u2_lpm_disable) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index d292adc65e5a..bcfe45d23f17 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -454,11 +454,6 @@ static void xhci_pci_quirks(struct device *dev, struct= xhci_hcd *xhci) =20 if (pdev->vendor =3D=3D PCI_VENDOR_ID_ASMEDIA && pdev->device =3D=3D PCI_DEVICE_ID_ASMEDIA_1042_XHCI) { - /* - * try to tame the ASMedia 1042 controller which reports 0.96 - * but appears to behave more like 1.0 - */ - xhci->quirks |=3D XHCI_SPURIOUS_SUCCESS; xhci->quirks |=3D XHCI_BROKEN_STREAMS; } if (pdev->vendor =3D=3D PCI_VENDOR_ID_ASMEDIA && diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 2b889caff0f5..a21d403305f1 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2450,16 +2450,16 @@ static void process_isoc_td(struct xhci_hcd *xhci, = struct xhci_virt_ep *ep, /* handle completion code */ switch (trb_comp_code) { case COMP_SUCCESS: - if (remaining) { - frame->status =3D short_framestatus; - sum_trbs_for_length =3D true; + /* check transfer completeness, some HCs may lie */ + if (ep_trb =3D=3D td->end_trb && !remaining) { + frame->status =3D 0; break; } - frame->status =3D 0; - break; + fallthrough; case COMP_SHORT_PACKET: frame->status =3D short_framestatus; sum_trbs_for_length =3D true; + more_events =3D ep_trb !=3D td->end_trb; /* xHCI 4.10.1.1.2 */ break; case COMP_BANDWIDTH_OVERRUN_ERROR: frame->status =3D -ECOMM; @@ -2547,6 +2547,8 @@ static void process_bulk_intr_td(struct xhci_hcd *xhc= i, struct xhci_virt_ep *ep, struct xhci_slot_ctx *slot_ctx; u32 trb_comp_code; u32 remaining, requested, ep_trb_len; + /* Expect more events for this TD after short transfers before the last T= RB */ + bool more_events =3D false; =20 slot_ctx =3D xhci_get_slot_ctx(xhci, ep->vdev->out_ctx); trb_comp_code =3D GET_COMP_CODE(le32_to_cpu(event->transfer_len)); @@ -2568,6 +2570,7 @@ static void process_bulk_intr_td(struct xhci_hcd *xhc= i, struct xhci_virt_ep *ep, break; case COMP_SHORT_PACKET: td->status =3D 0; + more_events =3D ep_trb !=3D td->end_trb; /* xHCI 4.10.1.1.2 */ break; case COMP_STOPPED_SHORT_PACKET: td->urb->actual_length =3D remaining; @@ -2604,11 +2607,11 @@ static void process_bulk_intr_td(struct xhci_hcd *x= hci, struct xhci_virt_ep *ep, td->urb->actual_length =3D 0; } =20 - finish_td(xhci, ep, ep_ring, td, trb_comp_code, ep_seg, ep_trb, false); + finish_td(xhci, ep, ep_ring, td, trb_comp_code, ep_seg, ep_trb, more_even= ts); } =20 /* - * Process events for an already finished TD. See xHCI 4.9.1. + * Process events for an already finished TD. See xHCI 4.9.1 and 4.10.1.1.= 2. */ static void process_done_td(struct xhci_hcd *xhci, struct xhci_ring *ep_ri= ng, struct xhci_segment *ep_seg, union xhci_trb *ep_trb, @@ -2661,17 +2664,6 @@ static int handle_transferless_tx_event(struct xhci_= hcd *xhci, struct xhci_virt_ return 0; } =20 -static bool xhci_spurious_success_tx_event(struct xhci_hcd *xhci, - struct xhci_ring *ring) -{ - switch (ring->old_trb_comp_code) { - case COMP_SHORT_PACKET: - return xhci->quirks & XHCI_SPURIOUS_SUCCESS; - default: - return false; - } -} - /* * If this function returns an error condition, it means it got a Transfer * event with a corrupted Slot ID, Endpoint ID, or TRB DMA address. @@ -2733,11 +2725,6 @@ static int handle_tx_event(struct xhci_hcd *xhci, * transfer type */ case COMP_SUCCESS: - if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) !=3D 0) { - trb_comp_code =3D COMP_SHORT_PACKET; - xhci_dbg(xhci, "Successful completion on short TX for slot %u ep %u wit= h last td comp code %d\n", - slot_id, ep_index, ep_ring->old_trb_comp_code); - } break; case COMP_SHORT_PACKET: break; @@ -2857,7 +2844,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, =20 /* * Check if we are expecting more events for a "done" TD, which has been = given back before - * the xHC finished traversing all its TRBs, because it completed with an= error. + * the xHC finished traversing all its TRBs, because it completed short o= r with an error. */ if (ep_ring->done_end_trb) { if (trb_in_range(xhci, ep_ring->dequeue, ep_ring->done_end_trb, ep_seg, = ep_trb)) { @@ -2880,8 +2867,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, */ if (trb_comp_code !=3D COMP_STOPPED && trb_comp_code !=3D COMP_STOPPED_LENGTH_INVALID && - !ring_xrun_event && - !xhci_spurious_success_tx_event(xhci, ep_ring)) { + !ring_xrun_event) { xhci_warn(xhci, "Event TRB for slot %u ep %u with no TDs queued\n", slot_id, ep_index); } @@ -2942,17 +2928,6 @@ static int handle_tx_event(struct xhci_hcd *xhci, return 0; } =20 - /* - * Some hosts give a spurious success event after a short - * transfer or error on last TRB. Ignore it. - */ - if (xhci_spurious_success_tx_event(xhci, ep_ring)) { - xhci_dbg(xhci, "Spurious event dma %pad, comp_code %u after %u\n", - &ep_trb_dma, trb_comp_code, ep_ring->old_trb_comp_code); - ep_ring->old_trb_comp_code =3D 0; - return 0; - } - /* HC is busted, give up! */ goto debug_finding_td; } @@ -2972,8 +2947,6 @@ static int handle_tx_event(struct xhci_hcd *xhci, */ } while (ep->skip); =20 - ep_ring->old_trb_comp_code =3D trb_comp_code; - /* Get out if a TD was queued at enqueue after the xrun occurred */ if (ring_xrun_event) return 0; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 6da583c7778b..4e32cbe1c6b8 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -5473,13 +5473,6 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_qui= rks_t get_quirks) if (get_quirks) get_quirks(dev, xhci); =20 - /* In xhci controllers which follow xhci 1.0 spec gives a spurious - * success event after a short transfer. This quirk will ignore such - * spurious event. - */ - if (xhci->hci_version > 0x96) - xhci->quirks |=3D XHCI_SPURIOUS_SUCCESS; - if (xhci->hci_version =3D=3D 0x95 && link_quirk) { xhci_dbg(xhci, "QUIRK: Not clearing Link TRB chain bits"); xhci->quirks |=3D XHCI_LINK_TRB_QUIRK; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index a1dd9ce5f8aa..e72eda6cee62 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1380,7 +1380,6 @@ struct xhci_ring { unsigned int bounce_buf_len; enum xhci_ring_type type; union xhci_trb *done_end_trb; - u32 old_trb_comp_code; struct radix_tree_root *trb_address_map; }; =20 @@ -1587,7 +1586,7 @@ struct xhci_hcd { #define XHCI_RESET_EP_QUIRK BIT_ULL(1) /* Deprecated */ #define XHCI_NEC_HOST BIT_ULL(2) #define XHCI_AMD_PLL_FIX BIT_ULL(3) -#define XHCI_SPURIOUS_SUCCESS BIT_ULL(4) +#define XHCI_SPURIOUS_SUCCESS BIT_ULL(4) /* Deprecated */ /* * Certain Intel host controllers have a limit to the number of endpoint * contexts they can handle. Ideally, they would signal that they can't h= andle --=20 2.48.1