Linux USB
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Vadim Yuzifovich" <vadim@yuzi.co>
Cc: linux-usb@vger.kernel.org
Subject: Re: [PATCH 2/3] usb: dwc2: gadget: restart descriptor DMA bulk and interrupt endpoints after BNA
Date: Sun, 15 Nov 2026 19:09:54 +0000	[thread overview]
Message-ID: <sashiko-outbox-215741@kernel.org> (raw)
In-Reply-To: <20261115185335.782678-3-vadim@yuzi.co>

Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [Medium] usb: dwc2: gadget: wrong DMA offset in
  dwc2_gadget_handle_nonisoc_bna()
- [Medium] usb: dwc2: delayed EPDISBLD after BNA skips restart or
  flushes active TxFIFO
--

commit 11858f40d5a168bb783c631975d168ab78609905
Author: Vadim Yuzifovich <vadim@yuzi.co>

usb: dwc2: gadget: restart descriptor DMA bulk and interrupt endpoints after BNA

This commit adds a BNA interrupt handler for non-isochronous endpoints in
descriptor DMA mode to restart the current request when the endpoint is
disabled and not halted.

> diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
> index b0e129061abb6..046b5b04503bd 100644
> --- a/drivers/usb/dwc2/gadget.c
> +++ b/drivers/usb/dwc2/gadget.c
> @@ -2305,6 +2305,45 @@ static void dwc2_gadget_handle_isoc_bna(struct dwc2_hsotg_ep *hs_ep)
>  	dwc2_gadget_restart_isoc_out_ddma(hs_ep);
>  }
>  
> +/*
> + * dwc2_gadget_handle_nonisoc_bna - handle BNA interrupt for bulk and
> + * interrupt endpoints in descriptor DMA mode.
> + * @hs_ep: The endpoint, not EP0 and not isochronous.
> + * @ints: The endpoint interrupts that came with the BNA, for the log.
> + *
> + * The core raises BNA and disables the endpoint when the descriptor it
> + * fetches is not marked host ready. The chain of a bulk or interrupt
> + * endpoint is complete before the endpoint is enabled, and afterwards the
> + * descriptor reads host ready, so the core read it before the CPU's writes
> + * to it reached memory. Nothing was transferred and no XferCompl
> + * follows: the request stays current, the ones queued behind it never
> + * start, and the function waits until the host gives up and resets the
> + * port. Start the request again; that fills the descriptor anew.
> + */
> +static void dwc2_gadget_handle_nonisoc_bna(struct dwc2_hsotg_ep *hs_ep,
> +					   u32 ints)
> +{
> +	struct dwc2_hsotg *hsotg = hs_ep->parent;
> +	struct dwc2_hsotg_req *hs_req = hs_ep->req;
> +	u32 epctl_reg = hs_ep->dir_in ? DIEPCTL(hs_ep->index) :
> +					DOEPCTL(hs_ep->index);
> +	u32 epctl = dwc2_readl(hsotg, epctl_reg);
> +	u32 status = hs_ep->desc_list ? READ_ONCE(hs_ep->desc_list[0].status) : 0;
> +	bool restart = hs_req && !hs_ep->halted &&
> +		       !(epctl & (DXEPCTL_EPENA | DXEPCTL_STALL));

[Severity: Medium]
What happens if DXEPINT_BNAINTR is serviced before the core finishes
clearing DXEPCTL_EPENA and latching DXEPINT_EPDISBLD?

As noted in 540ccba08599 ("usb: dwc2: gadget: Start and complete DDMA isoc
transfers") and commit "usb: dwc2: gadget: restart descriptor DMA
isochronous OUT endpoints after BNA", the endpoint disable can complete
slightly after DXEPINT_BNAINTR is first read:

1. If DXEPCTL_EPENA is still set when dwc2_gadget_handle_nonisoc_bna()
   reads epctl_reg, restart is false and the request is not restarted.
   When DXEPINT_EPDISBLD arrives later, dwc2_gadget_handle_ep_disabled()
   returns early for non-isochronous endpoints, leaving the endpoint stuck.

2. If DXEPCTL_EPENA clears after dwc2_hsotg_epint() reads and clears
   DIEPINT, but before dwc2_gadget_handle_nonisoc_bna() reads DIEPCTL,
   dwc2_gadget_handle_nonisoc_bna() restarts the IN endpoint while
   DXEPINT_EPDISBLD remains pending in DIEPINT.  On the next interrupt,
   dwc2_gadget_handle_ep_disabled() unconditionally calls
   dwc2_hsotg_txfifo_flush(), flushing the TxFIFO of the newly restarted
   IN transfer.

> +
> +	dev_warn_ratelimited(hsotg->dev,
> +			     "%s: BNA, DxEPINT %08x DxEPCTL %08x descriptor %08x, %s\n",
> +			     hs_ep->name, ints, epctl, status,
> +			     restart ? "request restarted" : "not restarted");
> +
> +	if (!restart)
> +		return;
> +
> +	hs_ep->req = NULL;
> +	dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, false);
> +}

[Severity: Medium]
Does passing continuing = false to dwc2_hsotg_start_req() corrupt the DMA
offset when a BNA occurs on a continuation chunk of a multi-part request
(where hs_req->req.actual > 0)?

When a request exceeds dwc2_gadget_get_chain_limit(),
dwc2_hsotg_complete_in() or dwc2_hsotg_handle_outdone() starts the next
chunk with dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, true).  In
dwc2_hsotg_start_req(), length and hs_ep->last_load always account for
ureq->actual, but the DDMA buffer offset only advances when continuing is
true:

drivers/usb/dwc2/gadget.c:dwc2_hsotg_start_req() {
    ...
	length = ureq->length - ureq->actual;
    ...
	if (using_desc_dma(hsotg)) {
		u32 offset = 0;
    ...
		if (continuing)
			offset = ureq->actual;

		/* Fill DDMA chain entries */
		dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, ureq->dma + offset,
						     length);
    ...
}

Restarting with continuing = false programs the descriptors at ureq->dma
instead of ureq->dma + ureq->actual for the remaining length, re-sending or
overwriting the start of the buffer.  Passing hs_req->req.actual > 0 as
continuing (and keeping hs_ep->req set when continuing is true) would
preserve the offset.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261115185335.782678-1-vadim@yuzi.co?part=2

  reply	other threads:[~2026-11-15 19:09 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-15 18:53 [PATCH 0/3] usb: dwc2: gadget: descriptor DMA fixes for BNA, found on Sophgo SG2002 Vadim Yuzifovich
2026-11-15 18:53 ` [PATCH 1/3] usb: dwc2: gadget: restart descriptor DMA isochronous OUT endpoints after BNA Vadim Yuzifovich
2026-11-15 19:20   ` sashiko-bot
2026-11-15 18:53 ` [PATCH 2/3] usb: dwc2: gadget: restart descriptor DMA bulk and interrupt " Vadim Yuzifovich
2026-11-15 19:09   ` sashiko-bot [this message]
2026-11-15 18:53 ` [PATCH 3/3] usb: dwc2: gadget: make descriptors visible before the endpoint is enabled Vadim Yuzifovich
2026-11-15 19:07   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-215741@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=vadim@yuzi.co \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox