From nobody Tue Dec 2 02:32:13 2025 Received: from mail-ed1-f50.google.com (mail-ed1-f50.google.com [209.85.208.50]) (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 D37E8350A2C for ; Wed, 19 Nov 2025 11:04:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763550276; cv=none; b=Epn1Dftyvv0rJhqnhZWwl0JrHlaEtPiXZWXq4Up+PpmvjXHlGBrrinu543vEVVFUmf60wHlNpZxaNwl4o+bC+lFTX0TYLKwHJmM4OdHtF6vcnKOxrYWDx330toqETv8R5iZe8EAJIbWKEyT/ewpLWCN3eK88ZqzGeXoSVz4a+5w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763550276; c=relaxed/simple; bh=G7JunY/3iWsoDP1AL4Uu9VZnCup1j693fiMcSMDqWug=; h=Date:From:To:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=HZUpMSsnRMGjEbxISHyzP2RvPDYo/+kkyv8IYKqnD/MMYLinYusajMFeTzLOeQP7BXk4qq7M1CQkc0O6idP0aOLKa1L8s696VbMc5boo0PHK6kQiBnGZDH1MKrStXPAOl6574vjMhgoGk+qQBZ9oSv05qALZSyDTDyu7N1Jpwqw= 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=dDbesPcu; arc=none smtp.client-ip=209.85.208.50 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="dDbesPcu" Received: by mail-ed1-f50.google.com with SMTP id 4fb4d7f45d1cf-640860f97b5so10386999a12.2 for ; Wed, 19 Nov 2025 03:04:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1763550273; x=1764155073; 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=jECqb7FpaGoNZmYZTTPNeoOaaYauInUDkmHh57LIczM=; b=dDbesPcuvxue7WMUgbtZcB7fENPmcsJYO5oP7rnq3aXOnGzg0jiDc151ubwRYbxbqR L6yE2KbZ+9KUfL89pBwWTb7fyZZL1n9vc+w6FxKsDHd3uUWKfQ9WOJsg7CFl3MWQ9Zlf g24QvPs5GtNKfoGkqw5e+zK+4H/6FELJI7HWXgQRs2xsWT54sdc/GrwoWh/Fa3p9iiXK i/I3Hmvxwod81m/OU0uQ3FomPh5wpM0lzrp/yE9LyHGV1BTop4IDepY0NF7bBzpjosYX /gMuAY2DcayDJTEcqD6HTYpYUgW9reDMF4lazuhOH00uoi+Pe/t80GflfLpbReOXkIDc cbyw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1763550273; x=1764155073; 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=jECqb7FpaGoNZmYZTTPNeoOaaYauInUDkmHh57LIczM=; b=ih8tzXyLz9J9EgYBmXGmXkL1gVbLCOHWW8yAf+axx9lLa83vZQ2yBOZKYqxLdLN2VH SSmlPixQ3qhsNe+qG5hFel8A3KyszKprhDBLfENS8FW2LJvc65aqo7xbvPjH2HU+JluP 2AAo8v7c9JKGB8UZs1WRd6pibeTVuzKdAvS7hOaiTRAN/aCAdW57PimqKIQh1ZbbCOvr Rm/sKb0VcFM7A/Zxiua9ii2upxFiZtevNrBH+TU/LbwylzHIrkSFij3zauwQHyW7ka4w F9FuAFxojf/XcVVtXXa4Wd6PckCc6RtPq6Ia833t8ieYeleS20tZeCkTLcRalBr/INUs udSA== X-Forwarded-Encrypted: i=1; AJvYcCWIr5FEsjiqAeVaVvFmVeedY/x3BrhXHv7wj+TbdoMwaKJRDFkWle5M5ALu3BXghfTR7ivugM3mWpMWWZw=@vger.kernel.org X-Gm-Message-State: AOJu0YwhSUT80ymvu4hOX5xwgup0+msYT9epw0JnS863cfy5t+BPq6eE Mz4TVORdrBv8ELJKf0xEOVHEjxYmKANn60n+3hl9el8vedI5NKTtd6Cf X-Gm-Gg: ASbGnctfZxKddCqIW5lFzmXZg9gn6XBeBwh0cFjaDVFZA1jKrwLu5xrAAZRfXg5sYAI GAMbODFGOEZ+m9iaZXWrdVXuLd73kU0yytcss7mNpAtVyMJe+coDNXaX19bAfzkLplOkAHUNCbG qsfd2xmyUrCDUn5cKKaIuSZeS8fmauFva8V4DHBzBWcbLaDd9LVmdcn6XEXXNhoDnq+uK8Aw5ns z+pul8D3YLfXa9Im+vJt5jGAXwudAwPs8GYBhjaecpP35GMZpk0t403L703OEit4ZLgiY3pSNVA VSQhPvvsPj+h7fkozpU+sAhnXJdTARptu41f89L+TftZGpDA5NSjMgRgFi6Q75hnG7MP5+33y3b Q7NLv/qufusW683qSEb8fEqUBzN1a6RPUzoazfyGzM+B/GCLXbROpqNqWyF7aHSQ6R3TGV/HBi3 kGzUhsQLPxH8XTzOxhUihpDaQ= X-Google-Smtp-Source: AGHT+IGAn8aA94Gjc6rB7edvmJijL47gT2Orqoh2HUXTMCcoqOAgk+7GqJFDZKDrLhN1hgbOGdfvkQ== X-Received: by 2002:a05:6402:3506:b0:640:9b62:a8bb with SMTP id 4fb4d7f45d1cf-64350e89ad2mr17322636a12.22.1763550273047; Wed, 19 Nov 2025 03:04:33 -0800 (PST) Received: from foxbook (bhd138.neoplus.adsl.tpnet.pl. [83.28.93.138]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-644f13ff4d4sm5588048a12.12.2025.11.19.03.04.32 (version=TLS1_2 cipher=AES128-SHA bits=128/128); Wed, 19 Nov 2025 03:04:32 -0800 (PST) Date: Wed, 19 Nov 2025 12:04:30 +0100 From: Michal Pecio To: Mathias Nyman , Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 3/5] usb: xhci: Refactor and generalize trb_in_td() Message-ID: <20251119120430.5e41bf74.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" Replace the internal logic of trb_in_td() with a new one which works on (virtual) TRB pointers instead of DMA addresses. Since driver data structures use virtual pointers, the function and some of its callers will be simplified. Optimize for common case of trb =3D=3D end_trb. Extract the implementation into a lower level trb_in_range() function which works with arbitrary TRB ranges. Create a new trb_in_td() as the obvious wrapper around trb_in_range(). Create a new dma_in_td() using xhci_dma_to_trb() and trb_in_td(). Update former trb_in_td() callers to use new functions appropriately. Signed-off-by: Michal Pecio --- drivers/usb/host/xhci-ring.c | 101 +++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 46 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 531e2f207b17..a2257e1dc396 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -113,6 +113,11 @@ static bool trb_is_link(union xhci_trb *trb) return TRB_TYPE_LINK_LE32(trb->link.control); } =20 +static bool trb_on_seg(struct xhci_segment *seg, union xhci_trb *trb) +{ + return in_range((uintptr_t) trb, (uintptr_t) seg->trbs, TRB_SEGMENT_SIZE); +} + static bool last_trb_on_seg(struct xhci_segment *seg, union xhci_trb *trb) { return trb =3D=3D &seg->trbs[TRBS_PER_SEGMENT - 1]; @@ -304,54 +309,58 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhc= i_ring *ring, } =20 /* - * If the suspect DMA address is a TRB in this TD, this function returns t= hat - * TRB's segment. Otherwise it returns 0. + * Check if seg:trb is a TRB in the range between start_trb and end_trb, i= nclusive. + * If start_trb =3D=3D end_trb, the range is one TRB, not the full ring. T= he range may + * cycle back and end in an earlier segment or on earlier TRB in start_trb= segment. */ -static struct xhci_segment *trb_in_td(struct xhci_td *td, dma_addr_t suspe= ct_dma) +static bool trb_in_range(struct xhci_hcd *xhci, union xhci_trb *start_trb,= union xhci_trb *end_trb, + struct xhci_segment *seg, union xhci_trb *trb) { - dma_addr_t start_dma; - dma_addr_t end_seg_dma; - dma_addr_t end_trb_dma; - struct xhci_segment *cur_seg; + struct xhci_segment *seg_other; =20 - start_dma =3D xhci_trb_virt_to_dma(td->start_seg, td->start_trb); - cur_seg =3D td->start_seg; + if (!trb || !seg) + return false; =20 - do { - if (start_dma =3D=3D 0) - return NULL; - /* We may get an event for a Link TRB in the middle of a TD */ - end_seg_dma =3D xhci_trb_virt_to_dma(cur_seg, - &cur_seg->trbs[TRBS_PER_SEGMENT - 1]); - /* If the end TRB isn't in this segment, this is set to 0 */ - end_trb_dma =3D xhci_trb_virt_to_dma(cur_seg, td->end_trb); - - if (end_trb_dma > 0) { - /* The end TRB is in this segment, so suspect should be here */ - if (start_dma <=3D end_trb_dma) { - if (suspect_dma >=3D start_dma && suspect_dma <=3D end_trb_dma) - return cur_seg; - } else { - /* Case for one segment with - * a TD wrapped around to the top - */ - if ((suspect_dma >=3D start_dma && - suspect_dma <=3D end_seg_dma) || - (suspect_dma >=3D cur_seg->dma && - suspect_dma <=3D end_trb_dma)) - return cur_seg; - } - return NULL; - } - /* Might still be somewhere in this segment */ - if (suspect_dma >=3D start_dma && suspect_dma <=3D end_seg_dma) - return cur_seg; + /* Typically end_trb is near trb in the same segment */ + if (trb_on_seg(seg, end_trb)) + return trb <=3D end_trb + /* must not start between trb and end_trb */ + ? !(trb < start_trb && start_trb <=3D end_trb) + /* must start between end_trb and trb */ + : end_trb < start_trb && start_trb <=3D trb; =20 - cur_seg =3D cur_seg->next; - start_dma =3D xhci_trb_virt_to_dma(cur_seg, &cur_seg->trbs[0]); - } while (cur_seg !=3D td->start_seg); + /* The range ends in other segment, easy if it starts here */ + if (trb_on_seg(seg, start_trb)) + return start_trb <=3D trb; =20 - return NULL; + /* Walk segments and see if end_trb is reached before start_trb */ + for (seg_other =3D seg->next; seg_other !=3D seg; seg_other =3D seg_other= ->next) { + bool found_start =3D trb_on_seg(seg_other, start_trb); + bool found_end =3D trb_on_seg(seg_other, end_trb); + + if (found_end) + return found_start ? end_trb < start_trb : true; + + if (found_start) + return false; + } + + xhci_err(xhci, "TRB range boundaries not on ring\n"); + return false; +} + +static bool trb_in_td(struct xhci_hcd *xhci, struct xhci_td *td, + struct xhci_segment *seg, union xhci_trb *trb) +{ + return trb_in_range(xhci, td->start_trb, td->end_trb, seg, trb); +} + +static bool dma_in_td(struct xhci_hcd *xhci, struct xhci_td *td, dma_addr_= t dma) +{ + struct xhci_segment *seg; + union xhci_trb *trb =3D xhci_dma_to_trb(td->start_seg, dma, &seg); + + return trb_in_td(xhci, td, seg, trb); } =20 /* @@ -1094,7 +1103,7 @@ static int xhci_invalidate_cancelled_tds(struct xhci_= virt_ep *ep) td->urb->stream_id); hw_deq &=3D TR_DEQ_PTR_MASK; =20 - if (td->cancel_status =3D=3D TD_HALTED || trb_in_td(td, hw_deq)) { + if (td->cancel_status =3D=3D TD_HALTED || dma_in_td(xhci, td, hw_deq)) { switch (td->cancel_status) { case TD_CLEARED: /* TD is already no-op */ case TD_CLEARING_CACHE: /* set TR deq command already queued */ @@ -1184,7 +1193,7 @@ static struct xhci_td *find_halted_td(struct xhci_vir= t_ep *ep) hw_deq =3D xhci_get_hw_deq(ep->xhci, ep->vdev, ep->ep_index, 0); hw_deq &=3D TR_DEQ_PTR_MASK; td =3D list_first_entry(&ep->ring->td_list, struct xhci_td, td_list); - if (trb_in_td(td, hw_deq)) + if (dma_in_td(ep->xhci, td, hw_deq)) return td; } return NULL; @@ -2843,7 +2852,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, */ td =3D list_first_entry_or_null(&ep_ring->td_list, struct xhci_td, td_lis= t); =20 - if (td && td->error_mid_td && !trb_in_td(td, ep_trb_dma)) { + if (td && td->error_mid_td && !trb_in_td(xhci, td, ep_seg, ep_trb)) { xhci_dbg(xhci, "Missing TD completion event after mid TD error\n"); xhci_dequeue_td(xhci, td, ep_ring, td->status); } @@ -2876,7 +2885,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, td_list); =20 /* Is this a TRB in the currently executing TD? */ - if (!trb_in_td(td, ep_trb_dma)) { + if (!trb_in_td(xhci, td, ep_seg, ep_trb)) { =20 if (ep->skip && usb_endpoint_xfer_isoc(&td->urb->ep->desc)) { /* this event is unlikely to match any TD, don't skip them all */ --=20 2.48.1