All of lore.kernel.org
 help / color / mirror / Atom feed
From: Takashi Iwai <tiwai@suse.de>
To: Zhang Heng <zhangheng@kylinos.cn>
Cc: Gordon Chen <chengordon326@gmail.com>,
	perex@perex.cz, tiwai@suse.com, kees@kernel.org,
	jussi@sonarnerd.net, hulianqin@vivo.com, i@rong.moe, g@b4.vu,
	cryolitia@uniontech.com, pav@iki.fi, linux-sound@vger.kernel.org,
	linux-kernel@vger.kernel.org, mathias.nyman@linux.intel.com
Subject: Re: [PATCH] usb-audio: Fix boot-time crackling for Generic USB Audio device
Date: Tue, 14 Jul 2026 09:40:19 +0200	[thread overview]
Message-ID: <87tsq2yq70.wl-tiwai@suse.de> (raw)
In-Reply-To: <5ed9e0a3-e8ac-4295-b876-dcda8b96ca1e@kylinos.cn>

On Tue, 14 Jul 2026 03:58:08 +0200,
Zhang Heng wrote:
> 
> > On Mon, Jul 13, 2026 at 04:10:48PM +0800, Zhang Heng wrote:
> >> +		/* Generic USB Audio (0x1e0b:d01e): use SIA for consistent scheduling */
> >> +		if (ep->chip->usb_id == USB_ID(0x1e0b, 0xd01e))
> >> +			u->urb->transfer_flags |= URB_ISO_ASAP;
> > Not a maintainer, just a bystander who was Cc'd -- two small notes on the
> > form of the patch, plus one question I can't answer myself.
> > 
> > A per-device usb_id comparison in the endpoint.c fast path seems like the
> > kind of thing the quirk_flags_table in quirks.c exists to avoid. Would a
> > QUIRK_FLAG_ISO_ASAP (set in the table, tested here as
> > chip->quirk_flags & QUIRK_FLAG_ISO_ASAP) work for you? It keeps endpoint.c
> > device-agnostic, and the next device with the same symptom becomes a
> > one-line table entry rather than another if.
> First of all, let me clarify: this issue occurs when there is startup music,
> but it plays normally after entering the system. There is a heavy creaking
> sound when the system is turned on here. Based on the information from dmesg
> and syslog, there are a large number of xhci hcd frame synchronization
> failures. I tried adding URB_ISO_ASAP here, and it will be much better,
> with only a little noise.

OK, but it still makes sense to deal URB_ISO_ASAP workaround more
generically.

> >> +	if (ep->chip->usb_id == USB_ID(0x1e0b, 0xd01e) &&
> >> +	    ep->type == SND_USB_ENDPOINT_TYPE_SYNC)
> >> +		ep->skip_packets = 4;
> > The block immediately above this one already does exactly
> > "type == SND_USB_ENDPOINT_TYPE_SYNC -> skip_packets = 4"; adding the ID to
> > that condition would avoid the duplicate if. Also, the changelog doesn't
> > say what this hunk contributes on its own -- is URB_ISO_ASAP alone
> > insufficient, and if so, what does skipping the first 4 sync packets fix
> > that ASAP doesn't? Right now the two changes are indistinguishable in the
> > commit message, and skip_packets = 4 reads as belt-and-braces.
> As mentioned above, there is still a bit of noise when only adding
> URB_ISO_ASAP,
> 
> but skip-packets=4 can solve this problem.

Well, one missing thing is to understand why this fixes.
Originally, the skip_packets=4 for Playback Design devices was
introduced for bogus feedback packets at the start of the stream long
time ago.  But that's the only known device that needs it.  Does your
device send also 4 bogus packets?

The skip_packets=16 for M-Audio devices are rather for avoiding the
latency.  And, speaking of latency, I have a patch for the lowlatency
support of implicit fb mode, but never had a test environment.
Could you check the patch below and see the patch below has any
positive/negative influence?  Just to be sure.


thanks,

Takashi

-- 8< --
index 682b6c1fe76b..6d144e39a849 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -265,6 +265,7 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip,
 	return 0;
 }
 
+/* stop both data and sync endpoints */
 static bool stop_endpoints(struct snd_usb_substream *subs, bool keep_pending)
 {
 	bool stopped = 0;
@@ -280,6 +281,24 @@ static bool stop_endpoints(struct snd_usb_substream *subs, bool keep_pending)
 	return stopped;
 }
 
