git: a25ad366d51d - main - snd_hdsp: Serialize rate and latency updates

From: Kevin Bowling <kbowling_at_FreeBSD.org>
Date: Mon, 02 Nov 2026 15:55:27 UTC
The branch main has been updated by kbowling:

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

commit a25ad366d51d52ef30b8bc4e2a7dd377255a409b
Author:     Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-11-02 15:54:35 +0000
Commit:     Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-11-02 15:55:04 +0000

    snd_hdsp: Serialize rate and latency updates
    
    Protect running-state checks and register updates with the softc lock.
    Keep the pointer reset and the HDSP 9632 frequency rewrite in the same
    critical section as the latency update.
    
    Drop the lock around sndbuf_resize(), which may sleep, and recheck the
    running state after reacquiring it.  Preserve resize error handling so
    that a failed resize leaves the hardware unchanged.
    
    This mirrors the locking in snd_hdspe.
    
    MFC after:      3 days
    Sponsored by:   BBOX.io
---
 sys/dev/sound/pci/hdsp-pcm.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/sys/dev/sound/pci/hdsp-pcm.c b/sys/dev/sound/pci/hdsp-pcm.c
index 27ab21fd6d74..24969f0e22b0 100644
--- a/sys/dev/sound/pci/hdsp-pcm.c
+++ b/sys/dev/sound/pci/hdsp-pcm.c
@@ -851,6 +851,8 @@ hdspchan_setspeed(kobj_t obj, void *data, uint32_t speed)
 	device_printf(scp->dev, "hdspchan_setspeed(%d)\n", speed);
 #endif
 
+	mtx_lock(&sc->lock);
+
 	if (hdsp_running(sc) == 1)
 		goto end;
 
@@ -890,8 +892,10 @@ hdspchan_setspeed(kobj_t obj, void *data, uint32_t speed)
 
 	sc->speed = hr->speed;
 end:
+	speed = sc->speed;
+	mtx_unlock(&sc->lock);
 
-	return (sc->speed);
+	return (speed);
 }
 
 static uint32_t
@@ -913,6 +917,8 @@ hdspchan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
 	device_printf(scp->dev, "hdspchan_setblocksize(%d)\n", blocksize);
 #endif
 
+	mtx_lock(&sc->lock);
+
 	if (hdsp_running(sc) == 1)
 		goto end;
 
@@ -943,16 +949,23 @@ hdspchan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
 		}
 	}
 
+	/* sndbuf_resize() may sleep. */
+	mtx_unlock(&sc->lock);
 	if (sndbuf_resize(ch->buffer, 2,
 	    (hl->period * AFMT_CHANNEL(ch->format) * sizeof(uint32_t))) != 0)
 		return (0);
 
 	mtx_lock(&sc->lock);
+	/* A channel may have started while the lock was dropped. */
+	if (hdsp_running(sc) == 1) {
+		mtx_unlock(&sc->lock);
+		return (0);
+	}
+
 	sc->ctrl_register &= ~HDSP_LAT_MASK;
 	sc->ctrl_register |= hdsp_encode_latency(hl->n);
 	hdsp_write_4(sc, HDSP_CONTROL_REG, sc->ctrl_register);
 	sc->period = hl->period;
-	mtx_unlock(&sc->lock);
 
 #if 0
 	device_printf(scp->dev, "New period=%d\n", sc->period);
@@ -963,6 +976,7 @@ hdspchan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
 	if (sc->type == HDSP_9632)
 		hdsp_write_4(sc, HDSP_FREQ_REG, hdsp_freq_reg_value(sc->speed));
 end:
+	mtx_unlock(&sc->lock);
 
 	return (ch->buffer->blksz);
 }