git: eefd55678c53 - stable/15 - sound: Prefer idle primary channels when allocating

From: Christos Margiolis <christos_at_FreeBSD.org>
Date: Mon, 21 Sep 2026 11:05:34 UTC
The branch stable/15 has been updated by christos:

URL: https://cgit.FreeBSD.org/src/commit/?id=eefd55678c530e9d0cf3480edf86c4d815f36fc8

commit eefd55678c530e9d0cf3480edf86c4d815f36fc8
Author:     Christos Margiolis <christos@FreeBSD.org>
AuthorDate: 2026-09-07 13:04:09 +0000
Commit:     Christos Margiolis <christos@FreeBSD.org>
CommitDate: 2026-09-21 11:04:08 +0000

    sound: Prefer idle primary channels when allocating
    
    dsp_chn_alloc() stopped at the first primary channel that was either
    idle or already had vchans. Since the list is walked in order, the first
    channel matched both conditions once it had been used, so every client
    after the first was stacked onto it as a vchan and the remaining primary
    channels were never allocated at all.
    
    This is invisible on devices with a single primary channel, but not on
    those which provide several. snd_emu10kx(4), for instance, registers
    four primary channels for its front device, each able to run with its
    own rate.
    
    Look for an idle primary channel first, and only fall back to sharing
    one that already has vchans when there is none left.
    
    Sponsored by:   The FreeBSD Foundation
    MFC after:      2 weeks
    Reviewed by:    markj
    Differential Revision:  https://reviews.freebsd.org/D59084
    
    (cherry picked from commit 5e02679f03cda224f59adcf83d5308fffa6d11a1)
---
 sys/dev/sound/pcm/dsp.c | 24 +++++++++++++++++-------
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c
index 633f096a4e78..c7616d9ecefc 100644
--- a/sys/dev/sound/pcm/dsp.c
+++ b/sys/dev/sound/pcm/dsp.c
@@ -186,18 +186,28 @@ dsp_chn_alloc(struct snddev_info *d, struct pcm_channel **ch, int direction,
 	    (direction == PCMDIR_REC && d->flags & SD_F_RVCHANS);
 
 	*ch = NULL;
+
+	/*
+	 * Prefer an idle primary channel, so that devices which provide more
+	 * than one of them use them all, instead of stacking every client on
+	 * the first one.
+	 */
 	CHN_FOREACH(c, d, channels.pcm.primary) {
 		CHN_LOCK(c);
-		if (c->direction != direction) {
-			CHN_UNLOCK(c);
-			continue;
-		}
-		/* Find an available primary channel to use. */
-		if ((c->flags & CHN_F_BUSY) == 0 ||
-		    (vdir_enabled && (c->flags & CHN_F_HAS_VCHAN)))
+		if (c->direction == direction && (c->flags & CHN_F_BUSY) == 0)
 			break;
 		CHN_UNLOCK(c);
 	}
+	/* Fall back to sharing a primary channel that already has vchans. */
+	if (c == NULL && vdir_enabled) {
+		CHN_FOREACH(c, d, channels.pcm.primary) {
+			CHN_LOCK(c);
+			if (c->direction == direction &&
+			    (c->flags & CHN_F_HAS_VCHAN))
+				break;
+			CHN_UNLOCK(c);
+		}
+	}
 	if (c == NULL)
 		return (EBUSY);