+/* only start sync endpoint */
+static int start_sync_endpoint(struct snd_usb_substream *subs)
+{
+	int err;
+
+	if (subs->sync_endpoint &&
+	    !test_and_set_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) {
+		err = snd_usb_endpoint_start(subs->sync_endpoint);
+		if (err < 0) {
+			clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+/* start both data and sync endpoints */
 static int start_endpoints(struct snd_usb_substream *subs)
 {
 	int err;
@@ -295,14 +314,9 @@ static int start_endpoints(struct snd_usb_substream *subs)
 		}
 	}
 
-	if (subs->sync_endpoint &&
-	    !test_and_set_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) {
-		err = snd_usb_endpoint_start(subs->sync_endpoint);
-		if (err < 0) {
-			clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags);
-			goto error;
-		}
-	}
+	err = start_sync_endpoint(subs);
+	if (err < 0)
+		goto error;
 
 	return 0;
 
@@ -656,12 +670,16 @@ static int lowlatency_playback_available(struct snd_pcm_runtime *runtime,
 		return false;
 	if (in_free_wheeling_mode(runtime))
 		return false;
-	/* implicit feedback mode has own operation mode */
-	if (snd_usb_endpoint_implicit_feedback_sink(subs->data_endpoint))
-		return false;
 	return true;
 }
 
+/* return true if it's a normal playback (not in implicit fb) */
+static bool is_normal_lowlatency_playback(struct snd_usb_substream *subs)
+{
+	return subs->lowlatency_playback &&
+		!snd_usb_endpoint_implicit_feedback_sink(subs->data_endpoint);
+}
+
 /*
  * prepare callback
  *
@@ -709,9 +727,11 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
 	runtime->delay = 0;
 
 	subs->lowlatency_playback = lowlatency_playback_available(runtime, subs);
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
-	    !subs->lowlatency_playback) {
-		ret = start_endpoints(subs);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (!subs->lowlatency_playback)
+			ret = start_endpoints(subs);
+		else if (snd_usb_endpoint_implicit_feedback_sink(subs->data_endpoint))
+			ret = start_sync_endpoint(subs);
 		/* if XRUN happens at starting streams (possibly with implicit
 		 * fb case), restart again, but only try once.
 		 */
@@ -1539,7 +1559,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs,
 		frame_limit = subs->frame_limit + ep->max_urb_frames;
 		transfer_done = subs->transfer_done;
 
-		if (subs->lowlatency_playback &&
+		if (is_normal_lowlatency_playback(subs) &&
 		    runtime->state != SNDRV_PCM_STATE_DRAINING) {
 			unsigned int hwptr = subs->hwptr_done / stride;
 
@@ -1625,7 +1645,8 @@ static int prepare_playback_urb(struct snd_usb_substream *subs,
 			subs->trigger_tstamp_pending_update = false;
 		}
 
-		if (period_elapsed && !subs->running && subs->lowlatency_playback) {
+		if (period_elapsed && !subs->running &&
+		    is_normal_lowlatency_playback(subs)) {
 			subs->period_elapsed_pending = 1;
 			period_elapsed = 0;
 		}
@@ -1677,7 +1698,7 @@ static int snd_usb_pcm_playback_ack(struct snd_pcm_substream *substream)
 	struct snd_usb_substream *subs = substream->runtime->private_data;
 	struct snd_usb_endpoint *ep;
 
-	if (!subs->lowlatency_playback || !subs->running)
+	if (!is_normal_lowlatency_playback(subs) || !subs->running)
 		return 0;
 	ep = subs->data_endpoint;
 	if (!ep)
@@ -1705,6 +1726,7 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea
 					      prepare_playback_urb,
 					      retire_playback_urb,
 					      subs);
+		/* start EPs for both normal and implicit-fb modes */
 		if (subs->lowlatency_playback &&
 		    cmd == SNDRV_PCM_TRIGGER_START) {
 			if (in_free_wheeling_mode(substream->runtime))

  reply	other threads:[~2026-07-14  7:40 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-13  8:10 [PATCH] usb-audio: Fix boot-time crackling for Generic USB Audio device Zhang Heng
2026-07-13 13:20 ` Gordon Chen
2026-07-13 15:05   ` Takashi Iwai
2026-07-14 13:09     ` Zhang Heng
2026-07-14  1:58   ` Zhang Heng
2026-07-14  7:40     ` Takashi Iwai [this message]
2026-07-14 13:02       ` Zhang Heng
2026-07-14 13:38         ` Takashi Iwai

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=87tsq2yq70.wl-tiwai@suse.de \
    --to=tiwai@suse.de \
    --cc=chengordon326@gmail.com \
    --cc=cryolitia@uniontech.com \
    --cc=g@b4.vu \
    --cc=hulianqin@vivo.com \
    --cc=i@rong.moe \
    --cc=jussi@sonarnerd.net \
    --cc=kees@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-sound@vger.kernel.org \
    --cc=mathias.nyman@linux.intel.com \
    --cc=pav@iki.fi \
    --cc=perex@perex.cz \
    --cc=tiwai@suse.com \
    --cc=zhangheng@kylinos.cn \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.